Author: spouliot
Date: 2007-11-21 12:55:45 -0500 (Wed, 21 Nov 2007)
New Revision: 90098
Modified:
trunk/cecil/gendarme/rules/Gendarme.Rules.Performance/AvoidUncalledPrivateCodeRule.cs
trunk/cecil/gendarme/rules/Gendarme.Rules.Performance/ChangeLog
Log:
2007-11-21 Sebastien Pouliot <[EMAIL PROTECTED]>
* AvoidUncalledPrivateCodeRule.cs: Simplified logic. Avoid using
strings. Consider finalizers (since it's normal that they look
uncalled). Pass all unit tests under Mono but 3 fails under MS 2.0!
Modified:
trunk/cecil/gendarme/rules/Gendarme.Rules.Performance/AvoidUncalledPrivateCodeRule.cs
===================================================================
---
trunk/cecil/gendarme/rules/Gendarme.Rules.Performance/AvoidUncalledPrivateCodeRule.cs
2007-11-21 17:51:53 UTC (rev 90097)
+++
trunk/cecil/gendarme/rules/Gendarme.Rules.Performance/AvoidUncalledPrivateCodeRule.cs
2007-11-21 17:55:45 UTC (rev 90098)
@@ -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,176 +27,165 @@
// THE SOFTWARE.
using System;
-using System.Collections;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Gendarme.Framework;
-namespace Gendarme.Rules.Performance
-{
- public class AvoidUncalledPrivateCodeRule: IMethodRule
- {
- public MessageCollection CheckMethod (MethodDefinition method,
Runner runner)
- {
- MessageCollection messageCollection = new
MessageCollection ();
- TypeDefinition type = method.DeclaringType as
TypeDefinition;
+namespace Gendarme.Rules.Performance {
- if (MemberIsCallable (type, method) && !MemberIsCalled
(type, method)) {
- Location location = new Location
(method.DeclaringType.FullName, method.Name, 0);
- Message message = new Message ("The private or
internal code is not called", location, MessageType.Error);
- messageCollection.Add (message);
- }
+ public class AvoidUncalledPrivateCodeRule: IMethodRule {
- if (messageCollection.Count == 0)
- return null;
- return messageCollection;
- }
+ // we should move these methods into an helper class (e.g.
MethodHelper)
+ // and reuse them in other rules
- private bool MemberIsCalled (TypeDefinition type,
MethodDefinition method)
+ public bool IsStaticConstructor (MethodDefinition md)
{
- bool isCalled = false;
-
- if (TypeIsInternal (type) && TypeIsPrivate (type) &&
MemberIsInternal (method))
- isCalled = PrivateMemberIsCalled (type, method);
- if (TypeIsInternal (type) && TypeIsPrivate (type) &&
MemberIsPrivate (method))
- isCalled = PrivateMemberIsCalled (type, method);
- if (TypeIsInternal (type) && !TypeIsPrivate (type) &&
MemberIsInternal (method))
- isCalled = InternalMemberIsCalled (method);
- if (TypeIsInternal (type) && !TypeIsPrivate (type) &&
MemberIsPrivate (method))
- isCalled = PrivateMemberIsCalled (type, method);
- if (!TypeIsInternal (type) && TypeIsPrivate (type) &&
MemberIsInternal (method))
- isCalled = PrivateMemberIsCalled (type, method);
- if (!TypeIsInternal (type) && TypeIsPrivate (type) &&
MemberIsPrivate (method))
- isCalled = PrivateMemberIsCalled (type, method);
- if (!TypeIsInternal (type) && !TypeIsPrivate (type) &&
MemberIsInternal (method))
- isCalled = InternalMemberIsCalled (method);
- if (!TypeIsInternal (type) && !TypeIsPrivate (type) &&
MemberIsPrivate (method))
- isCalled = PrivateMemberIsCalled (type, method);
- if (TypeIsInternal (type) && TypeIsPrivate (type) &&
!MemberIsInternal (method) && !MemberIsPrivate (method))
- isCalled = PrivateMemberIsCalled (type, method);
- if (TypeIsInternal (type) && !TypeIsPrivate (type) &&
!MemberIsInternal (method) && !MemberIsPrivate (method))
- isCalled = InternalMemberIsCalled (method);
- if (!TypeIsInternal (type) && TypeIsPrivate (type) &&
!MemberIsInternal (method) && !MemberIsPrivate (method))
- isCalled = PrivateMemberIsCalled (type, method);
- if (!TypeIsInternal (type) && !TypeIsPrivate (type) &&
!MemberIsInternal (method) && !MemberIsPrivate (method))
- isCalled = true;
-
- return isCalled;
+ return (md.IsStatic && md.IsConstructor);
}
- private bool PrivateMemberIsCalled (TypeDefinition type,
MethodDefinition ToBeCalledMethod)
+ public bool IsEntryPoint (MethodDefinition md)
{
- bool isCalled = false;
-
- foreach (MethodDefinition method in type.Methods)
- if (method.HasBody)
- foreach (Instruction instruction in
method.Body.Instructions)
- if (instruction.Operand != null
&& instruction.Operand.ToString () == ToBeCalledMethod.ToString ())
- isCalled = true;
-
- if (type.NestedTypes.Count > 0)
- foreach (TypeDefinition nestedType in
type.NestedTypes)
- isCalled = PrivateMemberIsCalled
(nestedType, ToBeCalledMethod);
-
- return isCalled;
+ return (md ==
md.DeclaringType.Module.Assembly.EntryPoint);
}
- private bool InternalMemberIsCalled (MethodDefinition
ToBeCalledMethod)
+ public bool IsSerializationConstructor (MethodDefinition md)
{
- bool isCalled = false;
+ if (!md.IsConstructor || (md.Parameters.Count != 2))
+ return false;
- foreach (ModuleDefinition module in
ToBeCalledMethod.DeclaringType.Module.Assembly.Modules)
- foreach (TypeDefinition type in module.Types)
- foreach (MethodDefinition method in
type.Methods)
- if (method.HasBody)
- foreach (Instruction
instruction in method.Body.Instructions)
- if
(instruction.Operand != null && instruction.Operand.ToString () ==
ToBeCalledMethod.ToString ())
-
isCalled = true;
+ if (md.Parameters[0].ParameterType.Name !=
"System.Runtime.Serialization.SerializationInfo")
+ return false;
- return isCalled;
+ return (md.Parameters[1].ParameterType.Name ==
"System.Runtime.Serialization.StreamingContext");
}
- private bool TypeIsInternal (TypeDefinition type)
+ // static [void|int] Main ()
+ // static [void|int] Main (string[] args)
+ public bool IsMain (MethodDefinition md)
{
- bool isInternalType = true;
- string [] modifier = type.Attributes.ToString ().Split
(',');
+ // Main must be static
+ if (!md.IsStatic)
+ return false;
- if (modifier [0] == "NestedAssembly" || modifier [0] ==
"NestedFamANDAssem" || modifier [0] == "NestedFamORAssem")
- isInternalType = true;
- for (int i = 0; i < modifier.Length; i++)
- if (modifier [i] == "Public" || modifier [i] ==
"Private" || modifier [i] == "NestedPublic" || modifier [i] == "NestedPrivate"
|| modifier [i] == "NestedFamily")
- isInternalType = false;
+ if (md.Name != "Main")
+ return false;
- if (isInternalType)
- return isInternalType;
- else if (type.DeclaringType != null)
- isInternalType = TypeIsInternal
(type.DeclaringType as TypeDefinition);
- return isInternalType;
+ // Main must return void or int
+ switch (md.ReturnType.ReturnType.Name) {
+ case "Void":
+ case "Int":
+ // ok, continue checks
+ break;
+ default:
+ return false;
+ }
+
+ switch (md.Parameters.Count) {
+ case 0 :
+ // Main (void)
+ return true;
+ case 1:
+ // Main (string[] args)
+ return (md.Parameters[0].ParameterType.Name ==
"String[]");
+ default:
+ return false;
+ }
}
- private bool TypeIsPrivate (TypeDefinition type)
+ //
+
+ public MessageCollection CheckMethod (MethodDefinition method,
Runner runner)
{
- bool isPrivateType = false;
- string [] modifier = type.Attributes.ToString ().Split
(',');
+ // #1 - rule doesn't apply to static ctor
+ if (IsStaticConstructor (method))
+ return runner.RuleSuccess;
- for (int i = 0; i < modifier.Length; i++)
- if (modifier [i] == "NestedPrivate")
- isPrivateType = true;
+ // #2 - rule doesn't apply if the method is the
assembly entry point
+ if (IsEntryPoint (method))
+ return runner.RuleSuccess;
- if (isPrivateType)
- return isPrivateType;
- else if (type.DeclaringType != null)
- isPrivateType = TypeIsPrivate
(type.DeclaringType as TypeDefinition);
- return isPrivateType;
- }
+ if (IsMain (method))
+ return runner.RuleSuccess;
- private bool MemberIsInternal (MethodDefinition method)
- {
- bool isInternalMember = false;
- string [] modifier = method.Attributes.ToString
().Split (',');
- if (modifier [0] == "Assem")
- isInternalMember = true;
+ // ok, the rule applies
- return isInternalMember;
+ // check if the method is private
+ if (method.IsPrivate) {
+ // then we must check if this type use the
private method
+ if (!CheckTypeForMethodUsage
((method.DeclaringType as TypeDefinition), method)) {
+ Location location = new Location
(method.DeclaringType.FullName, method.Name, 0);
+ Message message = new Message ("The
private method code is not used in it's declaring type.", location,
MessageType.Error);
+ return new MessageCollection (message);
+ }
+ }
+
+ // check if method is internal
+ if (method.IsAssembly) {
+ // then we must check if something in the
assembly is using this method
+ if (!CheckAssemblyForMethodUsage
(method.DeclaringType.Module.Assembly, method)) {
+ Location location = new Location
(method.DeclaringType.FullName, method.Name, 0);
+ Message message = new Message ("The
internal method code is not used in it's declaring assembly.", location,
MessageType.Error);
+ return new MessageCollection (message);
+ }
+ }
+
+ // then method is accessible
+ return runner.RuleSuccess;
}
- private bool MemberIsPrivate (MethodDefinition method)
+ private bool CheckAssemblyForMethodUsage (AssemblyDefinition
ad, MethodDefinition md)
{
- bool isPrivateMember = false;
- string [] modifier = method.Attributes.ToString
().Split (',');
+ // scan each module
+ foreach (ModuleDefinition module in ad.Modules) {
+ // scan each type
+ foreach (TypeDefinition type in module.Types) {
+ if (CheckTypeForMethodUsage (type, md))
+ return true;
+ }
+ }
+ return false;
+ }
- if (modifier [0] == "Private")
- isPrivateMember = true;
-
- return isPrivateMember;
+ private bool CheckTypeForMethodUsage (TypeDefinition td,
MethodDefinition md)
+ {
+ // check every constructor for the type
+ foreach (MethodDefinition ctor in td.Constructors) {
+ // skip ourself
+ if (ctor == md)
+ continue;
+ if (CheckMethodUsage (ctor, md))
+ return true;
+ }
+ // check every method for the type
+ foreach (MethodDefinition method in td.Methods) {
+ // skip check ourself (even with recursion if
no one call us then it's still unused)
+ if (method == md)
+ continue;
+ if (CheckMethodUsage (method, md))
+ return true;
+ }
+ return false;
}
- private bool MemberIsCallable (TypeDefinition type,
MethodDefinition method)
+ private bool CheckMethodUsage (MethodDefinition method,
MethodDefinition md)
{
- bool isCallable = true;
- AssemblyDefinition assemblyDefinition =
method.DeclaringType.Module.Assembly;
+ if (!method.HasBody)
+ return false;
- foreach (CustomAttribute customAttribute in
method.CustomAttributes)
- if
(customAttribute.Constructor.DeclaringType.FullName ==
"System.Runtime.InteropServices.ComRegisterFunctionAttribute" ||
customAttribute.Constructor.DeclaringType.FullName ==
"System.Runtime.InteropServices.ComUnregisterFunctionAttribute")
- isCallable = false;
- if (type.IsInterface)
- isCallable = false;
- if (method.Attributes.ToString () == "Private, Final,
Virtual, HideBySig, NewSlot")
- isCallable = false;
- if (method.IsStatic && method.IsConstructor)
- isCallable = false;
- if (method == assemblyDefinition.EntryPoint)
- isCallable = false;
- if (method.IsConstructor && method.Parameters.Count ==
2)
- if (method.Parameters [0].ParameterType.Name ==
"System.Runtime.Serialization.SerializationInfo" && method.Parameters
[0].ParameterType.Name == "System.Runtime.Serialization.StreamingContext")
- isCallable = false;
- if (method.IsVirtual && !method.IsNewSlot)
- isCallable = false;
-
- return isCallable;
+ foreach (Instruction instruction in
method.Body.Instructions) {
+ if (instruction.Operand == md)
+ return true;
+ if (instruction.OpCode.Code == Code.Callvirt) {
+ foreach (MethodDefinition virtmd in
md.Overrides) {
+ if (instruction.Operand ==
virtmd)
+ return true;
+ }
+ }
+ }
+ return false;
}
}
}
-
\ No newline at end of file
+
Modified: trunk/cecil/gendarme/rules/Gendarme.Rules.Performance/ChangeLog
===================================================================
--- trunk/cecil/gendarme/rules/Gendarme.Rules.Performance/ChangeLog
2007-11-21 17:51:53 UTC (rev 90097)
+++ trunk/cecil/gendarme/rules/Gendarme.Rules.Performance/ChangeLog
2007-11-21 17:55:45 UTC (rev 90098)
@@ -1,3 +1,9 @@
+2007-11-21 Sebastien Pouliot <[EMAIL PROTECTED]>
+
+ * AvoidUncalledPrivateCodeRule.cs: Simplified logic. Avoid using
+ strings. Consider finalizers (since it's normal that they look
+ uncalled). Pass all unit tests under Mono but 3 fails under MS 2.0!
+
2007-11-18 Nestor Salceca <[EMAIL PROTECTED]>
* Gendarme.Rules.Performance.xml.in: Fix the problem closing tag in
_______________________________________________
Mono-patches maillist - [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches