[Mono-dev] [PATCH] Update Gendarme framework (fixed)

Aaron Tomb atomb at soe.ucsc.edu
Mon Jan 2 12:39:59 EST 2006


Mea culpa. I sent in a version of this patch in mid-December [1], and
just realized that it didn't include a number of necessary files. I'd
neglected 'svn add' a few times, before generating the diff. Here's the
a version with the necessary files included.

Aaron

[1]
http://lists.ximian.com/pipermail/mono-devel-list/2005-December/016177.html
-------------- next part --------------
Index: console/ConsoleRunner.cs
===================================================================
--- console/ConsoleRunner.cs	(revision 54948)
+++ console/ConsoleRunner.cs	(working copy)
@@ -86,6 +86,9 @@
 			case "--set":
 				set = GetNext (args, ++i, defaultRuleSet);
 				break;
+			case "--debug":
+				debug = true;
+				break;
 			case "--help":
 				return false;
 			default:
@@ -154,6 +157,7 @@
 		Console.WriteLine ("Where");
 		Console.WriteLine ("  --config configfile\tSpecify the configuration file. Default is 'rules.xml'.");
 		Console.WriteLine ("  --set ruleset\t\tSpecify the set of rules to verify. Default is '*'.");
+		Console.WriteLine ("  --debug\t\tEnable debugging output.");
 		Console.WriteLine ("  assembly\t\tSpecify the assembly to verify.");
 		Console.WriteLine ();
 	}
@@ -202,6 +206,13 @@
 			Console.WriteLine ();
 			Console.WriteLine ("Problem: {0}", String.Format (ri.Problem, v.Violator));
 			Console.WriteLine ();
+			if(v.Messages != null && v.Messages.Count > 0) {
+				Console.WriteLine ("Details:");
+				foreach(object message in v.Messages) {
+					Console.WriteLine("  {0}", message);
+				}
+				Console.WriteLine ();
+			}
 			Console.WriteLine ("Solution: {0}", String.Format (ri.Solution, v.Violator));
 			Console.WriteLine ();
 			string url = ri.Uri;
