Author: spouliot
Date: 2008-01-24 18:40:30 -0500 (Thu, 24 Jan 2008)
New Revision: 93863
Removed:
trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/ImplementingEqualsButNotGetHashCodeAndViceVersaRule.cs
Modified:
trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/ChangeLog
trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/Gendarme.Rules.BadPractice.xml.in
trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/Makefile.am
trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/ToStringReturnsNullRule.cs
Log:
2008-01-24 Sebastien Pouliot <[EMAIL PROTECTED]>
* ImplementingEqualsButNotGetHashCodeAndViceVersaRule.cs: Rule
moves (with tests) into Design since it affects the API.
* ToStringReturnsNullRule.cs: Simplification to avoid uncommon cases
that added *LOTS* of false positives while still missing some
real defects. Now a rock-ified ITypeRule with much lower memory
requirements.
* Gendarme.Rules.BadPractice.xml.in: Remove (moved) definition.
* Makefile.am: Remove (moved) rule and tests
Modified: trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/ChangeLog
===================================================================
--- trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/ChangeLog
2008-01-24 23:36:42 UTC (rev 93862)
+++ trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/ChangeLog
2008-01-24 23:40:30 UTC (rev 93863)
@@ -1,3 +1,14 @@
+2008-01-24 Sebastien Pouliot <[EMAIL PROTECTED]>
+
+ * ImplementingEqualsButNotGetHashCodeAndViceVersaRule.cs: Rule
+ moves (with tests) into Design since it affects the API.
+ * ToStringReturnsNullRule.cs: Simplification to avoid uncommon cases
+ that added *LOTS* of false positives while still missing some
+ real defects. Now a rock-ified ITypeRule with much lower memory
+ requirements.
+ * Gendarme.Rules.BadPractice.xml.in: Remove (moved) definition.
+ * Makefile.am: Remove (moved) rule and tests
+
2008-01-23 Sebastien Pouliot <[EMAIL PROTECTED]>
* ConstructorShouldNotCallVirtualMethodsRule.cs: Add recursive
Modified:
trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/Gendarme.Rules.BadPractice.xml.in
===================================================================
---
trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/Gendarme.Rules.BadPractice.xml.in
2008-01-24 23:36:42 UTC (rev 93862)
+++
trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/Gendarme.Rules.BadPractice.xml.in
2008-01-24 23:40:30 UTC (rev 93863)
@@ -1,10 +1,4 @@
<rules>
- <rule Name="ImplementingEqualsButNotGetHashCodeAndViceVersaRule"
-
Type="Gendarme.Rules.BadPractice.ImplementingEqualsButNotGetHashCodeAndViceVersaRule,
Gendarme.Rules.BadPractice, [EMAIL PROTECTED]@, Culture=neutral,
PublicKeyToken=null"
-
Uri="http://groups.google.com/group/gendarme/web/rules-documentation#ImplementingEqualsButNotGetHashCodeAndViceVersaRule"
>
- <problem>Only one method of Object.Equals (Object) and
Object.GetHashCode () is implemented in '{0}'.</problem>
- <solution>Implement the other method also.</solution>
- </rule>
<rule Name="CloneMethodShouldNotReturnNullRule"
Type="Gendarme.Rules.BadPractice.CloneMethodShouldNotReturnNullRule,
Gendarme.Rules.BadPractice, [EMAIL PROTECTED]@, Culture=neutral,
PublicKeyToken=null"
Uri="http://groups.google.com/group/gendarme/web/rules-documentation#CloneMethodShouldNotReturnNullRule"
>
Deleted:
trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/ImplementingEqualsButNotGetHashCodeAndViceVersaRule.cs
===================================================================
---
trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/ImplementingEqualsButNotGetHashCodeAndViceVersaRule.cs
2008-01-24 23:36:42 UTC (rev 93862)
+++
trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/ImplementingEqualsButNotGetHashCodeAndViceVersaRule.cs
2008-01-24 23:40:30 UTC (rev 93863)
@@ -1,75 +0,0 @@
-//
-//
Gendarme.Rules.BadPractice.ImplementingEqualsButNotGetHashCodeAndViceVersaRule
-//
-// Authors:
-// Nidhi Rawal <[EMAIL PROTECTED]>
-//
-// Copyright (c) <2007> Nidhi Rawal
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-using System;
-
-using Mono.Cecil;
-
-using Gendarme.Framework;
-
-namespace Gendarme.Rules.BadPractice {
-
- public class ImplementingEqualsButNotGetHashCodeAndViceVersaRule:
ITypeRule {
-
- bool equals = false;
- bool getHashCode = false;
-
- private void EqualsOrGetHashCode (TypeDefinition type)
- {
- equals = false;
- getHashCode = false;
-
- foreach (MethodDefinition method in type.Methods) {
- if (method.Name == "Equals" &&
method.Parameters.Count == 1)
- equals = true;
- else if (method.Name == "GetHashCode" &&
method.Parameters.Count == 0)
- getHashCode = true;
- }
- }
-
- public MessageCollection CheckType (TypeDefinition type, Runner
runner)
- {
- EqualsOrGetHashCode (type);
-
- // if we have Equals but no GetHashCode method
- if (equals && !getHashCode) {
- Location location = new Location (type);
- Message message = new Message ("Implements
Object.Equals (Object) but does not implement Object.GetHashCode ()", location,
MessageType.Error);
- return new MessageCollection (message);
- }
-
- // if we have GetHashCode but no Equals method
- if (!equals && getHashCode) {
- Location location = new Location (type);
- Message message = new Message ("Implements
Object.GetHashCode () but does not implement Object.Equals (Object)", location,
MessageType.Error);
- return new MessageCollection (message);
- }
-
- // we either have both Equals and GetHashCode or none
(both fine)
- return runner.RuleSuccess;
- }
- }
-}
Modified: trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/Makefile.am
===================================================================
--- trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/Makefile.am
2008-01-24 23:36:42 UTC (rev 93862)
+++ trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/Makefile.am
2008-01-24 23:40:30 UTC (rev 93863)
@@ -10,8 +10,7 @@
badpractice_rules_sources_in = ../../AssemblyInfo.cs.in
badpractice_rules_generated_sources = $(badpractice_rules_sources_in:.in=)
badpractice_rules_sources = CloneMethodShouldNotReturnNullRule.cs
EqualShouldHandleNullArgRule.cs \
- ImplementingEqualsButNotGetHashCodeAndViceVersaRule.cs
ToStringReturnsNullRule.cs GetEntryAssemblyMayReturnNullRule.cs \
- ConstructorShouldNotCallVirtualMethodsRule.cs
+ ToStringReturnsNullRule.cs GetEntryAssemblyMayReturnNullRule.cs
ConstructorShouldNotCallVirtualMethodsRule.cs
badpractice_rules_build_sources = $(addprefix $(srcdir)/,
$(badpractice_rules_sources))
badpractice_rules_build_sources += $(badpractice_rules_generated_sources)
@@ -35,8 +34,7 @@
done;
badpractice_test_sources = CloneMethodShouldNotReturnNullTest.cs
EqualShouldHandleNullArgTest.cs \
- ImplementingEqualsButNotGetHashCodeAndViceVersaTest.cs
ToStringReturnsNullTest.cs GetEntryAssemblyMayReturnNullTest.cs \
- ConstructorShouldNotCallVirtualMethodsTest.cs
+ ToStringReturnsNullTest.cs GetEntryAssemblyMayReturnNullTest.cs
ConstructorShouldNotCallVirtualMethodsTest.cs
badpractice_test_build_sources = $(addprefix $(srcdir)/Test/,
$(badpractice_test_sources))
Modified:
trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/ToStringReturnsNullRule.cs
===================================================================
---
trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/ToStringReturnsNullRule.cs
2008-01-24 23:36:42 UTC (rev 93862)
+++
trunk/cecil/gendarme/rules/Gendarme.Rules.BadPractice/ToStringReturnsNullRule.cs
2008-01-24 23:40:30 UTC (rev 93863)
@@ -3,8 +3,10 @@
//
// Authors:
// Nidhi Rawal <[EMAIL PROTECTED]>
+// Sebastien Pouliot <[EMAIL PROTECTED]>
//
// Copyright (c) <2007> Nidhi Rawal
+// 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
@@ -29,134 +31,74 @@
using Mono.Cecil;
using Mono.Cecil.Cil;
+
using Gendarme.Framework;
+using Gendarme.Framework.Rocks;
namespace Gendarme.Rules.BadPractice {
- public class ToStringReturnsNullRule: IMethodRule {
+ public class ToStringReturnsNullRule: ITypeRule {
- private static bool IsOverridenToString (MethodDefinition
method)
+ public MessageCollection CheckType (TypeDefinition type, Runner
runner)
{
- return method.Name == "ToString" && method.IsVirtual;
- }
-
- public MessageCollection CheckMethod (MethodDefinition method,
Runner runner)
- {
- if (!method.HasBody)
+ // rules applies to types that overrides
System.Object.Equals(object)
+ MethodDefinition method = type.GetMethod
(MethodSignatures.ToString);
+ if ((method == null) || !method.HasBody)
return runner.RuleSuccess;
- if (!IsOverridenToString (method))
+ // rule applies
+
+ if (!CheckIfMethodReturnsNull (method))
return runner.RuleSuccess;
- int offset = 0;
- bool nullReturned = false;
- foreach (Instruction ins in method.Body.Instructions) {
- if (ins.OpCode == OpCodes.Ret) {
- Instruction prevIns = ins.Previous;
- if (prevIns.OpCode != OpCodes.Ldnull) {
- string opCodeSt;
- if (prevIns.OpCode ==
OpCodes.Call || prevIns.OpCode == OpCodes.Callvirt)
- opCodeSt = ReturnSt
(method, prevIns.Previous);
- else
- opCodeSt = ReturnSt
(method, prevIns);
- if (opCodeSt == null &&
(prevIns.Operand == null || prevIns.Operand.ToString () != "System.String
System.Convert::ToString(System.Object)"))
- nullReturned = true;
- if (MethodReturnsNull (method,
opCodeSt)) {
- nullReturned = true;
- offset = ins.Offset;
- }
- }
- else {
- nullReturned = true;
- offset = ins.Offset;
- }
- }
- }
-
- if (nullReturned) {
- Location location = new Location (method,
offset);
- Message message = new Message ("ToString ()
seems to returns null in some condition", location, MessageType.Error);
- return new MessageCollection (message);
- }
-
- return runner.RuleSuccess;
+ // 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);
}
- private static string ReturnSt (MethodDefinition method,
Instruction instruc)
+ private static bool CheckIfMethodReturnsNull (MethodDefinition
method)
{
- Hashtable opCodes = InitializeHashTable (method);
- string stOpCode = null;
- switch (instruc.OpCode.Code) {
- case Code.Ldloc_0:
- stOpCode = opCodes.ContainsKey (0)? opCodes
[0].ToString () : null;
- break;
- case Code.Ldloc_1:
- stOpCode = opCodes.ContainsKey (1)? opCodes
[1].ToString () : null;
- break;
- case Code.Ldloc_2:
- stOpCode = opCodes.ContainsKey (2)? opCodes
[2].ToString () : null;
- break;
- case Code.Ldloc_3:
- stOpCode = opCodes.ContainsKey (3)? opCodes
[3].ToString () : null;
- break;
- case Code.Ldloc_S:
- string [] s = instruc.Operand.ToString ().Split
('_');
- int i = Convert.ToInt32 (s [1]);
- stOpCode = opCodes.ContainsKey (i) ? opCodes
[i].ToString () : null;
- break;
- case Code.Ldfld:
- TypeDefinition type = (TypeDefinition)
method.DeclaringType;
- foreach (MethodDefinition ctor in
type.Constructors)
- foreach (Instruction ctorins in
ctor.Body.Instructions)
- if (ctorins.Operand !=null &&
ctorins.Operand.ToString () == instruc.Operand.ToString ())
- stOpCode =
ctorins.Operand.ToString ();
- break;
- case Code.Ldsfld:
- stOpCode = String.Empty;
- break;
- }
- return stOpCode;
- }
-
- private static Hashtable InitializeHashTable (MethodDefinition
method)
- {
- int count = 0;
- Hashtable hash = new Hashtable ();
-
foreach (Instruction ins in method.Body.Instructions) {
- if (ins.OpCode.Code.ToString().Substring(0,2)
== "St") {
- if (ins.OpCode.Code == Code.Stloc_S) {
- hash.Add (count,
ins.Operand.ToString ());
- count ++;
+ switch (ins.OpCode.Code) {
+ case Code.Ret:
+ switch (ins.Previous.OpCode.Code) {
+ case Code.Ldarg_0:
+ // very special case where
String.ToString() return "this"
+ return false;
+ case Code.Ldloc_0:
+ case Code.Ldloc_1:
+ case Code.Ldloc_2:
+ 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;
+ case Code.Ldnull:
+ // we're sure it's null
+ return true;
+ case Code.Ldstr:
+ return (ins.Previous.Operand ==
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;
+ case Code.Call:
+ case Code.Callvirt:
+ // note: calling other
ToString() is safe since the rule applies to them too
+ // FIXME: we could check if the
method can possibly return a null string
+ break;
+ default:
+ throw new NotSupportedException
(String.Format ("{0} inside {1}", ins.Previous.OpCode.Code, method));
}
- else {
- hash.Add (count,
ins.OpCode.Code.ToString ());
- count ++;
- }
+ break;
}
}
- return hash;
+ return false;
}
-
- public bool MethodReturnsNull (MethodDefinition method, string
code)
- {
- bool isNull = false;
- Instruction prevInstruc;
- foreach (Instruction ins in method.Body.Instructions) {
- prevInstruc = ins.Previous;
- if (ins.Operand != null && ins.Operand.ToString
() == null && ins.OpCode == OpCodes.Stfld)
- isNull = false;
- else if (ins.OpCode.Code.ToString () == code ||
(ins.OpCode.ToString ().StartsWith ("st") && ins.Operand !=null &&
ins.Operand.ToString () == code)) {
- if (prevInstruc.OpCode.Code ==
Code.Ldnull)
- isNull = true;
- else if (prevInstruc.OpCode.Code ==
Code.Call || prevInstruc.OpCode.Code == Code.Callvirt) {
- code = ReturnSt (method,
prevInstruc.Previous);
- isNull = MethodReturnsNull
(method, code);
- }
- }
- }
- return isNull;
- }
-
}
}
_______________________________________________
Mono-patches maillist - [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches