[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