Index: rules/Gendarme.Rules.Security/Test/TypeExposeFieldsTest.cs
===================================================================
--- rules/Gendarme.Rules.Security/Test/TypeExposeFieldsTest.cs	(revision 54948)
+++ rules/Gendarme.Rules.Security/Test/TypeExposeFieldsTest.cs	(working copy)
@@ -123,42 +123,42 @@
 		public void NonPublic ()
 		{
 			ITypeDefinition type = GetTest ("NonPublicClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void NoSecurity ()
 		{
 			ITypeDefinition type = GetTest ("NoSecurityClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void NoDemand ()
 		{
 			ITypeDefinition type = GetTest ("NoDemandClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void NoPublicField ()
 		{
 			ITypeDefinition type = GetTest ("NoPublicFieldClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void LinkDemandWithField ()
 		{
 			ITypeDefinition type = GetTest ("LinkDemandWithFieldClass");
-			Assert.IsFalse (rule.CheckType (assembly, module, type));
+			Assert.IsNotNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void DemandWithField ()
 		{
 			ITypeDefinition type = GetTest ("DemandWithFieldClass");
-			Assert.IsFalse (rule.CheckType (assembly, module, type));
+			Assert.IsNotNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 	}
 }
Index: rules/Gendarme.Rules.Security/Test/SealedTypeWithInheritanceDemandTest.cs
===================================================================
--- rules/Gendarme.Rules.Security/Test/SealedTypeWithInheritanceDemandTest.cs	(revision 54948)
+++ rules/Gendarme.Rules.Security/Test/SealedTypeWithInheritanceDemandTest.cs	(working copy)
@@ -94,28 +94,28 @@
 		public void NonSealed ()
 		{
 			ITypeDefinition type = GetTest ("NonSealedClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNotNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void SealedWithoutSecurity ()
 		{
 			ITypeDefinition type = GetTest ("SealedClassWithoutSecurity");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNotNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void SealedWithoutInheritanceDemand ()
 		{
 			ITypeDefinition type = GetTest ("SealedClassWithoutInheritanceDemand");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNotNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void SealedWithInheritanceDemand ()
 		{
 			ITypeDefinition type = GetTest ("SealedClassWithInheritanceDemand");
-			Assert.IsFalse (rule.CheckType (assembly, module, type));
+			Assert.IsNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 	}
 }
Index: rules/Gendarme.Rules.Security/Test/NonVirtualMethodWithInheritanceDemandTest.cs
===================================================================
--- rules/Gendarme.Rules.Security/Test/NonVirtualMethodWithInheritanceDemandTest.cs	(revision 54948)
+++ rules/Gendarme.Rules.Security/Test/NonVirtualMethodWithInheritanceDemandTest.cs	(working copy)
@@ -119,7 +119,7 @@
 		{
 			ITypeDefinition type = GetTest ("AbstractMethodsClass");
 			foreach (IMethodDefinition method in type.Methods) {
-				Assert.IsTrue (rule.CheckMethod (assembly, module, type, method));
+				Assert.IsNotNull (rule.CheckMethod (assembly, module, type, method, new MinimalRunner()));
 			}
 		}
 
@@ -128,7 +128,7 @@
 		{
 			ITypeDefinition type = GetTest ("VirtualMethodsClass");
 			foreach (IMethodDefinition method in type.Methods) {
-				Assert.IsTrue (rule.CheckMethod (assembly, module, type, method));
+				Assert.IsNotNull (rule.CheckMethod (assembly, module, type, method, new MinimalRunner()));
 			}
 		}
 
@@ -137,7 +137,7 @@
 		{
 			ITypeDefinition type = GetTest ("NoVirtualMethodsClass");
 			foreach (IMethodDefinition method in type.Methods) {
-				Assert.IsFalse (rule.CheckMethod (assembly, module, type, method));
+				Assert.IsNull (rule.CheckMethod (assembly, module, type, method, new MinimalRunner()));
 			}
 		}
 
@@ -146,7 +146,7 @@
 		{
 			ITypeDefinition type = GetTest ("NotInheritanceDemandClass");
 			foreach (IMethodDefinition method in type.Methods) {
-				Assert.IsTrue (rule.CheckMethod (assembly, module, type, method));
+				Assert.IsNotNull (rule.CheckMethod (assembly, module, type, method, new MinimalRunner()));
 			}
 		}
 	}
Index: rules/Gendarme.Rules.Security/Test/TypeIsNotSubsetOfMethodSecurityTest.cs
===================================================================
--- rules/Gendarme.Rules.Security/Test/TypeIsNotSubsetOfMethodSecurityTest.cs	(revision 54948)
+++ rules/Gendarme.Rules.Security/Test/TypeIsNotSubsetOfMethodSecurityTest.cs	(working copy)
@@ -149,49 +149,49 @@
 		public void NoSecurity ()
 		{
 			ITypeDefinition type = GetTest ("NoSecurityClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void LinkDemand ()
 		{
 			ITypeDefinition type = GetTest ("LinkDemandClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void InheritanceDemand ()
 		{
 			ITypeDefinition type = GetTest ("InheritanceDemandClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void AssertNotSubset ()
 		{
 			ITypeDefinition type = GetTest ("AssertNotSubsetClass");
-			Assert.IsFalse (rule.CheckType (assembly, module, type));
+			Assert.IsNotNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void DemandSubset ()
 		{
 			ITypeDefinition type = GetTest ("DemandSubsetClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void DenyNotSubset ()
 		{
 			ITypeDefinition type = GetTest ("DenyNotSubsetClass");
-			Assert.IsFalse (rule.CheckType (assembly, module, type));
+			Assert.IsNotNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void PermitOnlySubset ()
 		{
 			ITypeDefinition type = GetTest ("PermitOnlySubsetClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 	}
 }
Index: rules/Gendarme.Rules.Security/Test/MethodCallWithSubsetLinkDemandTest.cs
===================================================================
--- rules/Gendarme.Rules.Security/Test/MethodCallWithSubsetLinkDemandTest.cs	(revision 54948)
+++ rules/Gendarme.Rules.Security/Test/MethodCallWithSubsetLinkDemandTest.cs	(working copy)
@@ -128,7 +128,7 @@
 		{
 			ITypeDefinition type = GetTest ("SubsetInheritClass");
 			foreach (IMethodDefinition method in type.Methods) {
-				Assert.IsTrue (rule.CheckMethod (assembly, module, type, method));
+				Assert.IsNotNull (rule.CheckMethod (assembly, module, type, method, new MinimalRunner()));
 			}
 		}
 
@@ -137,7 +137,7 @@
 		{
 			ITypeDefinition type = GetTest ("NotASubsetInheritClass");
 			foreach (IMethodDefinition method in type.Methods) {
-				Assert.IsFalse (rule.CheckMethod (assembly, module, type, method));
+				Assert.IsNull (rule.CheckMethod (assembly, module, type, method, new MinimalRunner()));
 			}
 		}
 
@@ -146,7 +146,7 @@
 		{
 			ITypeDefinition type = GetTest ("SubsetCallClass");
 			foreach (IMethodDefinition method in type.Methods) {
-				Assert.IsTrue (rule.CheckMethod (assembly, module, type, method));
+				Assert.IsNotNull (rule.CheckMethod (assembly, module, type, method, new MinimalRunner()));
 			}
 		}
 
@@ -155,7 +155,7 @@
 		{
 			ITypeDefinition type = GetTest ("NotASubsetCallClass");
 			foreach (IMethodDefinition method in type.Methods) {
-				Assert.IsFalse (rule.CheckMethod (assembly, module, type, method));
+				Assert.IsNull (rule.CheckMethod (assembly, module, type, method, new MinimalRunner()));
 			}
 		}
 	}
Index: rules/Gendarme.Rules.Security/Test/TypeLinkDemandTest.cs
===================================================================
--- rules/Gendarme.Rules.Security/Test/TypeLinkDemandTest.cs	(revision 54948)
+++ rules/Gendarme.Rules.Security/Test/TypeLinkDemandTest.cs	(working copy)
@@ -147,56 +147,56 @@
 		public void NonPublic ()
 		{
 			ITypeDefinition type = GetTest ("NonPublicClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void Sealed ()
 		{
 			ITypeDefinition type = GetTest ("SealedClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void LinkDemand ()
 		{
 			ITypeDefinition type = GetTest ("LinkDemandClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void LinkDemandVirtualMethod ()
 		{
 			ITypeDefinition type = GetTest ("LinkDemandVirtualMethodClass");
-			Assert.IsFalse (rule.CheckType (assembly, module, type));
+			Assert.IsNotNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void InheritanceDemand ()
 		{
 			ITypeDefinition type = GetTest ("InheritanceDemandClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void NoIntersection ()
 		{
 			ITypeDefinition type = GetTest ("NoIntersectionClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void NoIntersectionVirtualMethod ()
 		{
 			ITypeDefinition type = GetTest ("NoIntersectionVirtualMethodClass");
-			Assert.IsFalse (rule.CheckType (assembly, module, type));
+			Assert.IsNotNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void Intersection ()
 		{
 			ITypeDefinition type = GetTest ("IntersectionClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 	}
 }
Index: rules/Gendarme.Rules.Security/Test/SecureGetObjectDataOverridesTest.cs
===================================================================
--- rules/Gendarme.Rules.Security/Test/SecureGetObjectDataOverridesTest.cs	(revision 54948)
+++ rules/Gendarme.Rules.Security/Test/SecureGetObjectDataOverridesTest.cs	(working copy)
@@ -155,7 +155,7 @@
 			ITypeDefinition type = GetTest ("SerializableClass");
 			// there's no GetObjectData method here so the test should never fail
 			foreach (IMethodDefinition method in type.Methods) {
-				Assert.IsTrue (rule.CheckMethod (assembly, module, type, method));
+				Assert.IsNull (rule.CheckMethod (assembly, module, type, method, new MinimalRunner()));
 			}
 		}
 
@@ -164,7 +164,7 @@
 		{
 			ITypeDefinition type = GetTest ("ISerializableClass");
 			IMethodDefinition method = GetObjectData (type);
-			Assert.IsFalse (rule.CheckMethod (assembly, module, type, method));
+			Assert.IsNotNull (rule.CheckMethod (assembly, module, type, method, new MinimalRunner()));
 		}
 
 		[Test]
@@ -172,7 +172,7 @@
 		{
 			ITypeDefinition type = GetTest ("InheritISerializableClass");
 			IMethodDefinition method = GetObjectData (type);
-			Assert.IsFalse (rule.CheckMethod (assembly, module, type, method));
+			Assert.IsNotNull (rule.CheckMethod (assembly, module, type, method, new MinimalRunner()));
 		}
 
 		[Test]
@@ -180,7 +180,7 @@
 		{
 			ITypeDefinition type = GetTest ("LinkDemandClass");
 			IMethodDefinition method = GetObjectData (type);
-			Assert.IsTrue (rule.CheckMethod (assembly, module, type, method));
+			Assert.IsNull (rule.CheckMethod (assembly, module, type, method, new MinimalRunner()));
 		}
 
 		[Test]
@@ -188,7 +188,7 @@
 		{
 			ITypeDefinition type = GetTest ("InheritanceDemandClass");
 			IMethodDefinition method = GetObjectData (type);
-			Assert.IsFalse (rule.CheckMethod (assembly, module, type, method));
+			Assert.IsNotNull (rule.CheckMethod (assembly, module, type, method, new MinimalRunner()));
 		}
 
 		[Test]
@@ -196,7 +196,7 @@
 		{
 			ITypeDefinition type = GetTest ("DemandClass");
 			IMethodDefinition method = GetObjectData (type);
-			Assert.IsTrue (rule.CheckMethod (assembly, module, type, method));
+			Assert.IsNull (rule.CheckMethod (assembly, module, type, method, new MinimalRunner()));
 		}
 
 		[Test]
@@ -204,7 +204,7 @@
 		{
 			ITypeDefinition type = GetTest ("DemandWrongPermissionClass");
 			IMethodDefinition method = GetObjectData (type);
-			Assert.IsFalse (rule.CheckMethod (assembly, module, type, method));
+			Assert.IsNotNull (rule.CheckMethod (assembly, module, type, method, new MinimalRunner()));
 		}
 	}
 }
Index: rules/Gendarme.Rules.Security/MethodCallWithSubsetLinkDemandRule.cs
===================================================================
--- rules/Gendarme.Rules.Security/MethodCallWithSubsetLinkDemandRule.cs	(revision 54948)
+++ rules/Gendarme.Rules.Security/MethodCallWithSubsetLinkDemandRule.cs	(working copy)
@@ -27,6 +27,7 @@
 //
 
 using System;
+using System.Collections;
 using System.Security;
 using System.Security.Permissions;
 
@@ -61,17 +62,17 @@
 			return calleeLinkDemand.IsSubsetOf (GetLinkDemand (caller));
 		}
 
-		public bool CheckMethod (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type, IMethodDefinition method)
+		public IList CheckMethod (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type, IMethodDefinition method, Runner runner)
 		{
 			// #1 - rule apply to methods are publicly accessible
 			//	note that the type doesn't have to be public (indirect access)
 			if ((method.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
-				return true;
+				return runner.RuleSuccess;
 
 			// #2 - rule apply only if the method has a body (e.g. p/invokes, icalls don't)
 			//	otherwise we don't know what it's calling
 			if (method.Body == null)
-				return true;
+				return runner.RuleSuccess;
 
 			// *** ok, the rule applies! ***
 
@@ -82,15 +83,16 @@
 				case "callvirt":
 					IMethodDefinition callee = AssemblyManager.GetMethod (ins.Operand);
 					if (callee == null) {
-						return true; // ignore (missing reference)
+						return runner.RuleSuccess; // ignore (missing reference)
 					}
 					// 4 - and if it has security, ensure we don't reduce it's strength
-					if ((callee.SecurityDeclarations.Count > 0) && !Check (method, callee))
-						return false;
+					if ((callee.SecurityDeclarations.Count > 0) && !Check (method, callee)) {
+						return runner.RuleFailure;
+					}
 					break;
 				}
 			}
-			return true;
+			return runner.RuleSuccess;
 		}
 	}
 }
Index: rules/Gendarme.Rules.Security/TypeLinkDemandRule.cs
===================================================================
--- rules/Gendarme.Rules.Security/TypeLinkDemandRule.cs	(revision 54948)
+++ rules/Gendarme.Rules.Security/TypeLinkDemandRule.cs	(working copy)
@@ -27,6 +27,7 @@
 //
 
 using System;
+using System.Collections;
 using System.Security;
 
 using Mono.Cecil;
@@ -36,7 +37,7 @@
 
 	public class TypeLinkDemandRule: ITypeRule {
 
-		public bool CheckType (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type)
+		public IList CheckType (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type, Runner runner)
 		{
 			// #1 - rule apply to types (and nested types) that are publicly visible
 			switch (type.Attributes & TypeAttributes.VisibilityMask) {
@@ -44,12 +45,12 @@
 			case TypeAttributes.NestedPublic:
 				break;
 			default:
-				return true;
+				return runner.RuleSuccess;
 			}
 
 			// #2 - rule apply to types that aren't sealed
 			if (type.IsSealed)
-				return true;
+				return runner.RuleSuccess;
 
 			PermissionSet link = null;
 			PermissionSet inherit = null;
@@ -68,7 +69,7 @@
 			}
 
 			if (link == null)
-				return true; // no LinkDemand == no problem
+				return runner.RuleSuccess; // no LinkDemand == no problem
 
 			// #4 - rule apply if there are virtual methods defined
 			bool virt = false;
@@ -79,14 +80,17 @@
 			}
 
 			if (!virt)
-				return true; // no virtual method == no problem
+				return runner.RuleSuccess; // no virtual method == no problem
 
 			// *** ok, the rule applies! ***
 
 			// #5 - and ensure the LinkDemand is a subset of the InheritanceDemand
 			if (inherit == null)
-				return false; // LinkDemand without InheritanceDemand
-			return link.IsSubsetOf (inherit);
+				return runner.RuleFailure; // LinkDemand without InheritanceDemand
+			if (link.IsSubsetOf (inherit))
+				return runner.RuleSuccess;
+			else
+				return runner.RuleFailure;
 		}
 	}
 }
Index: rules/Gendarme.Rules.Security/SecureGetObjectDataOverridesRule.cs
===================================================================
--- rules/Gendarme.Rules.Security/SecureGetObjectDataOverridesRule.cs	(revision 54948)
+++ rules/Gendarme.Rules.Security/SecureGetObjectDataOverridesRule.cs	(working copy)
@@ -27,6 +27,7 @@
 //
 
 using System;
+using System.Collections;
 using System.Security;
 using System.Security.Permissions;
 using System.Text;
@@ -51,19 +52,19 @@
 			}
 		}
 
-		public bool CheckMethod (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type, IMethodDefinition method)
+		public IList CheckMethod (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type, IMethodDefinition method, Runner runner)
 		{
 			// check that the method is called "GetObjectData"
 			if (method.Name != "GetObjectData")
-				return true;
+				return runner.RuleSuccess;
 
 			// check parameters
 			if (method.Parameters.Count != 2)
-				return true;
+				return runner.RuleSuccess;
 			if (method.Parameters[0].ParameterType.ToString () != "System.Runtime.Serialization.SerializationInfo")
-				return true;
+				return runner.RuleSuccess;
 			if (method.Parameters[1].ParameterType.ToString () != "System.Runtime.Serialization.StreamingContext")
-				return true;
+				return runner.RuleSuccess;
 
 			// check for ISerializable
 			bool iserialize = true; // FIXME
@@ -78,7 +79,7 @@
 
 			// is there any security applied ?
 			if (method.SecurityDeclarations.Count < 1)
-				return false;
+				return runner.RuleFailure;
 
 			// the SerializationFormatter must be a subset of the one (of the) demand(s)
 			foreach (ISecurityDeclaration declsec in method.SecurityDeclarations) {
@@ -88,12 +89,12 @@
 				case Mono.Cecil.SecurityAction.LinkDemand:
 				case Mono.Cecil.SecurityAction.NonCasLinkDemand:
 					if (RuleSet.IsSubsetOf (declsec.PermissionSet))
-						return true;
+						return runner.RuleSuccess;
 					break;
 				}
 			}
 
-			return false;
+			return runner.RuleFailure;
 		}
 	}
 }
Index: rules/Gendarme.Rules.Security/TypeExposeFieldsRule.cs
===================================================================
--- rules/Gendarme.Rules.Security/TypeExposeFieldsRule.cs	(revision 54948)
+++ rules/Gendarme.Rules.Security/TypeExposeFieldsRule.cs	(working copy)
@@ -27,6 +27,7 @@
 //
 
 using System;
+using System.Collections;
 using System.Text;
 
 using Mono.Cecil;
@@ -36,7 +37,7 @@
 
 	public class TypeExposeFieldsRule : ITypeRule {
 
-		public bool CheckType (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type)
+		public IList CheckType (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type, Runner runner)
 		{
 			// #1 - rule apply to types (and nested types) that are publicly visible
 			switch (type.Attributes & TypeAttributes.VisibilityMask) {
@@ -44,12 +45,12 @@
 			case TypeAttributes.NestedPublic:
 				break;
 			default:
-				return true;
+				return runner.RuleSuccess;
 			}
 
 			// #2 - rule apply to type is protected by a Demand or a LinkDemand
 			if (type.SecurityDeclarations.Count == 0)
-				return true;
+				return runner.RuleSuccess;
 
 			bool demand = false;
 			foreach (ISecurityDeclaration declsec in type.SecurityDeclarations) {
@@ -62,16 +63,16 @@
 			}
 
 			if (!demand)
-				return true;
+				return runner.RuleSuccess;
 
 			// *** ok, the rule applies! ***
 
 			// #3 - so it shouldn't have any public fields
 			foreach (IFieldDefinition field in type.Fields) {
 				if ((field.Attributes & FieldAttributes.Public) == FieldAttributes.Public)
-					return false;
+					return runner.RuleFailure;
 			}
-			return true;
+			return runner.RuleSuccess;
 		}
 	}
 }
Index: rules/Gendarme.Rules.Security/SealedTypeWithInheritanceDemandRule.cs
===================================================================
--- rules/Gendarme.Rules.Security/SealedTypeWithInheritanceDemandRule.cs	(revision 54948)
+++ rules/Gendarme.Rules.Security/SealedTypeWithInheritanceDemandRule.cs	(working copy)
@@ -27,6 +27,7 @@
 //
 
 using System;
+using System.Collections;
 
 using Mono.Cecil;
 using Gendarme.Framework;
@@ -35,22 +36,22 @@
 
 	public class SealedTypeWithInheritanceDemandRule : ITypeRule {
 
-		public bool CheckType (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type)
+		public IList CheckType (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type, Runner runner)
 		{
 			// 1 - this applies only to sealed types
 			if (!type.IsSealed)
-				return true;
+				return runner.RuleSuccess;
 
 			// 2 - the type must have an InheritanceDemand
 			if (type.SecurityDeclarations.Count == 0)
-				return true;
+				return runner.RuleSuccess;
 
 			foreach (ISecurityDeclaration declsec in type.SecurityDeclarations) {
 				if (declsec.Action == SecurityAction.InheritDemand)
-					return false;
+					return runner.RuleFailure;
 			}
 			// the action wasn't an inheritance demand check
-			return true;
+			return runner.RuleSuccess;
 		}
 	}
 }
Index: rules/Gendarme.Rules.Security/NonVirtualMethodWithInheritanceDemandRule.cs
===================================================================
--- rules/Gendarme.Rules.Security/NonVirtualMethodWithInheritanceDemandRule.cs	(revision 54948)
+++ rules/Gendarme.Rules.Security/NonVirtualMethodWithInheritanceDemandRule.cs	(working copy)
@@ -27,6 +27,7 @@
 //
 
 using System;
+using System.Collections;
 
 using Mono.Cecil;
 using Gendarme.Framework;
@@ -35,11 +36,11 @@
 
 	public class NonVirtualMethodWithInheritanceDemandRule : IMethodRule {
 
-		public bool CheckMethod (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type, IMethodDefinition method)
+		public IList CheckMethod (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type, IMethodDefinition method, Runner runner)
 		{
 			// #1 - this rule apply only to methods with an inheritance demand
 			if (method.SecurityDeclarations.Count == 0)
-				return true;
+				return runner.RuleSuccess;
 
 			bool inherit = false;
 			foreach (ISecurityDeclaration declsec in method.SecurityDeclarations) {
@@ -51,12 +52,15 @@
 				}
 			}
 			if (!inherit)
-				return true;
+				return runner.RuleSuccess;
 
 			// *** ok, the rule applies! ***
 
 			// #2 - InheritanceDemand doesn't make sense on methods that cannot be overriden
-			return method.IsVirtual;
+			if(method.IsVirtual)
+				return runner.RuleSuccess;
+			else
+				return runner.RuleFailure;
 		}
 	}
 }
Index: rules/Gendarme.Rules.Security/TypeIsNotSubsetOfMethodSecurityRule.cs
===================================================================
--- rules/Gendarme.Rules.Security/TypeIsNotSubsetOfMethodSecurityRule.cs	(revision 54948)
+++ rules/Gendarme.Rules.Security/TypeIsNotSubsetOfMethodSecurityRule.cs	(working copy)
@@ -27,6 +27,7 @@
 //
 
 using System;
+using System.Collections;
 using System.Security;
 using System.Text;
 
@@ -37,11 +38,11 @@
 
 	public class TypeIsNotSubsetOfMethodSecurityRule : ITypeRule {
 
-		public bool CheckType (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type)
+		public IList CheckType (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type, Runner runner)
 		{
 			// #1 - this rules apply if type as security permissions
 			if (type.SecurityDeclarations.Count == 0)
-				return true;
+				return runner.RuleSuccess;
 
 			PermissionSet assert = null;
 			PermissionSet deny = null;
@@ -73,7 +74,7 @@
 			// #2 - this rules doesn't apply to LinkDemand (both are executed) 
 			// and to InheritanceDemand (both are executed at different time).
 			if (!apply)
-				return true;
+				return runner.RuleSuccess;
 
 			// *** ok, the rule applies! ***
 
@@ -89,32 +90,32 @@
 						if (assert == null)
 							continue;
 						if (!assert.IsSubsetOf (declsec.PermissionSet))
-							return false;
+							return runner.RuleFailure;
 						break;
 					case Mono.Cecil.SecurityAction.Deny:
 						if (deny == null)
 							continue;
 						if (!deny.IsSubsetOf (declsec.PermissionSet))
-							return false;
+							return runner.RuleFailure;
 						break;
 					case Mono.Cecil.SecurityAction.PermitOnly:
 						if (permitonly == null)
 							continue;
 						if (!permitonly.IsSubsetOf (declsec.PermissionSet))
-							return false;
+							return runner.RuleFailure;
 						break;
 					case Mono.Cecil.SecurityAction.Demand:
 					case Mono.Cecil.SecurityAction.NonCasDemand:
 						if (demand == null)
 							continue;
 						if (!demand.IsSubsetOf (declsec.PermissionSet))
-							return false;
+							return runner.RuleFailure;
 						break;
 					}
 				}
 			}
 			// other types security applies
-			return true;
+			return runner.RuleSuccess;
 		}
 	}
 }
Index: rules/Gendarme.Rules.Concurrency/DoubleCheckLockingRule.cs
===================================================================
--- rules/Gendarme.Rules.Concurrency/DoubleCheckLockingRule.cs	(revision 54948)
+++ rules/Gendarme.Rules.Concurrency/DoubleCheckLockingRule.cs	(working copy)
@@ -1,5 +1,5 @@
 /*
- * DCLChecker.cs: looks for instances of double-check locking.
+ * DoubleCheckLockingRule.cs: looks for instances of double-check locking.
  *
  * Authors:
  *   Aaron Tomb <atomb at soe.ucsc.edu>
@@ -17,15 +17,19 @@
 using Mono.Cecil.Cil;
 using Gendarme.Framework;
 
+namespace Gendarme.Rules.Concurrency {
+
 public class DoubleCheckLockingRule : IMethodRule {
 
-    public bool CheckMethod (IAssemblyDefinition assembly, IModuleDefinition module,
-            ITypeDefinition type, IMethodDefinition method)
+    public IList CheckMethod (IAssemblyDefinition assembly,
+            IModuleDefinition module,
+            ITypeDefinition type, IMethodDefinition method,
+            Runner runner)
     {
         Hashtable comparisons = new Hashtable();
 
         if(method.Body == null)
-            return true;
+            return runner.RuleSuccess;
 
         IInstructionCollection insns = method.Body.Instructions;
 
@@ -40,22 +44,25 @@
                     foreach(IInstruction insn in comparisons.Keys) {
                         IInstruction[] twoBeforeI =
                             (IInstruction[])comparisons[insn];
-                        if(EffectivelyEqual(insn, insns[i]) &&
-                           EffectivelyEqual(twoBeforeI[0], twoBefore[0]) &&
-                           EffectivelyEqual(twoBeforeI[1], twoBefore[1]) &&
-                           mcount > 0 &&
-                           insn.Offset < (int)monitorOffsetList[mcount - 1]) {
-                            return false;
-                            /* TODO: restore messages */
-                            /*
-                            string etype = method.DeclaringType.FullName;
-                            Location loc = new Location(etype, method.Name,
-                                    insn.Offset);
-                            report.AddMessage(new Message(
-                                        "possible double-check locking",
-                                        loc, MessageType.Warning));
-                                        */
-                        }
+                        if(!EffectivelyEqual(insn, insns[i]))
+                            continue;
+                        if(!EffectivelyEqual(twoBeforeI[0], twoBefore[0]))
+                            continue;
+                        if(!EffectivelyEqual(twoBeforeI[1], twoBefore[1]))
+                            continue;
+                        if(mcount <= 0)
+                            continue;
+                        if(insn.Offset >= (int)monitorOffsetList[mcount - 1])
+                            continue;
+                        IList messages = new ArrayList();
+                        string etype = method.DeclaringType.FullName;
+                        Location loc = new Location(etype, method.Name,
+                                insn.Offset);
+                        Message msg = new Message(
+                                    "possible double-check locking",
+                                    loc, MessageType.Warning);
+                        messages.Add(msg);
+                        return messages;
                     }
                 }
                 comparisons[insns[i]] = twoBefore;
@@ -66,7 +73,7 @@
                 if(mcount > 0)
                     monitorOffsetList.RemoveAt(monitorOffsetList.Count - 1);
         }
-        return true;
+        return runner.RuleSuccess;
     }
 
     private bool IsMonitorMethod(IInstruction insn, string methodName)
@@ -110,3 +117,5 @@
         return false;
     }
 }
+
+}
Index: rules/Gendarme.Rules.Correctness/NullDerefFrame.cs
===================================================================
--- rules/Gendarme.Rules.Correctness/NullDerefFrame.cs	(revision 0)
+++ rules/Gendarme.Rules.Correctness/NullDerefFrame.cs	(revision 0)
@@ -0,0 +1,250 @@
+/*
+ * NullDerefFrame.cs: the fact passed around in dataflow analysis for
+ * null-dereference checking.
+ *
+ * Authors:
+ *   Aaron Tomb <atomb at soe.ucsc.edu>
+ *
+ * Copyright (c) 2005 Aaron Tomb and the contributors listed
+ * in the ChangeLog.
+ *
+ * This is free software, distributed under the MIT/X11 license.
+ * See the included LICENSE.MIT file for details.
+ **********************************************************************/
+
+using System;
+
+namespace Gendarme.Rules.Correctness {
+
+public class NullDerefFrame : ICloneable {
+    [NonNull] private Nullity[] stack;
+    [NonNull] private Nullity[] locals;
+    [NonNull] private Nullity[] args;
+    int stackDepth;
+
+    /* Unused   Null     NonNull  Unknown            */
+    /* -------------------------------------         */
+    /* Unused   Null     NonNull  Unknown  | Unused  */
+    /* Null     Null     Unknown  Unknown  | Null    */
+    /* NonNull  Unknown  NonNull  Unknown  | NonNull */
+    /* Unknown  Unknown  Unknown  Unknown  | Uknown  */
+    [NonNull] private static Nullity[][] lub = {
+        new Nullity[] { Nullity.Unused, Nullity.Null,
+            Nullity.NonNull, Nullity.Unknown },
+        new Nullity[] { Nullity.Null, Nullity.Null,
+            Nullity.Unknown, Nullity.Unknown },
+        new Nullity[] { Nullity.NonNull, Nullity.Unknown,
+            Nullity.NonNull, Nullity.Unknown },
+        new Nullity[] { Nullity.Unknown, Nullity.Unknown,
+            Nullity.Unknown, Nullity.Unknown },
+    };
+
+    public NullDerefFrame(int maxStackDepth, int numLocals, int numArgs,
+            bool entry)
+    {
+        int i;
+
+        stackDepth = 0;
+        stack = new Nullity[maxStackDepth];
+        locals = new Nullity[numLocals];
+        args = new Nullity[numArgs];
+        for(i = 0; i < maxStackDepth; i++)
+            stack[i] = Nullity.Unused;
+
+        if(entry) {
+            for(i = 0; i < numLocals; i++)
+                locals[i] = Nullity.Null;
+            for(i = 0; i < numArgs; i++)
+                args[i] = Nullity.Unknown;
+        } else {
+            for(i = 0; i < numLocals; i++)
+                locals[i] = Nullity.Unused;
+            for(i = 0; i < numArgs; i++)
+                args[i] = Nullity.Unused;
+        }
+    }
+
+    public void PushStack(Nullity n)
+    {
+        if(stackDepth == stack.Length) {
+            throw new Exception("Nullity stack overflow");
+        }
+        /*
+        if(BugFinder.opts.Debug)
+            Console.WriteLine("Push: {0} {1} {2}", stackDepth,
+                    stack.Length, n);
+                    */
+        stack[stackDepth] = n;
+        stackDepth++;
+    }
+
+    [NonNull]
+    public Nullity PopStack()
+    {
+        if(stackDepth == 0) {
+            throw new Exception("Nullity stack underflow");
+        }
+        /*
+        if(BugFinder.opts.Debug)
+            Console.WriteLine("Pop: {0} {1} {2}", stackDepth,
+                    stack.Length, stack[stackDepth - 1]);
+                    */
+        stackDepth--;
+        Nullity result = stack[stackDepth];
+        stack[stackDepth] = Nullity.Unused;
+        return result;
+    }
+
+    public void PopStack(int count)
+    {
+        for(int i = 0; i < count; i++)
+            PopStack();
+    }
+
+    public void EmptyStack()
+    {
+        PopStack(stackDepth);
+    }
+
+    [NonNull]
+    public Nullity PeekStack()
+    {
+        if(stackDepth == 0) {
+            throw new Exception("Nullity stack underflow");
+        }
+        return stack[stackDepth - 1];
+    }
+
+    public void SetLocNullity(int index, Nullity n)
+    {
+        /*
+        if(BugFinder.opts.Debug)
+            Console.WriteLine("SetLoc {0} {1} {2}", index, locals.Length, n);
+            */
+        locals[index] = n;
+    }
+
+    [NonNull]
+    public Nullity GetLocNullity(int index)
+    {
+        /*
+        if(BugFinder.opts.Debug)
+            Console.WriteLine("GetLoc {0} {1} {2}", index, locals.Length,
+                    locals[index]);
+                    */
+        return locals[index];
+    }
+
+    public void SetArgNullity(int index, Nullity n)
+    {
+        /*
+        if(BugFinder.opts.Debug)
+            Console.WriteLine("SetArg {0} {1} {2}", index, args.Length, n);
+            */
+        args[index] = n;
+    }
+
+    [NonNull]
+    public Nullity GetArgNullity(int index)
+    {
+        /*
+        if(BugFinder.opts.Debug)
+            Console.WriteLine("GetArg {0} {1} {2}", index, args.Length,
+                    args[index]);
+                    */
+        return args[index];
+    }
+
+    public void MergeWith([NonNull] NullDerefFrame incoming)
+    {
+        int i;
+        if(locals.Length != incoming.locals.Length ||
+                args.Length != incoming.args.Length ||
+                stack.Length != incoming.stack.Length)
+            throw new Exception("Merging incompatible frames");
+
+        for(i = 0; i < locals.Length; i++)
+            locals[i] = MergeNullity(locals[i], incoming.locals[i]);
+        for(i = 0; i < args.Length; i++)
+            args[i] = MergeNullity(args[i], incoming.args[i]);
+        for(i = 0; i < stack.Length; i++)
+            stack[i] = MergeNullity(stack[i], incoming.stack[i]);
+        if(incoming.stackDepth > stackDepth)
+            stackDepth = incoming.stackDepth;
+    }
+
+    [NonNull]
+    public Nullity MergeNullity(Nullity n1, Nullity n2)
+    {
+        return lub[(int)n1][(int)n2];
+    }
+
+    public override bool Equals(object o)
+    {
+        if(o == null)
+            return false;
+        NullDerefFrame frame = (NullDerefFrame)o;
+        if(this.stackDepth != frame.stackDepth)
+            return false;
+        if(this.stack.Length != frame.stack.Length)
+            return false;
+        if(this.args.Length != frame.args.Length)
+            return false;
+        if(this.locals.Length != frame.locals.Length)
+            return false;
+        int i;
+        for(i = 0; i < this.stack.Length; i++)
+            if(this.stack[i] != frame.stack[i])
+                return false;
+        for(i = 0; i < this.args.Length; i++)
+            if(this.args[i] != frame.args[i])
+                return false;
+        for(i = 0; i < this.locals.Length; i++)
+            if(this.locals[i] != frame.locals[i])
+                return false;
+        return true;
+    }
+
+    public override int GetHashCode()
+    {
+        /* FIXME: we can do better than this, perhaps? */
+        return base.GetHashCode();
+    }
+
+    [NonNull]
+    public object Clone()
+    {
+        NullDerefFrame result = new NullDerefFrame(stack.Length,
+                locals.Length, args.Length, false);
+        int i;
+
+        for(i = 0; i < locals.Length; i++)
+            result.locals[i] = locals[i];
+        for(i = 0; i < args.Length; i++)
+            result.args[i] = args[i];
+        for(i = 0; i < stack.Length; i++)
+            result.stack[i] = stack[i];
+        result.stackDepth = stackDepth;
+        return result;
+    }
+
+    public override string ToString()
+    {
+        string result;
+        int i;
+
+        result = "Locals {";
+        for(i = 0; i < locals.Length; i++)
+            result += " " + locals[i].ToString();
+        result += " }\nArgs { ";
+        for(i = 0; i < args.Length; i++)
+            result += " " + args[i].ToString();
+        result += " }\nStack { ";
+        for(i = 0; i < stack.Length; i++)
+            result += " " + stack[i].ToString();
+        result += " }\nstackDepth = " + stackDepth + "\n";
+        return result;
+    }
+}
+
+}
Index: rules/Gendarme.Rules.Correctness/graph/DFS.cs
===================================================================
--- rules/Gendarme.Rules.Correctness/graph/DFS.cs	(revision 0)
+++ rules/Gendarme.Rules.Correctness/graph/DFS.cs	(revision 0)
@@ -0,0 +1,70 @@
+/*
+ * DFS.cs: performs a depth-first search on a graph.
+ *
+ * Authors:
+ *   Aaron Tomb <atomb at soe.ucsc.edu>
+ *
+ * Copyright (c) 2005 Aaron Tomb and the contributors listed
+ * in the ChangeLog.
+ *
+ * This is free software, distributed under the MIT/X11 license.
+ * See the included LICENSE.MIT file for details.
+ **********************************************************************/
+
+using System.Collections;
+
+namespace Gendarme.Rules.Correctness {
+
+public class DFS {
+    private const int WHITE = 1;
+    private const int GRAY = 2;
+    private const int BLACK = 3;
+
+    [NonNull] private ArrayList orderedNodes;
+    [NonNull] private Graph graph;
+    [NonNull] private Node initial;
+    [NonNull] private Hashtable colors;
+
+    public DFS([NonNull] Graph graph, [NonNull] Node initial)
+    {
+        this.orderedNodes = new ArrayList();
+        this.graph = graph;
+        this.initial = initial;
+        this.colors = new Hashtable(graph.NodeCount);
+    }
+
+    public void Traverse() 
+    {
+        foreach(object o in graph.Nodes)
+            colors[o] = WHITE;
+
+        /* Start with given initial node */
+        TraverseInternal(initial);
+
+        /* Cover any nodes not reachable from the given initial node. */
+        foreach(object o in graph.Nodes)
+            if((int)colors[o] == WHITE)
+                TraverseInternal((Node)o);
+
+        orderedNodes.Reverse();
+    }
+
+    private void TraverseInternal(Node node)
+    {
+        colors[node] = GRAY;
+        foreach(object o in graph.Successors(node)) {
+            Node succ = (Node)o;
+            if((int)colors[succ] == WHITE)
+                TraverseInternal(succ);
+        }
+        orderedNodes.Add(node);
+        colors[node] = BLACK;
+    }
+
+    public IList OrderedNodes {
+        [NonNull]
+        get { return orderedNodes; }
+    }
+}
+
+}
Index: rules/Gendarme.Rules.Correctness/graph/IEdge.cs
===================================================================
--- rules/Gendarme.Rules.Correctness/graph/IEdge.cs	(revision 0)
+++ rules/Gendarme.Rules.Correctness/graph/IEdge.cs	(revision 0)
@@ -0,0 +1,21 @@
+/*
+ * IEdge.cs: the interface graph edges must implement.
+ *
+ * Authors:
+ *   Aaron Tomb <atomb at soe.ucsc.edu>
+ *
+ * Copyright (c) 2005 Aaron Tomb and the contributors listed
+ * in the ChangeLog.
+ *
+ * This is free software, distributed under the MIT/X11 license.
+ * See the included LICENSE.MIT file for details.
+ **********************************************************************/
+
+namespace Gendarme.Rules.Correctness {
+
+public interface IEdge {
+    Node Start { get; }
+    Node End { get; }
+}
+
+}
Index: rules/Gendarme.Rules.Correctness/graph/INode.cs
===================================================================
--- rules/Gendarme.Rules.Correctness/graph/INode.cs	(revision 0)
+++ rules/Gendarme.Rules.Correctness/graph/INode.cs	(revision 0)
@@ -0,0 +1,19 @@
+/*
+ * INode.cs: the interface arbitrary graph nodes must implement.
+ *
+ * Authors:
+ *   Aaron Tomb <atomb at soe.ucsc.edu>
+ *
+ * Copyright (c) 2005 Aaron Tomb and the contributors listed
+ * in the ChangeLog.
+ *
+ * This is free software, distributed under the MIT/X11 license.
+ * See the included LICENSE.MIT file for details.
+ **********************************************************************/
+
+namespace Gendarme.Rules.Correctness {
+
+public interface INode {
+}
+
+}
Index: rules/Gendarme.Rules.Correctness/graph/Graph.cs
===================================================================
--- rules/Gendarme.Rules.Correctness/graph/Graph.cs	(revision 0)
+++ rules/Gendarme.Rules.Correctness/graph/Graph.cs	(revision 0)
@@ -0,0 +1,98 @@
+/*
+ * Graph.cs: greneric graph skeleton.
+ *
+ * Authors:
+ *   Aaron Tomb <atomb at soe.ucsc.edu>
+ *
+ * Copyright (c) 2005 Aaron Tomb and the contributors listed
+ * in the ChangeLog.
+ *
+ * This is free software, distributed under the MIT/X11 license.
+ * See the included LICENSE.MIT file for details.
+ **********************************************************************/
+
+using System;
+using System.Collections;
+
+namespace Gendarme.Rules.Correctness {
+
+public class Graph : IGraph {
+    [NonNull] private IList edges;
+    [NonNull] private IList nodes;
+    [NonNull] private IDictionary predecessors;
+    [NonNull] private IDictionary successors;
+
+    public Graph()
+    {
+        edges = new ArrayList();
+        nodes = new ArrayList();
+        predecessors = new Hashtable();
+        successors = new Hashtable();
+    }
+
+    public IList Edges {
+        [NonNull]
+        get { return edges; }
+    }
+
+    public IList Nodes {
+        [NonNull]
+        get { return nodes; }
+    }
+
+    public int EdgeCount {
+        get { return edges.Count; }
+    }
+
+    public int NodeCount {
+        get { return nodes.Count; }
+    }
+
+    public IList Predecessors([NonNull] Node node)
+    {
+        return (IList)predecessors[node];
+    }
+
+    public IList Successors([NonNull] Node node)
+    {
+        return (IList)successors[node];
+    }
+
+    public void AddNode([NonNull] Node /*Type*/ node)
+    {
+        nodes.Add(node);
+        predecessors[node] = new ArrayList();
+        successors[node] = new ArrayList();
+    }
+
+    public bool ContainsNode([NonNull] Node /*Type*/ node)
+    {
+        return nodes.Contains(node);
+    }
+
+    public void AddEdge([NonNull] Edge /*Type*/ edge)
+    {
+        edges.Add(edge);
+        AddSuccessor(edge.Start, edge.End);
+        AddPredecessor(edge.End, edge.Start);
+    }
+
+    public bool ContainsEdge([NonNull] Edge /*Type*/ edge)
+    {
+        return edges.Contains(edge);
+    }
+
+    private void AddPredecessor([NonNull] Node node, [NonNull] Node pred)
+    {
+        IList predList = (IList)predecessors[node];
+        predList.Add(pred);
+    }
+
+    private void AddSuccessor([NonNull] Node node, [NonNull] Node succ)
+    {
+        IList succList = (IList)successors[node];
+        succList.Add(succ);
+    }
+}
+
+}
Index: rules/Gendarme.Rules.Correctness/graph/Edge.cs
===================================================================
--- rules/Gendarme.Rules.Correctness/graph/Edge.cs	(revision 0)
+++ rules/Gendarme.Rules.Correctness/graph/Edge.cs	(revision 0)
@@ -0,0 +1,32 @@
+/*
+ * Edge.cs: generic edge abstraction for arbitrary graphs.
+ *
+ * Authors:
+ *   Aaron Tomb <atomb at soe.ucsc.edu>
+ *
+ * Copyright (c) 2005 Aaron Tomb and the contributors listed
+ * in the ChangeLog.
+ *
+ * This is free software, distributed under the MIT/X11 license.
+ * See the included LICENSE.MIT file for details.
+ **********************************************************************/
+
+namespace Gendarme.Rules.Correctness {
+
+public class Edge : IEdge {
+
+    [NonNull] protected Node start;
+    [NonNull] protected Node end;
+
+    public Node Start {
+        [NonNull]
+        get { return start; }
+    }
+
+    public Node End {
+        [NonNull]
+        get { return end; }
+    }
+}
+
+}
Index: rules/Gendarme.Rules.Correctness/graph/Node.cs
===================================================================
--- rules/Gendarme.Rules.Correctness/graph/Node.cs	(revision 0)
+++ rules/Gendarme.Rules.Correctness/graph/Node.cs	(revision 0)
@@ -0,0 +1,19 @@
+/*
+ * Node.cs: a generic graph node.
+ *
+ * Authors:
+ *   Aaron Tomb <atomb at soe.ucsc.edu>
+ *
+ * Copyright (c) 2005 Aaron Tomb and the contributors listed
+ * in the ChangeLog.
+ *
+ * This is free software, distributed under the MIT/X11 license.
+ * See the included LICENSE.MIT file for details.
+ **********************************************************************/
+
+namespace Gendarme.Rules.Correctness {
+
+public class Node : INode {
+}
+
+}
Index: rules/Gendarme.Rules.Correctness/graph/IGraph.cs
===================================================================
--- rules/Gendarme.Rules.Correctness/graph/IGraph.cs	(revision 0)
+++ rules/Gendarme.Rules.Correctness/graph/IGraph.cs	(revision 0)
@@ -0,0 +1,29 @@
+/*
+ * IGraph.cs: the interface arbitrary graphs must implement.
+ *
+ * Authors:
+ *   Aaron Tomb <atomb at soe.ucsc.edu>
+ *
+ * Copyright (c) 2005 Aaron Tomb and the contributors listed
+ * in the ChangeLog.
+ *
+ * This is free software, distributed under the MIT/X11 license.
+ * See the included LICENSE.MIT file for details.
+ **********************************************************************/
+
+using System.Collections;
+
+namespace Gendarme.Rules.Correctness {
+
+public interface IGraph {
+    IList Edges { get; }
+    IList Nodes { get; }
+    int EdgeCount { get; }
+    int NodeCount { get; }
+    void AddNode(Node node);
+    bool ContainsNode(Node node);
+    void AddEdge(Edge edge);
+    bool ContainsEdge(Edge edge);
+}
+
+}
Index: rules/Gendarme.Rules.Correctness/dataflow/BasicBlock.cs
===================================================================
--- rules/Gendarme.Rules.Correctness/dataflow/BasicBlock.cs	(revision 0)
+++ rules/Gendarme.Rules.Correctness/dataflow/BasicBlock.cs	(revision 0)
@@ -0,0 +1,57 @@
+/*
+ * BasicBlock.cs: simple representation of basic blocks.
+ *
+ * Authors:
+ *   Aaron Tomb <atomb at soe.ucsc.edu>
+ *
+ * Copyright (c) 2005 Aaron Tomb and the contributors listed
+ * in the ChangeLog.
+ *
+ * This is free software, distributed under the MIT/X11 license.
+ * See the included LICENSE.MIT file for details.
+ **********************************************************************/
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+namespace Gendarme.Rules.Correctness {
+
+public class BasicBlock : Node {
+    /* All instructions in the method */
+    [NonNull] private IInstructionCollection instructions;
+
+    /* Index of the first instruction in this basic block */
+    public int first;
+
+    /* Index of the last instruction in this basic block */
+    public int last;
+
+    public bool isExit = false;
+    public bool isException = false;
+
+    public BasicBlock([NonNull] IInstructionCollection instructions)
+    {
+        this.instructions = instructions;
+    }
+
+    public IInstructionCollection Instructions {
+        [NonNull]
+        get { return instructions; }
+    }
+
+    public IInstruction FirstInstruction {
+        get { return instructions[first]; }
+    }
+
+    [NonNull]
+    public override string ToString() {
+        if(isExit)
+            return "exit";
+        if(isException)
+            return "exception";
+        return instructions[first].Offset.ToString("X4") + "-" +
+            instructions[last].Offset.ToString("X4");
+    }
+}
+
+}
Index: rules/Gendarme.Rules.Correctness/dataflow/IDataflowAnalysis.cs
===================================================================
--- rules/Gendarme.Rules.Correctness/dataflow/IDataflowAnalysis.cs	(revision 0)
+++ rules/Gendarme.Rules.Correctness/dataflow/IDataflowAnalysis.cs	(revision 0)
@@ -0,0 +1,31 @@
+/*
+ * IDataflowAnalysis.cs: the interface specific dataflow analyses must
+ * implement.
+ *
+ * Authors:
+ *   Aaron Tomb <atomb at soe.ucsc.edu>
+ *
+ * Copyright (c) 2005 Aaron Tomb and the contributors listed
+ * in the ChangeLog.
+ *
+ * This is free software, distributed under the MIT/X11 license.
+ * See the included LICENSE.MIT file for details.
+ **********************************************************************/
+
+using System.Collections;
+
+namespace Gendarme.Rules.Correctness {
+
+public interface IDataflowAnalysis {
+    object NewTop();
+
+    object NewEntry();
+    
+    object NewCatch();
+
+    void MeetInto(object originalFact, object newFact, bool warn);
+
+    void Transfer(Node node, object inFact, object outFact, bool warn);
+}
+
+}
Index: rules/Gendarme.Rules.Correctness/dataflow/CFG.cs
===================================================================
--- rules/Gendarme.Rules.Correctness/dataflow/CFG.cs	(revision 0)
+++ rules/Gendarme.Rules.Correctness/dataflow/CFG.cs	(revision 0)
@@ -0,0 +1,361 @@
+/*
+ * CFG.cs: code for control flow graphs -- graphs made up of basic
+ * blocks.
+ *
+ * Authors:
+ *   Aaron Tomb <atomb at soe.ucsc.edu>
+ *
+ * Copyright (c) 2005 Aaron Tomb and the contributors listed
+ * in the ChangeLog.
+ *
+ * This is free software, distributed under the MIT/X11 license.
+ * See the included LICENSE.MIT file for details.
+ **********************************************************************/
+
+using System;
+using System.Collections;
+using System.IO;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+namespace Gendarme.Rules.Correctness {
+
+public class CFG : Graph { 
+
+    [NonNull] private IInstructionCollection instructions;
+    [NonNull] private IMethodDefinition method;
+    [NonNull] private IDictionary branchTable;
+    private BasicBlock entryPoint;
+
+    public BasicBlock EntryPoint {
+        get { return entryPoint; }
+    }
+
+    public CFG([NonNull] IMethodDefinition method)
+    {
+        Init(method.Body.Instructions, method);
+    }
+
+    public CFG(IInstructionCollection instructions)
+    {
+        Init(instructions, null);
+    }
+
+    private void Init([NonNull] IInstructionCollection instructions,
+            [NonNull] IMethodDefinition method)
+    {
+        this.instructions = instructions;
+        this.method = method;
+        InitBranchTable();
+        BuildGraph();
+    }
+
+    private bool IsBranch(IInstruction instruction)
+    {
+        if(instruction == null)
+            return false;
+        switch(instruction.OpCode.FlowControl) {
+            case FlowControl.Branch: return true;
+            case FlowControl.Cond_Branch: return true;
+            case FlowControl.Return: return true;
+            /* Throw creates a new basic block, but it has no target,
+             * because the object to be thrown is taken from the stack.
+             * Thus, its type is not known before runtime, and we can't
+             * know which catch block will recieve it. */
+            case FlowControl.Throw: return true;
+        }
+        return false;
+    }
+
+    private bool HasNext([NonNull] IInstruction instruction)
+    {
+        if(instruction.OpCode.FlowControl == FlowControl.Branch)
+            return false;
+        if(instruction.OpCode.FlowControl == FlowControl.Throw)
+            return false;
+        if(instruction.OpCode.FlowControl == FlowControl.Return)
+            return false;
+        else
+            return true;
+    }
+
+    private int[] BranchTargets([NonNull] IInstruction instruction)
+    {
+        int[] result = null;
+        switch(instruction.OpCode.OperandType) {
+            case OperandType.InlineSwitch:
+                IInstruction[] targets = (IInstruction[])instruction.Operand;
+                result = new int[targets.Length];
+                int i = 0;
+                foreach(IInstruction target in targets) {
+                    result[i] = target.Offset;
+                    i++;
+                }
+                break;
+            case OperandType.InlineBrTarget:
+                result = new int[1];
+                result[0] = ((IInstruction)instruction.Operand).Offset;
+                break;
+            case OperandType.ShortInlineBrTarget:
+                result = new int[1];
+                result[0] = ((IInstruction)instruction.Operand).Offset;
+                break;
+        }
+        return result;
+    }
+
+    public bool BeginsCatch(BasicBlock bb)
+    {
+        IExceptionHandler handler = StartsHandlerRegion(bb.FirstInstruction);
+        if(handler != null && handler.Type == ExceptionHandlerType.Catch)
+            return true;
+        return false;
+    }
+
+    private BasicBlock GetNearestFinally(IInstruction insn, Hashtable insnBB)
+    {
+        BasicBlock nearest = null;
+        IInstructionCollection insns = method.Body.Instructions;
+        int width = insns[insns.Count - 1].Offset;
+        foreach(IExceptionHandler handler in method.Body.ExceptionHandlers) {
+            if(handler.Type == ExceptionHandlerType.Finally) {
+                if(insn.Offset >= handler.TryStart.Offset &&
+                        insn.Offset < handler.TryEnd.Offset &&
+                        (handler.TryEnd.Offset -
+                         handler.TryStart.Offset) < width)
+                    nearest = (BasicBlock)insnBB[handler.HandlerStart.Offset];
+            }
+        }
+        return nearest;
+    }
+
+    private bool OffsetsEqual(IInstruction insn1, IInstruction insn2)
+    {
+        if(insn1 == insn2) return true;
+        if(insn1 == null) return false;
+        if(insn2 == null) return false;
+        if(insn1.Offset == insn2.Offset) return true;
+        return false;
+    }
+
+    private IExceptionHandler EndsTryRegion([NonNull] IInstruction instruction)
+    {
+        foreach(IExceptionHandler handler in method.Body.ExceptionHandlers) {
+            if(instruction != null)
+                if(OffsetsEqual(instruction.Next, handler.TryEnd))
+                    return handler;
+        }
+        return null;
+    }
+
+    private IExceptionHandler EndsHandlerRegion(
+            [NonNull] IInstruction instruction)
+    {
+        foreach(IExceptionHandler handler in method.Body.ExceptionHandlers) {
+            if(instruction != null)
+                if(OffsetsEqual(instruction.Next, handler.HandlerEnd))
+                    return handler;
+        }
+        return null;
+    }
+
+    private IExceptionHandler StartsTryRegion(
+            [NonNull] IInstruction instruction)
+    {
+        foreach(IExceptionHandler handler in method.Body.ExceptionHandlers) {
+            if(OffsetsEqual(instruction, handler.TryStart))
+                return handler;
+        }
+        return null;
+    }
+
+    private IExceptionHandler StartsHandlerRegion(
+            [NonNull] IInstruction instruction)
+    {
+        foreach(IExceptionHandler handler in method.Body.ExceptionHandlers) {
+            if(OffsetsEqual(instruction, handler.HandlerStart))
+                return handler;
+        }
+        return null;
+    }
+
+    private bool IsLeader([NonNull] IInstruction instruction,
+            [NonNull] IInstruction previous)
+    {
+        /* First instruction in the method */
+        if(previous == null)
+            return true;
+
+        /* Target of a branch */
+        if(branchTable.Contains(instruction.Offset))
+            return true;
+
+        /* Follows a control flow instruction */
+        if(IsBranch(instruction.Previous))
+            return true;
+
+        /* Is the beginning of a try region */
+        if(StartsTryRegion(instruction) != null)
+            return true;
+
+        /* Is the beginning of a handler region */
+        if(StartsHandlerRegion(instruction) != null)
+            return true;
+
+        return false;
+    }
+
+    private void InitBranchTable() {
+        branchTable = new Hashtable();
+        foreach(IInstruction instr in instructions) {
+            int[] targets = BranchTargets(instr);
+            if(targets != null)
+                foreach(int target in targets)
+                    if(!branchTable.Contains(target)) {
+                        IList sources = new ArrayList();
+                        sources.Add(target);
+                        branchTable.Add(target, sources);
+                    } else {
+                        IList sources = (IList)branchTable[target];
+                        sources.Add(target);
+                    }
+        }
+    }
+
+    private void BuildGraph() {
+        BasicBlock tail = null;
+        IInstruction prevInsn = null;
+        BasicBlock prevBB = null;
+        int currentInsnNum = 0;
+        Hashtable insnBB = new Hashtable();
+        BasicBlock exit = new BasicBlock(instructions);
+        exit.first = exit.last = 0;
+        exit.isExit = true;
+        AddNode(exit);
+
+        foreach(IInstruction insn in instructions) {
+            if(IsLeader(insn, prevInsn)) {
+                tail = new BasicBlock(instructions);
+                tail.first = currentInsnNum;
+                AddNode(tail);
+                if(prevBB != null) {
+                    prevBB.last = currentInsnNum - 1;
+                    if(HasNext(instructions[currentInsnNum - 1])) {
+                        CFGEdge edge = new CFGEdge(prevBB, tail,
+                                CFGEdgeType.Forward);
+                        AddEdge(edge);
+                    }
+                }
+            }
+            insnBB.Add(insn.Offset, tail);
+            prevInsn = insn;
+            prevBB = tail;
+            currentInsnNum++;
+        }
+        if(prevBB != null) {
+            prevBB.last = currentInsnNum - 1;
+        }
+
+        foreach(IInstruction insn in instructions) {
+            if((EndsTryRegion(insn) != null) ||
+                    (EndsHandlerRegion(insn) != null)) { 
+                BasicBlock finallyBB = GetNearestFinally(insn, insnBB);
+                if(finallyBB != null)
+                    AddEdge(new CFGEdge((BasicBlock)insnBB[insn.Offset],
+                                finallyBB, CFGEdgeType.Forward));
+            }
+
+            if(insn.OpCode.FlowControl == FlowControl.Return) {
+                if(insn.OpCode.Value == OpCodeConstants.Endfinally &&
+                        insn.Next != null) {
+                    AddEdge(new CFGEdge((BasicBlock)insnBB[insn.Offset],
+                                (BasicBlock)insnBB[insn.Next.Offset],
+                                CFGEdgeType.Forward));
+                } else {
+                    AddEdge(new CFGEdge((BasicBlock)insnBB[insn.Offset],
+                                exit, CFGEdgeType.Return));
+                }
+            }
+            /*
+            if((insn.OpCode.Value != OpCodeConstants.Leave) &&
+                    (insn.OpCode.Value != OpCodeConstants.Endfinally)) {
+                    */
+                int[] targets = BranchTargets(insn);
+                if(targets == null)
+                    continue;
+                foreach(int target in targets) {
+                    AddEdge(new CFGEdge((BasicBlock)insnBB[insn.Offset],
+                                (BasicBlock)insnBB[target],
+                                CFGEdgeType.Branch));
+                }
+            /*} */
+        }
+
+        entryPoint = (BasicBlock)insnBB[0];
+    }
+
+    public void PrintBasicBlocks() {
+        IInstruction prevInstr = null;
+
+        Console.WriteLine(method.Name);
+        foreach(IInstruction instr in instructions) {
+            if(StartsTryRegion(instr) != null)
+                Console.WriteLine("Try {");
+            if(StartsHandlerRegion(instr) != null)
+                Console.WriteLine("Handle {");
+
+            if(IsLeader(instr, prevInstr))
+                Console.Write("* ");
+            else
+                Console.Write("  ");
+            Console.Write("  {0}: {1}", instr.Offset.ToString("X4"),
+                    instr.OpCode.Name);
+            int[] targets = BranchTargets(instr);
+            if(targets != null)
+                foreach(int target in targets)
+                    Console.Write(" {0}", target.ToString("X4"));
+            else if(instr.Operand is string)
+                Console.Write(" \"{0}\"", instr.Operand.ToString());
+            else if(instr.Operand != null)
+                Console.Write(" {0}", instr.Operand.ToString());
+            Console.WriteLine();
+            prevInstr = instr;
+            if(EndsTryRegion(instr) != null)
+                Console.WriteLine("} (Try)");
+            if(EndsHandlerRegion(instr) != null)
+                Console.WriteLine("} (Handle)");
+        }
+    }
+
+    public void PrintDot() {
+        string name = method.DeclaringType.Name + "." + method.Name + ".dot";
+        FileMode mode = FileMode.Create;
+        StreamWriter writer = new StreamWriter(new FileStream(name, mode));
+        writer.Write("digraph {0} ", method.Name);
+        writer.Write("{\n");
+        foreach(Node node in Nodes) {
+            BasicBlock bb = (BasicBlock)node;
+            writer.Write("    \"{0}\" [ label = \"{1}\" ];\n", bb, bb);
+        }
+
+        foreach(Edge edge in Edges) {
+            CFGEdge ce = (CFGEdge)edge;
+            writer.Write("    \"{0}\" -> \"{1}\"", ce.Start, ce.End);
+            if(ce.Type == CFGEdgeType.Branch) {
+                writer.Write(" [ label = \"branch\" ];\n");
+            } else if(ce.Type == CFGEdgeType.Forward) {
+                writer.Write(" [ label = \"forward\" ];\n");
+            } else if(ce.Type == CFGEdgeType.Return) {
+                writer.Write(" [ label = \"return\" ];\n");
+            } else if(ce.Type == CFGEdgeType.Exception) {
+                writer.Write(" [ label = \"exception\" ];\n");
+            } else {
+                writer.Write(" [ label = \"unknown\" ];\n");
+            }
+        }
+        writer.Write("}\n");
+        writer.Close();
+    }
+}
+
+}
Index: rules/Gendarme.Rules.Correctness/dataflow/Dataflow.cs
===================================================================
--- rules/Gendarme.Rules.Correctness/dataflow/Dataflow.cs	(revision 0)
+++ rules/Gendarme.Rules.Correctness/dataflow/Dataflow.cs	(revision 0)
@@ -0,0 +1,90 @@
+/*
+ * Dataflow.cs: a generic dataflow analysis algorithm
+ *
+ * Authors:
+ *   Aaron Tomb <atomb at soe.ucsc.edu>
+ *
+ * Copyright (c) 2005 Aaron Tomb and the contributors listed
+ * in the ChangeLog.
+ *
+ * This is free software, distributed under the MIT/X11 license.
+ * See the included LICENSE.MIT file for details.
+ **********************************************************************/
+
+using System;
+using System.Collections;
+
+namespace Gendarme.Rules.Correctness {
+
+public class Dataflow {
+
+    [NonNull] private CFG cfg;
+    [NonNull] private IDictionary inFact;
+    [NonNull] private IDictionary outFact;
+    [NonNull] private IDataflowAnalysis analysis;
+
+    public Dataflow([NonNull] CFG cfg, [NonNull] IDataflowAnalysis analysis)
+    {
+        this.cfg = cfg;
+        this.analysis = analysis;
+        this.inFact = new Hashtable();
+        this.outFact = new Hashtable();
+    }
+
+    /* This only does forward analysis so far. We might need to make it
+     * do backward analysis at some point. */
+    public void Compute()
+    {
+        /* Initialize nodes */
+        foreach(Node node in cfg.Nodes) {
+            outFact[node] = analysis.NewTop();
+            if(cfg.BeginsCatch((BasicBlock)node)) {
+                /* Catch nodes start with one thing on the stack. */
+                inFact[node] = analysis.NewCatch();
+            } else if(cfg.Predecessors(node).Count > 0) {
+                inFact[node] = analysis.NewTop();
+            } else {
+                inFact[node] = analysis.NewEntry();
+            }
+        }
+        DFS dfs = new DFS(cfg, cfg.EntryPoint);
+        dfs.Traverse();
+
+        /* Calculate the fixpoint of the dataflow equations. */
+        bool changed;
+        int iteration = 0;
+        do {
+            iteration++;
+            changed = false;
+            foreach(object o in dfs.OrderedNodes) {
+                Node node = (Node)o;
+                foreach(object pred in cfg.Predecessors(node))
+                    analysis.MeetInto(inFact[node], outFact[pred], false);
+
+                object temp = ((ICloneable)inFact[node]).Clone();
+                analysis.Transfer(node, inFact[node], temp, false);
+                if(!temp.Equals(outFact[node])) {
+                    changed = true;
+                    /* No need to assign new out fact unless changed. */
+                    outFact[node] = temp;
+                }
+
+            }
+        } while(changed);
+
+        /* Run one final iteration with checking enabled. This is where
+         * warnings will be presented. Because nothing changed in the
+         * last iteration, nothing should change during this one. The
+         * loop iterates over the nodes in CFG order, rather than DFS
+         * order, so that messages will be sorted by location. */
+        foreach(object o in cfg.Nodes) {
+            Node node = (Node)o;
+            foreach(object pred in cfg.Predecessors(node))
+                analysis.MeetInto(inFact[node], outFact[pred], true);
+            object temp = ((ICloneable)inFact[node]).Clone();
+            analysis.Transfer(node, inFact[node], temp, true);
+        }
+    }
+}
+
+}
Index: rules/Gendarme.Rules.Correctness/dataflow/CFGEdge.cs
===================================================================
--- rules/Gendarme.Rules.Correctness/dataflow/CFGEdge.cs	(revision 0)
+++ rules/Gendarme.Rules.Correctness/dataflow/CFGEdge.cs	(revision 0)
@@ -0,0 +1,40 @@
+/*
+ * CFGEdge.cs: edges with extra flow information for use in control flow
+ * graphs.
+ *
+ * Authors:
+ *   Aaron Tomb <atomb at soe.ucsc.edu>
+ *
+ * Copyright (c) 2005 Aaron Tomb and the contributors listed
+ * in the ChangeLog.
+ *
+ * This is free software, distributed under the MIT/X11 license.
+ * See the included LICENSE.MIT file for details.
+ **********************************************************************/
+
+namespace Gendarme.Rules.Correctness {
+
+public class CFGEdge : Edge {
+    private CFGEdgeType type;
+
+    public CFGEdgeType Type {
+        get { return type; }
+    }
+
+    public CFGEdge([NonNull] BasicBlock start, [NonNull] BasicBlock end,
+            CFGEdgeType type)
+    {
+        this.start = start;
+        this.end = end;
+        this.type = type;
+    }
+}
+
+public enum CFGEdgeType {
+    Forward,
+    Branch,
+    Exception,
+    Return
+}
+
+}
Index: rules/Gendarme.Rules.Correctness/BadRecursiveInvocationRule.cs
===================================================================
--- rules/Gendarme.Rules.Correctness/BadRecursiveInvocationRule.cs	(revision 54948)
+++ rules/Gendarme.Rules.Correctness/BadRecursiveInvocationRule.cs	(working copy)
@@ -1,6 +1,6 @@
 /*
- * BadRecChecker.cs: looks for instances of problematic recursive
- * invocations.
+ * BadRecursiveInvocationRule.cs: looks for instances of problematic
+ * recursive invocations.
  *
  * Authors:
  *   Aaron Tomb <atomb at soe.ucsc.edu>
@@ -13,17 +13,21 @@
  **********************************************************************/
 
 using System;
+using System.Collections;
 using Mono.Cecil;
 using Mono.Cecil.Cil;
 using Gendarme.Framework;
 
+namespace Gendarme.Rules.Correctness {
+
 public class BadRecursiveInvocationRule : IMethodRule {
 
-    public bool CheckMethod (IAssemblyDefinition assembly, IModuleDefinition module,
-            ITypeDefinition type, IMethodDefinition method)
+    public IList CheckMethod (IAssemblyDefinition assembly,
+            IModuleDefinition module, ITypeDefinition type,
+            IMethodDefinition method, Runner runner)
     {
         if(method.Body == null)
-            return true;
+            return runner.RuleSuccess;
 
         IInstructionCollection instructions = method.Body.Instructions;
 
@@ -56,21 +60,19 @@
                 }
                 if(rName.Equals(mName) && rDecl.Equals(mDecl) && argsEqual) {
                     if(LoadsVerbatimArgs(method, i)) {
-                        return false;
-                        /* TODO: restore the ability to generate
-                         * messages. */
-                        /*
+                        IList messages = new ArrayList();
                         string etype = method.DeclaringType.FullName;
                         Location loc = new Location(etype, method.Name,
                                 insn.Offset);
-                        report.AddMessage(new Message("suspicious recursive call",
-                                    loc, MessageType.Warning));
-                                    */
+                        Message msg = new Message("suspicious recursive call",
+                                    loc, MessageType.Warning);
+                        messages.Add(msg);
+                        return messages;
                     }
                 }
             }
         }
-        return true;
+        return runner.RuleSuccess;
     }
 
     private bool LoadsVerbatimArgs([NonNull] IMethodDefinition method,
@@ -105,3 +107,5 @@
         return false;
     }
 }
+
+}
Index: rules/Gendarme.Rules.Correctness/NonNullAttributeCollector.cs
===================================================================
--- rules/Gendarme.Rules.Correctness/NonNullAttributeCollector.cs	(revision 0)
+++ rules/Gendarme.Rules.Correctness/NonNullAttributeCollector.cs	(revision 0)
@@ -0,0 +1,106 @@
+/*
+ * NonNullAttributeCollector.cs: collects and caches non-null attributes.
+ *
+ * Authors:
+ *   Aaron Tomb <atomb at soe.ucsc.edu>
+ *
+ * Copyright (c) 2005 Aaron Tomb and the contributors listed
+ * in the ChangeLog.
+ *
+ * This is free software, distributed under the MIT/X11 license.
+ * See the included LICENSE.MIT file for details.
+ **********************************************************************/
+
+using System;
+using System.Collections;
+using System.IO;
+using Mono.Cecil;
+
+namespace Gendarme.Rules.Correctness {
+
+public class NonNullAttributeCollector {
+    [NonNull] private Hashtable nonNullMethods;
+    [NonNull] private Hashtable nonNullFields;
+    [NonNull] private Hashtable nonNullParams;
+
+    public NonNullAttributeCollector()
+    {
+        this.nonNullMethods = new Hashtable();
+        this.nonNullFields = new Hashtable();
+        this.nonNullParams = new Hashtable();
+
+    }
+
+    public void AddAssembly([NonNull] IAssemblyDefinition assembly)
+    {
+        foreach(IModuleDefinition module in assembly.Modules) {
+            foreach(ITypeDefinition type in module.Types) {
+                foreach(IMethodDefinition method in type.Methods) {
+                    if(DefHasNonNullAttribute(method)) {
+                        nonNullMethods.Add(method.ToString(), method);
+                    }
+                    foreach(IParameterDefinition param in method.Parameters) {
+                        if(DefHasNonNullAttribute(param)) {
+                            nonNullParams.Add(method.ToString() + "/"
+                                    + param.Sequence, param);
+                        }
+                    }
+                }
+                foreach(IFieldDefinition field in type.Fields) {
+                    if(DefHasNonNullAttribute(field)) {
+                        nonNullFields.Add(field.ToString(), field);
+                    }
+                }
+            }
+        }
+    }
+
+    public void AddList(string fileName)
+    {
+        StreamReader r = new StreamReader(fileName);
+        string line;
+        for(line = r.ReadLine(); line != null; line = r.ReadLine()) {
+            if(line.IndexOf("/") != -1) {
+                nonNullParams.Add(line, null);
+            } else if(line.IndexOf("(") != -1) {
+                nonNullMethods.Add(line, null);
+            } else {
+                nonNullFields.Add(line, null);
+            }
+        }
+    }
+
+    public bool HasNonNullAttribute([NonNull] IMethodSignature msig)
+    {
+        if(nonNullMethods.Contains(msig.ToString()))
+            return true;
+        return false;
+    }
+
+    public bool HasNonNullAttribute([NonNull] IMethodSignature msig,
+            [NonNull] IParameterReference param)
+    {
+        if(nonNullParams.Contains(msig.ToString() + "/" + param.Sequence))
+            return true;
+        return false;
+    }
+
+    public bool HasNonNullAttribute([NonNull] IFieldReference field)
+    {
+        if(nonNullFields.Contains(field.ToString()))
+            return true;
+        return false;
+    }
+
+    private bool DefHasNonNullAttribute(
+            [NonNull] ICustomAttributeProvider provider)
+    {
+        string ctorName = "System.Void NonNullAttribute::.ctor()";
+        foreach(ICustomAttribute attrib in provider.CustomAttributes)
+            if(attrib.Constructor.ToString().Equals(ctorName))
+                return true;
+        return false;
+    }
+}
+
+}
Index: rules/Gendarme.Rules.Correctness/Nullity.cs
===================================================================
--- rules/Gendarme.Rules.Correctness/Nullity.cs	(revision 0)
+++ rules/Gendarme.Rules.Correctness/Nullity.cs	(revision 0)
@@ -0,0 +1,24 @@
+/*
+ * Nullity.cs: the possibilities for the known state of a particular
+ * object.
+ *
+ * Authors:
+ *   Aaron Tomb <atomb at soe.ucsc.edu>
+ *
+ * Copyright (c) 2005 Aaron Tomb and the contributors listed
+ * in the ChangeLog.
+ *
+ * This is free software, distributed under the MIT/X11 license.
+ * See the included LICENSE.MIT file for details.
+ **********************************************************************/
+
+namespace Gendarme.Rules.Correctness {
+
+public enum Nullity : int {
+    Unused  = 0,
+    Null    = 1,
+    NonNull = 2,
+    Unknown = 3,
+}
+
+}
Index: rules/Gendarme.Rules.Correctness/Gendarme.Rules.Correctness.xml.in
===================================================================
--- rules/Gendarme.Rules.Correctness/Gendarme.Rules.Correctness.xml.in	(revision 54948)
+++ rules/Gendarme.Rules.Correctness/Gendarme.Rules.Correctness.xml.in	(working copy)
@@ -2,7 +2,13 @@
 	<rule	Name="BadRecursiveInvocationRule" 
 		Type="Gendarme.Rules.Correctness.BadRecursiveInvocationRule, Gendarme.Rules.Correctness, Version=@VERSION@, Culture=neutral, PublicKeyToken=null"
 		Uri="http://www.mono-project.com/Gendarme" >
