Author: spouliot
Date: 2008-02-15 13:16:01 -0500 (Fri, 15 Feb 2008)
New Revision: 95778

Modified:
   trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/ChangeLog
   
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/CheckNewExceptionWithoutThrowingRule.cs
   
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/CheckNewThreadWithoutStartRule.cs
   
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/CloneMethodShouldNotReturnNullRule.cs
   
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/ConstructorShouldNotCallVirtualMethodsRule.cs
   
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/EqualShouldHandleNullArgRule.cs
   
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/GetEntryAssemblyMayReturnNullRule.cs
   
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/ToStringReturnsNullRule.cs
Log:
2008-02-15  Sebastien Pouliot  <[EMAIL PROTECTED]>

        * CheckNewExceptionWithoutThrowingRule.cs
        * CheckNewThreadWithoutStartRule.cs
        * CloneMethodShouldNotReturnNullRule.cs
        * ConstructorShouldNotCallVirtualMethodsRule.cs
        * EqualShouldHandleNullArgRule.cs
        * GetEntryAssemblyMayReturnNullRule.cs
        * ToStringReturnsNullRule.cs
                Update rules wrt framework changes.



Modified: trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/ChangeLog
===================================================================
--- trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/ChangeLog        
2008-02-15 18:14:10 UTC (rev 95777)
+++ trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/ChangeLog        
2008-02-15 18:16:01 UTC (rev 95778)
@@ -1,3 +1,14 @@
+2008-02-15  Sebastien Pouliot  <[EMAIL PROTECTED]>
+
+       * CheckNewExceptionWithoutThrowingRule.cs
+       * CheckNewThreadWithoutStartRule.cs
+       * CloneMethodShouldNotReturnNullRule.cs
+       * ConstructorShouldNotCallVirtualMethodsRule.cs
+       * EqualShouldHandleNullArgRule.cs
+       * GetEntryAssemblyMayReturnNullRule.cs
+       * ToStringReturnsNullRule.cs
+               Update rules wrt framework changes.
+
 2008-01-30  Sebastien Pouliot  <[EMAIL PROTECTED]>
 
        * CheckNewExceptionWithoutThrowingRule.cs: New. Rule to check that

Modified: 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/CheckNewExceptionWithoutThrowingRule.cs
===================================================================
--- 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/CheckNewExceptionWithoutThrowingRule.cs
  2008-02-15 18:14:10 UTC (rev 95777)
+++ 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/CheckNewExceptionWithoutThrowingRule.cs
  2008-02-15 18:16:01 UTC (rev 95778)
@@ -3,8 +3,10 @@
 //
 // Authors:
 //     Andreas Noever <[EMAIL PROTECTED]>
+//     Sebastien Pouliot <[EMAIL PROTECTED]>
 //
 //  (C) 2008 Andreas Noever
+// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -32,6 +34,7 @@
 using System.Text;
 
 using Gendarme.Framework;
+using Gendarme.Framework.Helpers;
 using Gendarme.Framework.Rocks;
 
 using Mono.Cecil;
@@ -39,15 +42,15 @@
 
 namespace Gendarme.Rules.BadPractice {
 
-       public class CheckNewExceptionWithoutThrowingRule : IMethodRule {
+       [Problem ("This method creates an exception that is never throwed nor 
returned to the caller.")]
+       [Solution ("Make sure the exception is required, throw it (if it is) or 
remove it (if not).")]
+       public class CheckNewExceptionWithoutThrowingRule : Rule, IMethodRule {
 
-               public MessageCollection CheckMethod (MethodDefinition method, 
Runner runner)
+               public RuleResult CheckMethod (MethodDefinition method)
                {
                        if (!method.HasBody)
-                               return runner.RuleSuccess;
+                               return RuleResult.DoesNotApply;
 
-                       MessageCollection results = null;
-
                        StackEntryAnalysis sea = null;
 
                        foreach (Instruction ins in method.Body.Instructions) {
@@ -100,15 +103,12 @@
                                }
 
                                if (!exceptionUsed) {
-                                       if (results == null)
-                                               results = new MessageCollection 
();
-                                       Location loc = new Location (method, 
ins.Offset);
-                                       Message msg = new Message ("This 
exception is not thrown, passed as an argument or returned by this method.", 
loc, MessageType.Warning);
-                                       results.Add (msg);
+                                       // Critical because code cannot work as 
intented
+                                       Runner.Report (method, ins, 
Severity.Critical, Confidence.High, String.Empty);
                                }
                        }
 
-                       return results;
+                       return Runner.CurrentRuleResult;
                }
        }
 }

Modified: 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/CheckNewThreadWithoutStartRule.cs
===================================================================
--- 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/CheckNewThreadWithoutStartRule.cs
        2008-02-15 18:14:10 UTC (rev 95777)
+++ 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/CheckNewThreadWithoutStartRule.cs
        2008-02-15 18:16:01 UTC (rev 95778)
@@ -3,8 +3,10 @@
 //
 // Authors:
 //     Andreas Noever <[EMAIL PROTECTED]>
+//     Sebastien Pouliot <[EMAIL PROTECTED]>
 //
 //  (C) 2008 Andreas Noever
+// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -32,15 +34,17 @@
 using System.Text;
 
 using Gendarme.Framework;
+using Gendarme.Framework.Helpers;
 using Gendarme.Framework.Rocks;
 
 using Mono.Cecil;
 using Mono.Cecil.Cil;
 
-
 namespace Gendarme.Rules.BadPractice {
 
-       public class CheckNewThreadWithoutStartRule : IMethodRule {
+       [Problem ("This method creates an thread that is never started nor 
returned to the caller.")]
+       [Solution ("Make sure the thread is required, start it (if it is) or 
remove it (if not).")]
+       public class CheckNewThreadWithoutStartRule : Rule, IMethodRule {
 
                private static bool CheckUsage (StackEntryAnalysis.UsageResult 
[] usageResults)
                {
@@ -74,13 +78,11 @@
                        return false;
                }
 
-               public MessageCollection CheckMethod (MethodDefinition method, 
Runner runner)
+               public RuleResult CheckMethod (MethodDefinition method)
                {
                        if (!method.HasBody)
-                               return runner.RuleSuccess;
+                               return RuleResult.DoesNotApply;
 
-                       MessageCollection results = null;
-
                        StackEntryAnalysis sea = null;
 
                        foreach (Instruction ins in method.Body.Instructions) {
@@ -103,15 +105,12 @@
                                StackEntryAnalysis.UsageResult [] usageResults 
= sea.GetStackEntryUsage (ins);
 
                                if (!CheckUsage (usageResults)) {
-                                       if (results == null)
-                                               results = new MessageCollection 
();
-                                       Location loc = new Location (method, 
ins.Offset);
-                                       Message msg = new Message ("This Thread 
is not started, passed as an argument or returned by this method.", loc, 
MessageType.Warning);
-                                       results.Add (msg);
+                                       // Critical because code cannot work as 
intented
+                                       Runner.Report (method, ins, 
Severity.Critical, Confidence.High, String.Empty);
                                }
                        }
 
-                       return results;
+                       return Runner.CurrentRuleResult;
                }
        }
 }

Modified: 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/CloneMethodShouldNotReturnNullRule.cs
===================================================================
--- 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/CloneMethodShouldNotReturnNullRule.cs
    2008-02-15 18:14:10 UTC (rev 95777)
+++ 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/CloneMethodShouldNotReturnNullRule.cs
    2008-02-15 18:16:01 UTC (rev 95778)
@@ -6,7 +6,7 @@
 //     Sebastien Pouliot <[EMAIL PROTECTED]>
 //
 // Copyright (c) <2007> Nidhi Rawal
-// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2007-2008 Novell, Inc (http://www.novell.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to 
deal
@@ -32,75 +32,72 @@
 using Mono.Cecil.Cil;
 
 using Gendarme.Framework;
+using Gendarme.Framework.Helpers;
 using Gendarme.Framework.Rocks;
 
 namespace Gendarme.Rules.BadPractice {
 
-       public class CloneMethodShouldNotReturnNullRule: ITypeRule {
+       [Problem ("The implementation ICloneable.Clone () seems to return null 
in some circumstances.")]
+       [Solution ("Return an appropriate object instead of returning null.")]
+       public class CloneMethodShouldNotReturnNullRule: Rule, ITypeRule {
 
                private static bool IsCloneMethod (MethodDefinition method)
                {
                        return (method.Name == "Clone" && 
(method.Parameters.Count == 0));
                }
 
-               public MessageCollection CheckType (TypeDefinition type, Runner 
runner)
+               public RuleResult CheckType (TypeDefinition type)
                {
                        // rule applies only to types implementing 
System.ICloneable
                        if (!type.Implements ("System.ICloneable"))
-                               return runner.RuleSuccess;
+                               return RuleResult.DoesNotApply;
 
-                       foreach (MethodDefinition method in type.Methods) {
-                               // look for the Clone() method
-                               if (!IsCloneMethod (method))
-                                       continue;
+                       // rule applies only if a body is available (e.g. not 
for pinvokes...)
+                       MethodDefinition method = type.GetMethod 
(MethodSignatures.Clone);
+                       if ((method == null) || (!method.HasBody))
+                               return RuleResult.DoesNotApply;
 
-                               // rule applies only if a body is available 
(e.g. not for pinvokes...)
-                               if (!method.HasBody)
-                                       return runner.RuleSuccess;
-
-                               // FIXME: still *very* incomplete, but that 
will handle non-optimized code
-                               // from MS CSC where "return null" == "nop | 
ldnull | stloc.0 | br.s | ldloc.0 | ret"
-                               bool return_null = false;
-                               Instruction previous = null;
-                               foreach (Instruction instruction in 
method.Body.Instructions) {
-                                       switch (instruction.OpCode.Code) {
-                                       case Code.Nop:
-                                       case Code.Constrained:
-                                               // don't update previous
-                                               break;
-                                       case Code.Ldnull:
-                                               return_null = true;
+                       // FIXME: still *very* incomplete, but that will handle 
non-optimized code
+                       // from MS CSC where "return null" == "nop | ldnull | 
stloc.0 | br.s | ldloc.0 | ret"
+                       bool return_null = false;
+                       Instruction previous = null;
+                       foreach (Instruction instruction in 
method.Body.Instructions) {
+                               switch (instruction.OpCode.Code) {
+                               case Code.Nop:
+                               case Code.Constrained:
+                                       // don't update previous
+                                       break;
+                               case Code.Ldnull:
+                                       return_null = true;
+                                       previous = instruction;
+                                       break;
+                               case Code.Br:
+                               case Code.Br_S:
+                                       // don't update previous if branching 
to next instruction
+                                       if (instruction.Operand != 
instruction.Next)
                                                previous = instruction;
+                                       break;
+                               case Code.Ldloc_0:
+                                       if ((previous != null) && 
(previous.OpCode.Code == Code.Stloc_0))
                                                break;
-                                       case Code.Br:
-                                       case Code.Br_S:
-                                               // don't update previous if 
branching to next instruction
-                                               if (instruction.Operand != 
instruction.Next)
-                                                       previous = instruction;
-                                               break;
-                                       case Code.Ldloc_0:
-                                               if ((previous != null) && 
(previous.OpCode.Code == Code.Stloc_0))
-                                                       break;
-                                               return_null = false;
-                                               break;
-                                       case Code.Ret:
-                                               if (return_null) {
-                                                       Location location = new 
Location (method, instruction.Offset);
-                                                       Message message = new 
Message ("The ICloneable.Clone () method returns null", location, 
MessageType.Error);
-                                                       return new 
MessageCollection (message);
-                                               }
-                                               previous = instruction;
-                                               break;
-                                       case Code.Stloc_0:
-                                               // return_null doesn't change 
state
-                                       default:
-                                               previous = instruction;
-                                               break;
+                                       return_null = false;
+                                       break;
+                               case Code.Ret:
+                                       if (return_null) {
+                                               Runner.Report (method, 
instruction, Severity.Medium, Confidence.Normal, String.Empty);
+                                               return RuleResult.Failure;
                                        }
+                                       previous = instruction;
+                                       break;
+                               case Code.Stloc_0:
+                                       // return_null doesn't change state
+                               default:
+                                       previous = instruction;
+                                       break;
                                }
                        }
 
-                       return runner.RuleSuccess;
+                       return RuleResult.Success;
                }
        }
 }

Modified: 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/ConstructorShouldNotCallVirtualMethodsRule.cs
===================================================================
--- 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/ConstructorShouldNotCallVirtualMethodsRule.cs
    2008-02-15 18:14:10 UTC (rev 95777)
+++ 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/ConstructorShouldNotCallVirtualMethodsRule.cs
    2008-02-15 18:16:01 UTC (rev 95778)
@@ -38,31 +38,31 @@
 
 namespace Gendarme.Rules.BadPractice {
 
-       public class ConstructorShouldNotCallVirtualMethodsRule : ITypeRule {
+       [Problem ("Some constructors calls virtual methods which won't be known 
before runtime.")]
+       [Solution ("Avoid calling virtual methods from constructors or seal the 
the type.")]
+       public class ConstructorShouldNotCallVirtualMethodsRule : Rule, 
ITypeRule {
 
-               public MessageCollection CheckType (TypeDefinition type, Runner 
runner)
+               public RuleResult CheckType (TypeDefinition type)
                {
                        // sealed classes are ok
                        if (type.IsSealed)
-                               return runner.RuleSuccess;
+                               return RuleResult.DoesNotApply;
 
-                       MessageCollection messages = runner.RuleSuccess;
-
                        // check each constructor
                        foreach (MethodDefinition constructor in 
type.Constructors) {
                                // early checks to avoid stack creation
                                if (constructor.IsStatic || 
!constructor.HasBody)
                                        continue;
 
-                               CheckConstructor (constructor, ref messages);
+                               CheckConstructor (constructor);
                        }
-                       return messages;
+                       return Runner.CurrentRuleResult;
                }
 
-               private static void CheckConstructor (MethodDefinition 
constructor, ref MessageCollection messages)
+               private void CheckConstructor (MethodDefinition constructor)
                {
                        Stack<string> stack = new Stack<string> ();
-                       CheckMethod (constructor, ref messages, stack);
+                       CheckMethod (constructor, stack);
                }
 
                private static bool IsSubsclass (TypeReference sub, 
TypeReference type)
@@ -110,7 +110,7 @@
                        return false;
                }
 
-               private static void CheckMethod (MethodDefinition method, ref 
MessageCollection messages, Stack<string> stack)
+               private void CheckMethod (MethodDefinition method, 
Stack<string> stack)
                {
                        if (!method.HasBody)
                                return;
@@ -140,17 +140,12 @@
                                                continue;
 
                                        if (md.IsVirtual && !md.IsFinal) {
-                                               Location loc = new Location 
(method, current.Offset);
                                                string s = stack.Count == 0 ? 
method.ToString () : stack.Aggregate ((a1, a2) => a1 + ", " + 
Environment.NewLine + a2);
-                                               s = String.Format ("Calling a 
virtual method, '{0}', from {1} of a non-sealed class is a bad practice.", md, 
s);
-                                               Message msg = new Message (s, 
loc, MessageType.Error);
-                                               if (messages == null)
-                                                       messages = new 
MessageCollection (msg);
-                                               else
-                                                       messages.Add (msg);
+                                               s = String.Format ("Calling a 
virtual method, '{0}' from {1}.", md, s);
+                                               Runner.Report (method, current, 
Severity.High, Confidence.High, s);
                                        } else {
                                                stack.Push (method_name);
-                                               CheckMethod (md, ref messages, 
stack);
+                                               CheckMethod (md, stack);
                                                stack.Pop ();
                                        }
                                        break;

Modified: 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/EqualShouldHandleNullArgRule.cs
===================================================================
--- 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/EqualShouldHandleNullArgRule.cs
  2008-02-15 18:14:10 UTC (rev 95777)
+++ 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/EqualShouldHandleNullArgRule.cs
  2008-02-15 18:16:01 UTC (rev 95778)
@@ -26,34 +26,36 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+using System;
+
 using Mono.Cecil;
 using Mono.Cecil.Cil;
 
 using Gendarme.Framework;
+using Gendarme.Framework.Helpers;
 using Gendarme.Framework.Rocks;
 
 namespace Gendarme.Rules.BadPractice {
 
-       public class EqualShouldHandleNullArgRule: ITypeRule {
+       [Problem ("This Equals method does not handle null argument as it 
should.")]
+       [Solution ("Modify the method implementation to return false if null 
argument found.")]
+       public class EqualShouldHandleNullArgRule : Rule, ITypeRule {
 
-               private const string Message = "The overridden method 
Object.Equals (Object) does not return false if null value is found";
-
-               public MessageCollection CheckType (TypeDefinition type, Runner 
runner)
+               public RuleResult CheckType (TypeDefinition type)
                {
                        // rules applies to types that overrides 
System.Object.Equals(object)
                        MethodDefinition method = type.GetMethod 
(MethodSignatures.Equals);
                        if ((method == null) || !method.HasBody)
-                               return runner.RuleSuccess;
+                               return RuleResult.DoesNotApply;
 
                        // rule applies
 
                        // scan IL to see if null is checked and false returned
                        if (HandlesNullArg (method))
-                               return runner.RuleSuccess;
-       
-                       Location location = new Location (method);
-                       Message msg = new Message (Message, location, 
MessageType.Error);
-                       return new MessageCollection (msg);
+                               return RuleResult.Success;
+
+                       Runner.Report (method, Severity.Medium, 
Confidence.High, String.Empty);
+                       return RuleResult.Failure;
                }
 
                // note: not perfect, in particular when calls to other methods 
are used

Modified: 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/GetEntryAssemblyMayReturnNullRule.cs
===================================================================
--- 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/GetEntryAssemblyMayReturnNullRule.cs
     2008-02-15 18:14:10 UTC (rev 95777)
+++ 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/GetEntryAssemblyMayReturnNullRule.cs
     2008-02-15 18:16:01 UTC (rev 95778)
@@ -3,8 +3,10 @@
 //
 // Authors:
 //     Daniel Abramov <[EMAIL PROTECTED]>
+//     Sebastien Pouliot <[EMAIL PROTECTED]>
 //
 // Copyright (C) 2008 Daniel Abramov
+// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to 
deal
@@ -35,41 +37,36 @@
 
 namespace Gendarme.Rules.BadPractice {
 
-       public class GetEntryAssemblyMayReturnNullRule : IMethodRule {
+       [Problem ("This method calls Assembly.GetEntryAssembly which may 
returns null if not called from the root application domain.")]
+       [Solution ("Avoid depending on Assembly.GetEntryAssembly inside 
reusable code.")]
+       public class GetEntryAssemblyMayReturnNullRule : Rule, IMethodRule {
 
-               public MessageCollection CheckMethod (MethodDefinition 
methodDefinition, Runner runner)
+               public RuleResult CheckMethod (MethodDefinition method)
                {
                        // rule doesn't not apply to methods without code (e.g. 
p/invokes)
-                       if (!methodDefinition.HasBody)
-                               return runner.RuleSuccess;
+                       if (!method.HasBody)
+                               return RuleResult.DoesNotApply;
 
-                       AssemblyDefinition assembly = 
methodDefinition.DeclaringType.Module.Assembly;
-
                        // not for executables
-                       if (assembly.EntryPoint != null)
-                               return runner.RuleSuccess;
+                       if (method.DeclaringType.Module.Assembly.EntryPoint != 
null)
+                               return RuleResult.DoesNotApply;
 
                        // go!
-                       MessageCollection messages = runner.RuleSuccess;
-                       foreach (Instruction current in 
methodDefinition.Body.Instructions) {
+
+                       foreach (Instruction current in 
method.Body.Instructions) {
                                switch (current.OpCode.Code) {
                                case Code.Call:
                                case Code.Calli:
                                case Code.Callvirt:
                                        MethodReference mr = (current.Operand 
as MethodReference);
-                                       if (mr != null && mr.Name == 
"GetEntryAssembly"
-                                           && mr.DeclaringType.FullName == 
"System.Reflection.Assembly") { // that's it
-                                               Location loc = new Location 
(methodDefinition, current.Offset);
-                                               Message msg = new Message 
("Assembly.GetEntryAssembly () method returns null when it is called not from 
the root application domain.", loc, MessageType.Warning);
-                                               if (messages == 
runner.RuleSuccess)
-                                                       messages = new 
MessageCollection (msg);
-                                               else
-                                                       messages.Add (msg);
+                                       if ((mr != null) && (mr.Name == 
"GetEntryAssembly")
+                                               && (mr.DeclaringType.FullName 
== "System.Reflection.Assembly")) {
+                                               Runner.Report (method, current, 
Severity.Medium, Confidence.Total, String.Empty);
                                        }
                                        break;
                                }
                        }
-                       return messages;
+                       return Runner.CurrentRuleResult;
                }
        }
 }

Modified: 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/ToStringReturnsNullRule.cs
===================================================================
--- 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/ToStringReturnsNullRule.cs
       2008-02-15 18:14:10 UTC (rev 95777)
+++ 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.BadPractice/ToStringReturnsNullRule.cs
       2008-02-15 18:16:01 UTC (rev 95778)
@@ -33,31 +33,33 @@
 using Mono.Cecil.Cil;
 
 using Gendarme.Framework;
+using Gendarme.Framework.Helpers;
 using Gendarme.Framework.Rocks;
 
 namespace Gendarme.Rules.BadPractice {
 
-       public class ToStringReturnsNullRule: ITypeRule {
+       [Problem ("This type contains a ToString () method that could returns 
null.")]
+       [Solution ("Return an empty string or other appropriate string rather 
than returning null.")]
+       public class ToStringReturnsNullRule: Rule, ITypeRule {
 
-               public MessageCollection CheckType (TypeDefinition type, Runner 
runner)
+               public RuleResult CheckType (TypeDefinition type)
                {
                        // rules applies to types that overrides 
System.Object.Equals(object)
                        MethodDefinition method = type.GetMethod 
(MethodSignatures.ToString);
                        if ((method == null) || !method.HasBody)
-                               return runner.RuleSuccess;
+                               return RuleResult.DoesNotApply;
 
                        // rule applies
 
-                       if (!CheckIfMethodReturnsNull (method))
-                               return runner.RuleSuccess;
+                       Instruction ins = CheckIfMethodReturnsNull (method);
+                       if (ins == null)
+                               return RuleResult.Success;
 
-                       // FIXME: location
-                       Location location = new Location (method, -1);
-                       Message message = new Message ("Method 'ToString()' 
seems to returns null under some conditions.", location, MessageType.Error);
-                       return new MessageCollection (message);
+                       Runner.Report (method, ins, Severity.Medium, 
Confidence.Normal, String.Empty);
+                       return RuleResult.Failure;
                }
 
-               private static bool CheckIfMethodReturnsNull (MethodDefinition 
method)
+               private static Instruction CheckIfMethodReturnsNull 
(MethodDefinition method)
                {
                        foreach (Instruction ins in method.Body.Instructions) {
                                switch (ins.OpCode.Code) {
@@ -65,28 +67,29 @@
                                        switch (ins.Previous.OpCode.Code) {
                                        case Code.Ldarg_0:
                                                // very special case where 
String.ToString() return "this"
-                                               return false;
+                                               return null;
                                        case Code.Ldloc_0:
                                        case Code.Ldloc_1:
                                        case Code.Ldloc_2:
+                                       case Code.Ldloc_3:
                                        case Code.Ldloc_S:
                                                // FIXME: we could detect some 
NULL in there
                                                break;
                                        case Code.Newobj:
                                                // we're sure it's not null, 
e.g. new string ('!', 2)
-                                               return false;
+                                               return null;
                                        case Code.Ldnull:
                                                // we're sure it's null
-                                               return true;
+                                               return ins;
                                        case Code.Ldstr:
-                                               return (ins.Previous.Operand == 
null);
+                                               return (ins.Previous.Operand == 
null) ? ins : null;
                                        case Code.Ldfld:
                                        case Code.Ldsfld:
                                                // we could be sure for 
read-only fields with
                                                //      if 
((ins.Previous.Operand as FieldDefinition).IsInitOnly)
                                                // but since it's unlikely we 
can track null in them...
                                                // ...better not return false 
positives
-                                               return false;
+                                               return null;
                                        case Code.Call:
                                        case Code.Callvirt:
                                                // note: calling other 
ToString() is safe since the rule applies to them too
@@ -98,7 +101,7 @@
                                        break;
                                }
                        }
-                       return false;
+                       return null;
                }
        }
 }

_______________________________________________
Mono-patches maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches

Reply via email to