Author: spouliot
Date: 2007-11-22 10:43:11 -0500 (Thu, 22 Nov 2007)
New Revision: 90162

Modified:
   trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/ChangeLog
   
trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/CloneMethodShouldNotReturnNullRule.cs
Log:
2007-11-22  Sebastien Pouliot  <[EMAIL PROTECTED]>

        * CloneMethodShouldNotReturnNullRule.cs: Don't create a 
        MessageCollection unless we return a message. IL check logic is too
        simplistic, added a little more logic (but it's still needs to be 
        fixed) so the test run correctly under Windows (VS in Debug mode 
        really generates crap).



Modified: trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/ChangeLog
===================================================================
--- trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/ChangeLog     
2007-11-22 15:39:39 UTC (rev 90161)
+++ trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/ChangeLog     
2007-11-22 15:43:11 UTC (rev 90162)
@@ -1,3 +1,11 @@
+2007-11-22  Sebastien Pouliot  <[EMAIL PROTECTED]>
+
+       * CloneMethodShouldNotReturnNullRule.cs: Don't create a 
+       MessageCollection unless we return a message. IL check logic is too
+       simplistic, added a little more logic (but it's still needs to be 
+       fixed) so the test run correctly under Windows (VS in Debug mode 
+       really generates crap).
+
 2007-11-18  Nestor Salceda  <[EMAIL PROTECTED]>
 
        * ToStringReturnsNullRule.cs: Fixed NullReferenceException when doesn't

Modified: 
trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/CloneMethodShouldNotReturnNullRule.cs
===================================================================
--- 
trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/CloneMethodShouldNotReturnNullRule.cs
 2007-11-22 15:39:39 UTC (rev 90161)
+++ 
trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/CloneMethodShouldNotReturnNullRule.cs
 2007-11-22 15:43:11 UTC (rev 90162)
@@ -3,8 +3,10 @@
 //
 // Authors:
 //     Nidhi Rawal <[EMAIL PROTECTED]>
+//     Sebastien Pouliot <[EMAIL PROTECTED]>
 //
 // Copyright (c) <2007> Nidhi Rawal
+// Copyright (C) 2007 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
@@ -25,41 +27,87 @@
 // THE SOFTWARE.
 
 using System;
-using System.Collections;
 
 using Mono.Cecil;
 using Mono.Cecil.Cil;
 using Gendarme.Framework;
 
-namespace Gendarme.Rules.BadPractice
-{
-       public class CloneMethodShouldNotReturnNullRule: ITypeRule
-       {
+namespace Gendarme.Rules.BadPractice {
+
+       public class CloneMethodShouldNotReturnNullRule: ITypeRule {
+
                private bool ImplementsICloneable (TypeDefinition type)
                {
-                       foreach (TypeReference iface in type.Interfaces)
-                               if(iface.FullName == "System.ICloneable")
+                       foreach (TypeReference iface in type.Interfaces) {
+                               if (iface.FullName == "System.ICloneable")
                                        return true;
+                       }
                        return false;
                }
 
+               private bool IsCloneMethod (MethodDefinition method)
+               {
+                       return (method.Name == "Clone" && 
(method.Parameters.Count == 0));
+               }
+
                public MessageCollection CheckType (TypeDefinition type, Runner 
runner)
                {
-                       MessageCollection messageCollection = new 
MessageCollection ();
-                       if (ImplementsICloneable (type))
-                               foreach (MethodDefinition method in 
type.Methods)
-                                       if (method.Name == "Clone" && 
method.Parameters.Count == 0 && method.HasBody)
-                                               foreach (Instruction 
instruction in method.Body.Instructions) {
-                                                       Instruction prevInstr = 
instruction.Previous;
-                                                       if 
(instruction.OpCode.Name == "ret" && prevInstr.OpCode.Name == "ldnull") {
-                                                               Location 
location = new Location (type.FullName, type.Name, instruction.Offset);
-                                                               Message message 
= new Message ("The ICloneable.Clone () method returns null", location, 
MessageType.Error);
-                                                               
messageCollection.Add (message);
-                                                       }
+                       // rule applies only to types implementing 
System.ICloneable
+                       if (!ImplementsICloneable (type))
+                               return runner.RuleSuccess;
+
+                       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...)
+                               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;
+                                               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;
+                                               return_null = false;
+                                               break;
+                                       case Code.Ret:
+                                               if (return_null) {
+                                                       Location location = new 
Location (type.FullName, type.Name, instruction.Offset);
+                                                       Message message = new 
Message ("The ICloneable.Clone () method returns null", location, 
MessageType.Error);
+                                                       return new 
MessageCollection (message);
                                                }
-                       if (messageCollection.Count == 0)
-                                       return null;
-                       return messageCollection;
+                                               previous = instruction;
+                                               break;
+                                       case Code.Stloc_0:
+                                               // return_null doesn't change 
state
+                                       default:
+                                               previous = instruction;
+                                               break;
+                                       }
+                               }
+                       }
+
+                       return runner.RuleSuccess;
                }
        }
 }

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

Reply via email to