-                <problem>Method or property '{0}' invokes itself recursively in a suspcious way.</problem>
+		<problem>Method or property '{0}' invokes itself recursively in a suspcious way.</problem>
 		<solution>Ensure that the parameters to the vary in such a way that the recursion will terminate.</solution>
 	</rule>
+	<rule	Name="NullDerefRule"
+		Type="Gendarme.Rules.Correctness.NullDerefRule, Gendarme.Rules.Correctness, Version=@VERSION@, Culture=neutral, PublicKeyToken=null"
+		Uri="http://www.mono-project.com/Gendarme" >
+		<problem>Method or property '{0}' might dereference a null pointer, or cause other code to do so.</problem>
+		<solution>Examine the detailed listing of problem locations, and ensure that the variables in question cannot be null.</solution>
+	</rule>
 </rules>
Index: rules/Gendarme.Rules.Correctness/NullDerefAnalysis.cs
===================================================================
--- rules/Gendarme.Rules.Correctness/NullDerefAnalysis.cs	(revision 0)
+++ rules/Gendarme.Rules.Correctness/NullDerefAnalysis.cs	(revision 0)
@@ -0,0 +1,852 @@
+/*
+ * NullDerefAnalysis.cs: dataflow analysis details for null-pointer
+ * dereference detection.
+ *
+ * Authors:
+ *   Aaron Tomb <atomb at soe.ucsc.edu>
+ *
+ * Copyright (c) 2005 Aaron Tomb and the contributors listed
+ * in the ChangeLog.
+ *
+ * This is free software, distributed under the MIT/X11 license.
+ * See the included LICENSE.MIT file for details.
+ **********************************************************************/
+
+using System;
+using System.Collections;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Gendarme.Framework;
+
+namespace Gendarme.Rules.Correctness {
+
+public class NullDerefAnalysis : OpCodeConstants, IDataflowAnalysis {
+
+    int stackDepth;
+    int locals;
+    int args;
+    [NonNull] private IMethodDefinition method;
+    [NonNull] private NonNullAttributeCollector nnaCollector;
+    [NonNull] private IList messages;
+    [NonNull] private Runner runner;
+
+    public NullDerefAnalysis([NonNull] IMethodDefinition method,
+            [NonNull] IList messages,
+            [NonNull] NonNullAttributeCollector nnaCollector,
+            [NonNull] Runner runner)
+    {
+        this.stackDepth = method.Body.MaxStack;
+        this.locals = method.Body.Variables.Count;
+        if(method.HasThis)
+            this.args = method.Parameters.Count + 1;
+        else
+            this.args = method.Parameters.Count;
+        this.method = method;
+        this.messages = messages;
+        this.nnaCollector = nnaCollector;
+        this.runner = runner;
+    }
+    
+    [NonNull]
+    public object NewTop()
+    {
+        return new NullDerefFrame(stackDepth, locals, args, false);
+    }
+
+    [NonNull]
+    public object NewEntry()
+    {
+        NullDerefFrame result =
+            new NullDerefFrame(stackDepth, locals, args, true);
+        if(method.HasThis)
+            result.SetArgNullity(0, Nullity.NonNull);
+        foreach(IParameterReference param in method.Parameters)
+            if(nnaCollector.HasNonNullAttribute(method, param))
+                result.SetArgNullity(param.Sequence, Nullity.NonNull);
+        return result;
+    }
+
+    [NonNull]
+    public object NewCatch()
+    {
+        NullDerefFrame result =
+            new NullDerefFrame(stackDepth, locals, args, true);
+        if(method.HasThis)
+            result.SetArgNullity(0, Nullity.NonNull);
+        foreach(IParameterReference param in method.Parameters)
+            if(nnaCollector.HasNonNullAttribute(method, param))
+                result.SetArgNullity(param.Sequence, Nullity.NonNull);
+        /* The exception being caught is pushed onto the stack. */
+        result.PushStack(Nullity.NonNull);
+        return result;
+    }
+
+    /* Changes originalFact. */
+    public void MeetInto([NonNull] object originalFact,
+            [NonNull] object newFact, bool warn)
+    {
+        NullDerefFrame original = (NullDerefFrame)originalFact;
+        NullDerefFrame incoming = (NullDerefFrame)newFact;
+        original.MergeWith(incoming);
+    }
+
+    private bool IsVoid([NonNull] ITypeReference type)
+    {
+        if(type.FullName.Equals("System.Void"))
+            return true;
+        return false;
+    }
+
+    public void Transfer([NonNull] Node node, [NonNull] object inFact,
+            [NonNull] object outFact, bool warn)
+    {
+        BasicBlock bb = (BasicBlock)node;
+
+        /* Exit and exception nodes don't cover any real instructions. */
+        if(bb.isExit || bb.isException)
+            return;
+
+        //NullDerefFrame inFrame = (NullDerefFrame)inFact;
+        NullDerefFrame outFrame = (NullDerefFrame)outFact;
+        IVariableDefinitionCollection vars = method.Body.Variables;
+
+        if(runner.Debug) {
+            Console.WriteLine("Basic block {0}", bb.ToString());
+            Console.WriteLine("Input frame:");
+            Console.Write(outFrame.ToString());
+        }
+        
+        for(int i = bb.first; i <= bb.last; i++) {
+            IInstruction insn = bb.Instructions[i];
+            OpCode opcode = insn.OpCode;
+
+            if(runner.Debug) {
+                Console.Write("{0}", opcode.Name);
+                if(insn.Operand != null && !(insn.Operand is IInstruction)) {
+                    Console.WriteLine(" {0}", insn.Operand.ToString());
+                } else if(insn.Operand is IInstruction) {
+                    Console.WriteLine(" {0}",
+                            ((IInstruction)insn.Operand).Offset.ToString("X4"));
+                } else {
+                    Console.WriteLine();
+                }
+            }
+
+            switch((int)((ushort)opcode.Value)) {
+                /* Load argument */
+                /* Stored nullities are set to declared values on method
+                 * entry. Starg and kin can change this over time. */
+                case Ldarg_0:
+                    outFrame.PushStack(outFrame.GetArgNullity(0));
+                    break;
+                case Ldarg_1:
+                    outFrame.PushStack(outFrame.GetArgNullity(1));
+                    break;
+                case Ldarg_2:
+                    outFrame.PushStack(outFrame.GetArgNullity(2));
+                    break;
+                case Ldarg_3:
+                    outFrame.PushStack(outFrame.GetArgNullity(3));
+                    break;
+                case Ldarg:
+                    outFrame.PushStack(
+                            outFrame.GetArgNullity((int)insn.Operand));
+                    break;
+                case Ldarg_S: {
+                    IParameterReference param =
+                        (IParameterReference)insn.Operand;
+                    outFrame.PushStack(outFrame.GetArgNullity(param.Sequence));
+                    break;
+                }
+                case Ldarga:
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldarga_S:
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+
+                /* Store argument */
+                case Starg:
+                    outFrame.SetArgNullity((int)insn.Operand,
+                            outFrame.PopStack());
+                    break;
+                case Starg_S: {
+                    IParameterReference param =
+                        (IParameterReference)insn.Operand;
+                    outFrame.SetArgNullity(param.Sequence, 
+                            outFrame.PopStack());
+                    break;
+                }
+
+                /* Load local */
+                case Ldloc_0:
+                    outFrame.PushStack(outFrame.GetLocNullity(0));
+                    break;
+                case Ldloc_1:
+                    outFrame.PushStack(outFrame.GetLocNullity(1));
+                    break;
+                case Ldloc_2:
+                    outFrame.PushStack(outFrame.GetLocNullity(2));
+                    break;
+                case Ldloc_3:
+                    outFrame.PushStack(outFrame.GetLocNullity(3));
+                    break;
+                case Ldloc:
+                    outFrame.PushStack(outFrame.GetLocNullity(
+                        vars.IndexOf((VariableDefinition)insn.Operand)));
+                    break;
+                case Ldloc_S:
+                    outFrame.PushStack(outFrame.GetLocNullity(
+                        vars.IndexOf((VariableDefinition)insn.Operand)));
+                    break;
+                case Ldloca:
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldloca_S:
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+
+                /* Store local */
+                case Stloc_0:
+                    outFrame.SetLocNullity(0, outFrame.PopStack());
+                    break;
+                case Stloc_1:
+                    outFrame.SetLocNullity(1, outFrame.PopStack());
+                    break;
+                case Stloc_2:
+                    outFrame.SetLocNullity(2, outFrame.PopStack());
+                    break;
+                case Stloc_3:
+                    outFrame.SetLocNullity(3, outFrame.PopStack());
+                    break;
+                case Stloc:
+                    outFrame.SetLocNullity(
+                        vars.IndexOf((VariableDefinition)insn.Operand),
+                        outFrame.PopStack());
+                    break;
+                case Stloc_S:
+                    outFrame.SetLocNullity(
+                        vars.IndexOf((VariableDefinition)insn.Operand),
+                        outFrame.PopStack());
+                    break;
+
+                /* Load other things */
+                case Ldftn:
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldvirtftn:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldstr:
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldnull:
+                    outFrame.PushStack(Nullity.Null);
+                    break;
+                case Ldlen:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldtoken:
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+
+                 /* Object operations */
+                case Cpobj: outFrame.PopStack(2); break;
+                case Newobj:
+                    outFrame.PopStack(
+                        ((IMethodReference)insn.Operand).Parameters.Count);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldobj:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Stobj: outFrame.PopStack(2); break;
+                case Initobj: outFrame.PopStack(); break;
+
+                 /* Load field */
+                case Ldfld: {
+                    Check(insn, warn, outFrame.PopStack(), "field");
+                    IFieldReference field = (IFieldReference)insn.Operand;
+                    if(nnaCollector.HasNonNullAttribute(field))
+                        outFrame.PushStack(Nullity.NonNull);
+                    else
+                        outFrame.PushStack(Nullity.Unknown);
+                    break;
+                }
+                case Ldflda:
+                    Check(insn, warn, outFrame.PopStack(), "field");
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldsfld: {
+                    IFieldReference field = (IFieldReference)insn.Operand;
+                    if(nnaCollector.HasNonNullAttribute(field))
+                        outFrame.PushStack(Nullity.NonNull);
+                    else
+                        outFrame.PushStack(Nullity.Unknown);
+                    break;
+                }
+                case Ldsflda: outFrame.PushStack(Nullity.NonNull); break;
+
+                /* Store field */
+                case Stfld: {
+                    /* FIXME: warn if writing null to non-null field */
+                    Nullity n = outFrame.PopStack();
+                    Check(insn, warn, outFrame.PopStack(), "field");
+                    IFieldReference field = (IFieldReference)insn.Operand;
+                    if(warn && nnaCollector.HasNonNullAttribute(field)) {
+                        string etype = method.DeclaringType.FullName;
+                        Location loc = new Location(etype,
+                                method.Name, insn.Offset);
+                        if(n == Nullity.Unknown)
+                            messages.Add(new Message(
+                                        "storing possibly null value in " +
+                                        "field declared non-null",
+                                        loc, MessageType.Warning));
+                        else if(n == Nullity.Null)
+                            messages.Add(new Message(
+                                        "storing null value in " +
+                                        "field declared non-null",
+                                        loc, MessageType.Warning));
+                    }
+                    break;
+                }
+                case Stsfld: {
+                    Nullity n = outFrame.PopStack();
+                    IFieldReference field = (IFieldReference)insn.Operand;
+                    if(warn && nnaCollector.HasNonNullAttribute(field)) {
+                        string etype = method.DeclaringType.FullName;
+                        Location loc = new Location(etype,
+                                method.Name, insn.Offset);
+                        if(n == Nullity.Unknown)
+                            messages.Add(new Message(
+                                        "storing possibly null value in " +
+                                        "field declared non-null",
+                                        loc, MessageType.Warning));
+                        else if(n == Nullity.Null)
+                            messages.Add(new Message(
+                                        "storing null value in " +
+                                        "field declared non-null",
+                                        loc, MessageType.Warning));
+                    }
+                    break;
+                }
+
+                /* Stack operations */
+                case Dup: outFrame.PushStack(outFrame.PeekStack()); break;
+                case Pop: outFrame.PopStack(); break;
+
+                 /* Method call and return */
+                case Call:
+                    ProcessCall(insn, warn, false, outFrame);
+                    break;
+                case Calli:
+                    ProcessCall(insn, warn, true, outFrame);
+                    break;
+                case Callvirt:
+                    ProcessCall(insn, warn, false, outFrame);
+                    break;
+                case Ret:
+                    if(!IsVoid(method.ReturnType.ReturnType)) {
+                        Nullity n = outFrame.PopStack();
+                        if(nnaCollector.HasNonNullAttribute(method) && warn) {
+                            string etype = method.DeclaringType.FullName;
+                            Location loc = new Location(etype,
+                                    method.Name, insn.Offset);
+                            if(n == Nullity.Null)
+                                messages.Add(new Message(
+                                            "returning null value from " +
+                                            "method declared non-null",
+                                            loc, MessageType.Warning));
+                            else if(n == Nullity.Unknown)
+                                messages.Add(new Message(
+                                            "returning possibly null value " +
+                                            "from method declared non-null",
+                                            loc, MessageType.Warning));
+                        }
+                    }
+                    break;
+
+                /* Indirect load */
+                case Ldind_I1:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldind_U1:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldind_I2:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldind_U2:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldind_I4:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldind_U4:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldind_I8:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldind_I:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldind_R4:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldind_R8:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldind_Ref:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.Unknown);
+                    break;
+
+                /* Indirect store */
+                case Stind_Ref: outFrame.PopStack(2); break;
+                case Stind_I: outFrame.PopStack(2); break;
+                case Stind_I1: outFrame.PopStack(2); break;
+                case Stind_I2: outFrame.PopStack(2); break;
+                case Stind_I4: outFrame.PopStack(2); break;
+                case Stind_I8: outFrame.PopStack(2); break;
+                case Stind_R4: outFrame.PopStack(2); break;
+                case Stind_R8: outFrame.PopStack(2); break;
+
+                /* Class-related operations */
+                case Box:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Unbox:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Unbox_Any:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Castclass: break;
+                case Isinst: break;
+
+                /* Exception handling */
+                case Throw: outFrame.EmptyStack(); break;
+                case Rethrow: break;
+                case Leave: outFrame.EmptyStack(); break;
+                case Leave_S: outFrame.EmptyStack(); break;
+                case Endfinally: outFrame.EmptyStack(); break;
+                case Endfilter: outFrame.PopStack(); break;
+
+                /* Array operations */
+                case Newarr:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                /* Load element */
+                case Ldelema:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldelem_I1:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldelem_U1:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldelem_I2:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldelem_U2:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldelem_I4:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldelem_U4:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldelem_I8:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldelem_I:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldelem_R4:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldelem_R8:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Ldelem_Ref:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.Unknown);
+                    break;
+                case Ldelem_Any: /* This may or may not be a reference. */
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.Unknown);
+                    break;
+                /* Store element */
+                /* Pop 3 */
+                case Stelem_I: outFrame.PopStack(3); break;
+                case Stelem_I1: outFrame.PopStack(3); break;
+                case Stelem_I2: outFrame.PopStack(3); break;
+                case Stelem_I4: outFrame.PopStack(3); break;
+                case Stelem_I8: outFrame.PopStack(3); break;
+                case Stelem_R4: outFrame.PopStack(3); break;
+                case Stelem_R8: outFrame.PopStack(3); break;
+                case Stelem_Ref: outFrame.PopStack(3); break;
+                case Stelem_Any: outFrame.PopStack(3); break;
+
+                case Mkrefany:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Arglist:
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Sizeof:
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Refanyval:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Refanytype:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+
+                /* Prefixes */
+                case Unaligned: break;
+                case Volatile: break;
+                case Tail: break;
+
+                /* Effect-free instructions */
+                case Nop: break;
+                case Break: break;
+
+                /* Load constant */
+                /* Push non-ref. */
+                case Ldc_I4_M1: outFrame.PushStack(Nullity.NonNull); break;
+                case Ldc_I4_0: outFrame.PushStack(Nullity.NonNull); break;
+                case Ldc_I4_1: outFrame.PushStack(Nullity.NonNull); break;
+                case Ldc_I4_2: outFrame.PushStack(Nullity.NonNull); break;
+                case Ldc_I4_3: outFrame.PushStack(Nullity.NonNull); break;
+                case Ldc_I4_4: outFrame.PushStack(Nullity.NonNull); break;
+                case Ldc_I4_5: outFrame.PushStack(Nullity.NonNull); break;
+                case Ldc_I4_6: outFrame.PushStack(Nullity.NonNull); break;
+                case Ldc_I4_7: outFrame.PushStack(Nullity.NonNull); break;
+                case Ldc_I4_8: outFrame.PushStack(Nullity.NonNull); break;
+                case Ldc_I4_S: outFrame.PushStack(Nullity.NonNull); break;
+                case Ldc_I4: outFrame.PushStack(Nullity.NonNull); break;
+                case Ldc_I8: outFrame.PushStack(Nullity.NonNull); break;
+                case Ldc_R4: outFrame.PushStack(Nullity.NonNull); break;
+                case Ldc_R8: outFrame.PushStack(Nullity.NonNull); break;
+
+                /* Unconditional control flow */
+                /* Do nothing */
+                case Br: break;
+                case Br_S: break;
+
+                /* Conditional branches */
+                /* Pop 1 */
+                case Brfalse: outFrame.PopStack(); break;
+                case Brtrue: outFrame.PopStack(); break;
+                case Brfalse_S: outFrame.PopStack(); break;
+                case Brtrue_S: outFrame.PopStack(); break;
+
+                /* Comparison branches */
+                /* Pop 2. */
+                case Beq: outFrame.PopStack(2); break;
+                case Bge: outFrame.PopStack(2); break;
+                case Bgt: outFrame.PopStack(2); break;
+                case Ble: outFrame.PopStack(2); break;
+                case Blt: outFrame.PopStack(2); break;
+                case Bne_Un: outFrame.PopStack(2); break;
+                case Bge_Un: outFrame.PopStack(2); break;
+                case Bgt_Un: outFrame.PopStack(2); break;
+                case Ble_Un: outFrame.PopStack(2); break;
+                case Blt_Un: outFrame.PopStack(2); break;
+                case Beq_S: outFrame.PopStack(2); break;
+                case Bge_S: outFrame.PopStack(2); break;
+                case Bgt_S: outFrame.PopStack(2); break;
+                case Ble_S: outFrame.PopStack(2); break;
+                case Blt_S: outFrame.PopStack(2); break;
+                case Bne_Un_S: outFrame.PopStack(2); break;
+                case Bge_Un_S: outFrame.PopStack(2); break;
+                case Bgt_Un_S: outFrame.PopStack(2); break;
+                case Ble_Un_S: outFrame.PopStack(2); break;
+                case Blt_Un_S: outFrame.PopStack(2); break;
+
+                case Switch: outFrame.PopStack(); break;
+
+                /* Comparisons */
+                /* Pop 2, push non-ref */
+                case Ceq:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Cgt:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Cgt_Un:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Clt:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Clt_Un:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+
+                /* Arithmetic and logical binary operators */
+                /* Pop 2, push non-ref */
+                case Add:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Sub:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Mul:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Div:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Div_Un:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Rem:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Rem_Un:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case And:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Or:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Xor:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Shl:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Shr:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Shr_Un:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Add_Ovf:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Add_Ovf_Un:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Mul_Ovf:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Mul_Ovf_Un:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Sub_Ovf:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Sub_Ovf_Un:
+                    outFrame.PopStack(2);
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+
+                /* Arithmetic and logical unary operators */
+                /* Pop 1, push non-ref */
+                case Neg:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+                case Not:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+
+                /* Conversions. */
+                /* Do nothing. */
+                case Conv_I1: break;
+                case Conv_I2: break;
+                case Conv_I4: break;
+                case Conv_I8: break;
+                case Conv_R4: break;
+                case Conv_R8: break;
+                case Conv_U4: break;
+                case Conv_U8: break;
+                case Conv_U: break;
+                case Conv_R_Un: break;
+                case Conv_Ovf_I1_Un: break;
+                case Conv_Ovf_I2_Un: break;
+                case Conv_Ovf_I4_Un: break;
+                case Conv_Ovf_I8_Un: break;
+                case Conv_Ovf_U1_Un: break;
+                case Conv_Ovf_U2_Un: break;
+                case Conv_Ovf_U4_Un: break;
+                case Conv_Ovf_U8_Un: break;
+                case Conv_Ovf_I_Un: break;
+                case Conv_Ovf_U_Un: break;
+                case Conv_Ovf_I1: break;
+                case Conv_Ovf_U1: break;
+                case Conv_Ovf_I2: break;
+                case Conv_Ovf_U2: break;
+                case Conv_Ovf_I4: break;
+                case Conv_Ovf_U4: break;
+                case Conv_Ovf_I8: break;
+                case Conv_Ovf_U8: break;
+                case Conv_U2: break;
+                case Conv_U1: break;
+                case Conv_I: break;
+                case Conv_Ovf_I: break;
+                case Conv_Ovf_U: break;
+
+                case Ckfinite: break;
+
+                /* Unverifiable instructions. */
+                case Jmp: break;
+                case Cpblk: outFrame.PopStack(3); break;
+                case Initblk: outFrame.PopStack(3); break;
+                case Localloc:
+                    outFrame.PopStack();
+                    outFrame.PushStack(Nullity.NonNull);
+                    break;
+
+                default:
+                    Console.WriteLine("Unknown instruction: {0} {1}",
+                            opcode.Name, opcode.Value.ToString("X4"));
+                    break;
+            } /* switch */
+        } /* for */
+
+        if(runner.Debug) {
+            Console.WriteLine("Output frame:");
+            Console.Write(outFrame.ToString());
+        }
+    } /* Transfer */
+
+    private void Check([NonNull]IInstruction insn, bool warn, Nullity n,
+            [NonNull] string type)
+    {
+        if(!warn) return;
+
+        string etype = method.DeclaringType.FullName;
+        Location loc = new Location(etype, method.Name, insn.Offset);
+        string name = insn.Operand.ToString();
+        int nameOffset = name.LastIndexOf("::");
+        if(nameOffset != -1)
+            name = name.Substring(nameOffset + 2);
+        if(type.Equals("method")) {
+            string prefix = name.Substring(0, 4);
+            if(prefix.Equals("get_") || prefix.Equals("set_")) {
+                name = name.Substring(4);
+                type = "property";
+            }
+        }
+        if(n == Nullity.Unknown) {
+            messages.Add(new Message(
+                        "accessing " + type + " " + name +
+                        " from potentially null object",
+                        loc, MessageType.Warning));
+        } else if(n == Nullity.Null) {
+            messages.Add(new Message(
+                        "accessing " + type + " " + name +
+                        " from null object",
+                        loc, MessageType.Warning));
+        }
+    }
+
+    private void ProcessCall([NonNull] IInstruction insn, bool warn,
+            bool indirect, [NonNull] NullDerefFrame frame)
+    {
+        string etype = method.DeclaringType.FullName;
+        Location loc = new Location(etype, method.Name, insn.Offset);
+        IMethodSignature csig = (IMethodSignature)insn.Operand;
+        if(indirect)
+            frame.PopStack(); /* Function pointer */
+        foreach(IParameterReference param in csig.Parameters) {
+            Nullity n = frame.PopStack();
+            if(warn && nnaCollector.HasNonNullAttribute(method, param)) {
+                if(n == Nullity.Null)
+                    messages.Add(new Message(
+                                "passing null value as argument " +
+                                "declared non-null",
+                                loc, MessageType.Warning));
+                else if(n == Nullity.Unknown)
+                    messages.Add(new Message(
+                                "passing possibly null value as argument " +
+                                "declared non-null",
+                                loc, MessageType.Warning));
+            }
+        }
+        if(csig.HasThis && !Ignoring(csig)) /* Add 'this' parameter. */
+            Check(insn, warn, frame.PopStack(), "method");
+        if(!IsVoid(csig.ReturnType.ReturnType)) {
+            if(csig.ReturnType.ReturnType.IsValueType)
+                frame.PushStack(Nullity.NonNull);
+            else if(nnaCollector.HasNonNullAttribute(csig))
+                frame.PushStack(Nullity.NonNull);
+            else
+                frame.PushStack(Nullity.Unknown);
+        }
+    }
+
+    private bool Ignoring([NonNull] IMethodSignature msig)
+    {
+        /* FIXME: Ignoring is a temporary hack! */
+        /* Right now, it always returns false, as it should. */
+        return false;
+    }
+}
+
+}
Index: rules/Gendarme.Rules.Correctness/Makefile.am
===================================================================
--- rules/Gendarme.Rules.Correctness/Makefile.am	(revision 54948)
+++ rules/Gendarme.Rules.Correctness/Makefile.am	(working copy)
@@ -8,8 +8,18 @@
 
 correctness_rules_sources_in = ../../AssemblyInfo.cs.in
 correctness_rules_generated_sources = $(correctness_rules_sources_in:.in=)
-correctness_rules_sources = BadRecursiveInvocationRule.cs OpCodeConstants.cs NonNullAttribute.cs
+correctness_rules_sources = BadRecursiveInvocationRule.cs OpCodeConstants.cs \
+			    NonNullAttribute.cs NonNullAttributeCollector.cs \
+			    NullDerefAnalysis.cs NullDerefRule.cs \
+			    NullDerefFrame.cs Nullity.cs \
+			    graph/INode.cs graph/Node.cs \
+			    graph/IEdge.cs graph/Edge.cs graph/IGraph.cs \
+			    graph/Graph.cs dataflow/BasicBlock.cs \
+			    dataflow/CFG.cs dataflow/CFGEdge.cs \
+			    dataflow/Dataflow.cs graph/DFS.cs \
+			    dataflow/IDataflowAnalysis.cs
 
+
 correctness_rules_build_sources = $(addprefix $(srcdir)/, $(correctness_rules_sources))
 correctness_rules_build_sources += $(correctness_rules_generated_sources)
 
Index: rules/Gendarme.Rules.Correctness/OpCodeConstants.cs
===================================================================
--- rules/Gendarme.Rules.Correctness/OpCodeConstants.cs	(revision 54948)
+++ rules/Gendarme.Rules.Correctness/OpCodeConstants.cs	(working copy)
@@ -12,6 +12,8 @@
  * See the included LICENSE.MIT file for details.
  **********************************************************************/
 
+namespace Gendarme.Rules.Correctness {
+
 public class OpCodeConstants {
 
     /* Opcodes starting with 0x00FF */
@@ -234,3 +236,5 @@
     public const int Sizeof = 0xFE1C;
     public const int Refanytype = 0xFE1D;
 }
+
+}
Index: rules/Gendarme.Rules.Correctness/NullDerefRule.cs
===================================================================
--- rules/Gendarme.Rules.Correctness/NullDerefRule.cs	(revision 0)
+++ rules/Gendarme.Rules.Correctness/NullDerefRule.cs	(revision 0)
@@ -0,0 +1,51 @@
+/*
+ * NullDerefRule.cs: looks for potential instances of null-pointer
+ * dereferencing.
+ *
+ * Authors:
+ *   Aaron Tomb <atomb at soe.ucsc.edu>
+ *
+ * Copyright (c) 2005 Aaron Tomb and the contributors listed
+ * in the ChangeLog.
+ *
+ * This is free software, distributed under the MIT/X11 license.
+ * See the included LICENSE.MIT file for details.
+ **********************************************************************/
+
+using System;
+using System.Collections;
+using Mono.Cecil;
+using Gendarme.Framework;
+
+namespace Gendarme.Rules.Correctness {
+
+public class NullDerefRule : IMethodRule {
+
+    public IList CheckMethod(IAssemblyDefinition assembly,
+            IModuleDefinition module, ITypeDefinition type,
+            IMethodDefinition method, Runner runner)
+    {
+        if(method.Body == null)
+            return runner.RuleSuccess;
+
+        CFG cfg = new CFG(method);
+        if(runner.Debug) {
+            cfg.PrintBasicBlocks();
+            cfg.PrintDot();
+        }
+
+        IList messages = new ArrayList();
+        NonNullAttributeCollector nnaCollector =
+            new NonNullAttributeCollector();
+        IDataflowAnalysis analysis = new NullDerefAnalysis(method, messages,
+                nnaCollector, runner);
+        Dataflow dataflow = new Dataflow(cfg, analysis);
+        dataflow.Compute();
+        if(messages.Count > 0)
+            return messages;
+        else
+            return runner.RuleSuccess;
+    }
+}
+
+}
Index: rules/Gendarme.Rules.Correctness/NonNullAttribute.cs
===================================================================
--- rules/Gendarme.Rules.Correctness/NonNullAttribute.cs	(revision 54948)
+++ rules/Gendarme.Rules.Correctness/NonNullAttribute.cs	(working copy)
@@ -15,6 +15,8 @@
 
 using System;
 
+namespace Gendarme.Rules.Correctness {
+
 [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field |
         AttributeTargets.Property | AttributeTargets.Parameter)]
 public class NonNullAttribute : System.Attribute {
@@ -22,3 +24,5 @@
     {
     }
 }
+
+}
Index: rules/Gendarme.Rules.Performance/Test/EmptyDestructorTest.cs
===================================================================
--- rules/Gendarme.Rules.Performance/Test/EmptyDestructorTest.cs	(revision 54948)
+++ rules/Gendarme.Rules.Performance/Test/EmptyDestructorTest.cs	(working copy)
@@ -87,21 +87,21 @@
 		public void NoDestructor ()
 		{
 			ITypeDefinition type = GetTest ("NoDestructorClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNotNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void EmptyDestructor ()
 		{
 			ITypeDefinition type = GetTest ("EmptyDestructorClass");
-			Assert.IsFalse (rule.CheckType (assembly, module, type));
+			Assert.IsNotNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void Destructor ()
 		{
 			ITypeDefinition type = GetTest ("DestructorClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNotNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 	}
 }
Index: rules/Gendarme.Rules.Performance/Test/IDisposableWithDestructorWithoutSuppressFinalizeTest.cs
===================================================================
--- rules/Gendarme.Rules.Performance/Test/IDisposableWithDestructorWithoutSuppressFinalizeTest.cs	(revision 54948)
+++ rules/Gendarme.Rules.Performance/Test/IDisposableWithDestructorWithoutSuppressFinalizeTest.cs	(working copy)
@@ -141,56 +141,56 @@
 		public void NoDestructor ()
 		{
 			ITypeDefinition type = GetTest ("NoDestructorClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNotNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void Destructor ()
 		{
 			ITypeDefinition type = GetTest ("DestructorClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNotNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void IDisposableNoDestructorWithoutSuppressFinalize ()
 		{
 			ITypeDefinition type = GetTest ("IDisposableNoDestructorWithoutSuppressFinalizeClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNotNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void IDisposableNoDestructorWithSuppressFinalize ()
 		{
 			ITypeDefinition type = GetTest ("IDisposableNoDestructorWithSuppressFinalizeClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNotNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void IDisposableDestructorWithoutSuppressFinalize ()
 		{
 			ITypeDefinition type = GetTest ("IDisposableDestructorWithoutSuppressFinalizeClass");
-			Assert.IsFalse (rule.CheckType (assembly, module, type));
+			Assert.IsNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void IDisposableDestructorWithSuppressFinalize ()
 		{
 			ITypeDefinition type = GetTest ("IDisposableDestructorWithSuppressFinalizeClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNotNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void ExplicitIDisposableDestructorWithoutSuppressFinalize ()
 		{
 			ITypeDefinition type = GetTest ("ExplicitIDisposableDestructorWithoutSuppressFinalizeClass");
-			Assert.IsFalse (rule.CheckType (assembly, module, type));
+			Assert.IsNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 
 		[Test]
 		public void ExplicitIDisposableDestructorWithSuppressFinalize ()
 		{
 			ITypeDefinition type = GetTest ("ExplicitIDisposableDestructorWithSuppressFinalizeClass");
-			Assert.IsTrue (rule.CheckType (assembly, module, type));
+			Assert.IsNotNull (rule.CheckType (assembly, module, type, new MinimalRunner()));
 		}
 	}
 }
Index: rules/Gendarme.Rules.Performance/IDisposableWithDestructorWithoutSuppressFinalizeRule.cs
===================================================================
--- rules/Gendarme.Rules.Performance/IDisposableWithDestructorWithoutSuppressFinalizeRule.cs	(revision 54948)
+++ rules/Gendarme.Rules.Performance/IDisposableWithDestructorWithoutSuppressFinalizeRule.cs	(working copy)
@@ -27,6 +27,7 @@
 //
 
 using System;
+using System.Collections;
 
 using Mono.Cecil;
 using Mono.Cecil.Cil;
@@ -45,11 +46,12 @@
 			return (md.ReturnType.ReturnType.ToString () == "System.Void");
 		}
 
-		private bool Recurse (IMethodDefinition method, int level)
+		private IList Recurse (IMethodDefinition method, int level, Runner runner)
 		{
 			// some methods have no body (e.g. p/invokes, icalls)
-			if (method.Body == null)
-				return false;
+			if (method.Body == null) {
+				return runner.RuleFailure;
+			}
 
 			foreach (IInstruction ins in method.Body.Instructions) {
 				switch (ins.OpCode.Name) {
@@ -57,21 +59,21 @@
 				case "callvirt":
 					// are we calling GC.SuppressFinalize ?
 					if (ins.Operand.ToString () == "System.Void System.GC::SuppressFinalize(System.Object)")
-						return true;
+						return runner.RuleSuccess;
 					else if (level < 3) {
 						IMethodDefinition callee = (ins.Operand as IMethodDefinition);
 						if (callee != null) {
-							if (Recurse (callee, level + 1))
-								return true;
+							if (Recurse (callee, level + 1, runner) == null)
+								return runner.RuleSuccess;
 						}
 					}
 					break;
 				}
 			}
-			return false;
+			return runner.RuleFailure;
 		}
 
-		public bool CheckType (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type)
+		public IList CheckType (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type, Runner runner)
 		{
 			// #1 - does the type implements System.IDisposable ?
 			bool idisposable = false;
@@ -82,7 +84,7 @@
 				}
 			}
 			if (!idisposable)
-				return true;
+				return runner.RuleSuccess;
 
 			// #2 - look for the Dispose method
 			IMethodDefinition dispose = null;
@@ -95,7 +97,7 @@
 				}
 			}
 			if (dispose == null)
-				return true;
+				return runner.RuleSuccess;
 
 			// #3 - look for a destructor
 			IMethodDefinition destructor = null;
@@ -106,11 +108,11 @@
 				}
 			}
 			if (destructor == null)
-				return true;
+				return runner.RuleSuccess;
 
 			// #4 - look if GC.SuppressFinalize is being called in the 
 			// Dispose method - or one of the method it calls
-			return Recurse (dispose, 0);
+			return Recurse (dispose, 0, runner);
 		}
 	}
 }
Index: rules/Gendarme.Rules.Performance/EmptyDestructorRule.cs
===================================================================
--- rules/Gendarme.Rules.Performance/EmptyDestructorRule.cs	(revision 54948)
+++ rules/Gendarme.Rules.Performance/EmptyDestructorRule.cs	(working copy)
@@ -27,6 +27,7 @@
 //
 
 using System;
+using System.Collections;
 
 using Mono.Cecil;
 using Mono.Cecil.Cil;
@@ -36,7 +37,7 @@
 
 	public class EmptyDestructorRule : ITypeRule {
 
-		public bool CheckType (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type)
+		public IList CheckType (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type, Runner runner)
 		{
 			IMethodDefinition destructor = null;
 			// #1 - look for a destructor
@@ -47,7 +48,7 @@
 				}
 			}
 			if (destructor == null)
-				return true;
+				return null;
 
 			// #2 - destructor is present, look if it has any code within it
 			// i.e. look if is does anything else than calling it's base class
@@ -57,7 +58,7 @@
 					// it's empty if we're calling the base class destructor
 					IMethodReference mr = (ins.Operand as IMethodReference);
 					if ((mr == null) || (mr.Name != "Finalize"))
-						return true;
+						return null;
 					break;
 				case "nop":
 				case "leave.s":
@@ -68,11 +69,11 @@
 					break;
 				default:
 					// destructor isn't empty (normal)
-					return true;
+					return null;
 				}
 			}
 			// destructor is empty (bad / useless)
-			return false;
+			return new ArrayList();
 		}
 	}
 }
Index: framework/IRule.cs
===================================================================
--- framework/IRule.cs	(revision 54948)
+++ framework/IRule.cs	(working copy)
@@ -27,6 +27,7 @@
 //
 
 using System;
+using System.Collections;
 using Mono.Cecil;
 
 namespace Gendarme.Framework {
@@ -35,18 +36,18 @@
 	}
 
 	public interface IAssemblyRule : IRule {
-		bool CheckAssembly (IAssemblyDefinition assembly);
+		IList CheckAssembly (IAssemblyDefinition assembly, Runner runner);
 	}
 
 	public interface IModuleRule : IRule {
-		bool CheckModule (IAssemblyDefinition assembly, IModuleDefinition module);
+		IList CheckModule (IAssemblyDefinition assembly, IModuleDefinition module, Runner runner);
 	}
 
 	public interface ITypeRule : IRule {
-		bool CheckType (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type);
+		IList CheckType (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type, Runner runner);
 	}
 
 	public interface IMethodRule : IRule {
-		bool CheckMethod (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type, IMethodDefinition method);
+		IList CheckMethod (IAssemblyDefinition assembly, IModuleDefinition module, ITypeDefinition type, IMethodDefinition method, Runner runner);
 	}
 }
Index: framework/MinimalRunner.cs
===================================================================
--- framework/MinimalRunner.cs	(revision 0)
+++ framework/MinimalRunner.cs	(revision 0)
@@ -0,0 +1,20 @@
+/*
+ * MinimalRunner.cs: A trivial extention of the Runner class, allowing
+ * it to be instantiated.
+ *
+ * Authors:
+ *   Aaron Tomb <atomb at soe.ucsc.edu>
+ *
+ * Copyright (c) 2005 Aaron Tomb and the contributors listed
+ * in the ChangeLog.
+ *
+ * This is free software, distributed under the MIT/X11 license.
+ * See the included LICENSE.MIT file for details.
+ **********************************************************************/
+
+namespace Gendarme.Framework {
+
+public class MinimalRunner : Runner {
+}
+
+}
Index: framework/Violation.cs
===================================================================
--- framework/Violation.cs	(revision 54948)
+++ framework/Violation.cs	(working copy)
@@ -27,17 +27,20 @@
 //
 
 using System;
+using System.Collections;
 
 namespace Gendarme.Framework {
 
 	public struct Violation {
 		public IRule Rule;
 		public object Violator;
+		public IList Messages;
 
-		public Violation (IRule rule, object violator)
+		public Violation (IRule rule, object violator, IList messages)
 		{
 			Rule = rule;
 			Violator = violator;
+			Messages = messages;
 		}
 	}
 }
Index: framework/Message.cs
===================================================================
--- framework/Message.cs	(revision 0)
+++ framework/Message.cs	(revision 0)
@@ -0,0 +1,52 @@
+/*
+ * Message.cs: an error or warning message produced by a checker when it
+ * discovers a problem.
+ *
+ * Authors:
+ *   Aaron Tomb <atomb at soe.ucsc.edu>
+ *
+ * Copyright (c) 2005 Aaron Tomb and the contributors listed
+ * in the ChangeLog.
+ *
+ * This is free software, distributed under the MIT/X11 license.
+ * See the included LICENSE.MIT file for details.
+ **********************************************************************/
+
+namespace Gendarme.Framework{
+
+public class Message {
+    private string text;
+    private Location location;
+    private MessageType type;
+
+    public Message(string text, Location location, MessageType type)
+    {
+        this.text = text;
+        this.location = location;
+        this.type = type;
+    }
+
+    public string Text {
+        get { return text; }
+    }
+
+    public Location Location {
+        get { return location; }
+    }
+
+    public MessageType Type {
+        get { return type; }
+    }
+
+    public override string ToString()
+    {
+        return location.ToString() + ": " + text;
+    }
+}
+
+public enum MessageType {
+    Error,
+    Warning
+}
+
+}
Index: framework/Makefile.am
===================================================================
--- framework/Makefile.am	(revision 54948)
+++ framework/Makefile.am	(working copy)
@@ -6,8 +6,10 @@
 
 framework_sources_in = ../AssemblyInfo.cs.in
 framework_generated_sources = $(framework_sources_in:.in=)
-framework_sources = AssemblyManager.cs IRule.cs RuleCollection.cs RuleInformation.cs \
-	RuleInformationManager.cs Rules.cs Runner.cs Violation.cs Violations.cs
+framework_sources = AssemblyManager.cs IRule.cs RuleCollection.cs \
+		    RuleInformation.cs  RuleInformationManager.cs \
+		    Rules.cs Runner.cs Violation.cs Violations.cs \
+		    Message.cs Location.cs MinimalRunner.cs
 
 framework_build_sources = $(addprefix $(srcdir)/, $(framework_sources))
 framework_build_sources += $(framework_generated_sources)
Index: framework/Violations.cs
===================================================================
--- framework/Violations.cs	(revision 54948)
+++ framework/Violations.cs	(working copy)
@@ -48,14 +48,14 @@
 			}
 		}
 
-		public void Add (IRule rule, object obj)
+		public void Add (IRule rule, object obj, IList messages)
 		{
 			if (rule == null)
 				throw new ArgumentNullException ("rule");
 			if (obj == null)
 				throw new ArgumentNullException ("obj");
 
-			List.Add (new Violation (rule, obj));
+			List.Add (new Violation (rule, obj, messages));
 		}
 
 		public void Add (Violation v)
Index: framework/Location.cs
===================================================================
--- framework/Location.cs	(revision 0)
+++ framework/Location.cs	(revision 0)
@@ -0,0 +1,48 @@
+/*
+ * Location.cs: an encapsulation of several pieces of information used
+ * to identify a location in an assembly.
+ *
+ * Authors:
+ *   Aaron Tomb <atomb at soe.ucsc.edu>
+ *
+ * Copyright (c) 2005 Aaron Tomb and the contributors listed
+ * in the ChangeLog.
+ *
+ * This is free software, distributed under the MIT/X11 license.
+ * See the included LICENSE.MIT file for details.
+ **********************************************************************/
+
+namespace Gendarme.Framework {
+
+public class Location {
+    private string type;
+    private string method;
+    private int offset; /* Offset of instruction into method */
+
+    public Location(string type, string method, int offset)
+    {
+        this.type = type;
+        this.method = method;
+        this.offset = offset;
+    }
+
+    public override string ToString()
+    {
+        string result = "";
+        if(type != null)
+            result += type;
+        if(method != null) {
+            if(type != null)
+                result += "::";
+            result += method;
+        }
+        if(offset >= 0) {
+            if(result.Length != 0)
+                result += ":";
+            result += offset.ToString("x4");
+        }
+        return result;
+    }
+}
+
+}
Index: framework/Runner.cs
===================================================================
--- framework/Runner.cs	(revision 54948)
+++ framework/Runner.cs	(working copy)
@@ -39,6 +39,8 @@
 
 		private Rules rules;
 		private Violations violations;
+		private static IList failure = new ArrayList();
+		protected bool debug = false;
 
 		public Rules Rules {
 			get {
@@ -56,6 +58,24 @@
 			}
 		}
 
+		public bool Debug {
+			get {
+				return debug;
+			}
+		}
+
+		public IList RuleSuccess {
+			get {
+				return null;
+			}
+		}
+
+		public IList RuleFailure {
+			get {
+				return failure;
+			}
+		}
+
 		private IRule CreateRuleFromType (Type type)
 		{
 			return (IRule) Activator.CreateInstance (type);
@@ -96,30 +116,35 @@
 
 		public void Process (IAssemblyDefinition assembly)
 		{
+			IList messages;
 			foreach (IAssemblyRule rule in Rules.Assembly) {
-				if (!rule.CheckAssembly (assembly))
-					Violations.Add (rule, assembly);
+				messages = rule.CheckAssembly(assembly, this);
+				if (messages != RuleSuccess)
+					Violations.Add (rule, assembly, messages);
 			}
 
 			foreach (IModuleDefinition module in assembly.Modules) {
 
 				foreach (IModuleRule rule in Rules.Module) {
-					if (!rule.CheckModule (assembly, module))
-						Violations.Add (rule, module);
+					messages = rule.CheckModule(assembly, module, this);
+					if (messages != RuleSuccess)
+						Violations.Add (rule, module, messages);
 				}
 
 				foreach (ITypeDefinition type in module.Types) {
 
 					foreach (ITypeRule rule in Rules.Type) {
-						if (!rule.CheckType (assembly, module, type))
-							Violations.Add (rule, type);
+						messages = rule.CheckType(assembly, module, type, this);
+						if (messages != RuleSuccess)
+							Violations.Add (rule, type, messages);
 					}
 
 					foreach (IMethodDefinition method in type.Methods) {
 
 						foreach (IMethodRule rule in Rules.Method) {
-							if (!rule.CheckMethod (assembly, module, type, method))
-								Violations.Add (rule, method);
+							messages = rule.CheckMethod(assembly, module, type, method, this);
+							if (messages != RuleSuccess)
+								Violations.Add (rule, method, messages);
 						}
 					}
 				}


More information about the Mono-devel-list mailing list