public RuleResult CheckMethod (MethodDefinition method) { // catch abstract, pinvoke and icalls - where rule does not apply if (!method.HasBody) return RuleResult.DoesNotApply; // skip methods without parameters if (!method.HasParameters) return RuleResult.DoesNotApply; // rule doesn't apply to virtual, overrides or generated code // doesn't apply to code referenced by delegates (note: more complex check moved last) if (method.IsVirtual || method.HasOverrides || method.IsGeneratedCode ()) return RuleResult.DoesNotApply; // Also EventArgs parameters are often required in method signatures, // but often not required. Reduce "false positives"(*) for GUI apps // (*) it's more a "don't report things outside developer's control" if (method.IsEventCallback () || IsReferencedByDelegate (method)) return RuleResult.DoesNotApply; // methods with [Conditional] can be empty (not using any parameter) IL-wise but not source-wise, ignore them if (method.HasCustomAttributes) { if (method.CustomAttributes.ContainsType ("System.Diagnostics.ConditionalAttribute")) return RuleResult.DoesNotApply; } // rule applies // we limit ourselves to the first 64 parameters (so we can use a bitmask) IList<ParameterDefinition> pdc = method.Parameters; int pcount = pdc.Count; if (pcount > 64) pcount = 64; ulong mask = 0; // scan IL to see which parameter is being used foreach (Instruction ins in method.Body.Instructions) { ParameterDefinition parameter = ins.GetParameter (method); if (parameter == null) continue; mask |= ((ulong)1 << (parameter.GetSequence () - 1)); } // quick out based on value - i.e. every parameter is being used int shift = 64 - pcount; if ((mask << shift) == (UInt64.MaxValue << shift)) return RuleResult.Success; for (int i = 0; i < pcount; i++) { if ((mask & ((ulong) 1 << i)) == 0) { ParameterDefinition parameter = pdc [i]; string text = String.Format ("Parameter '{0}' of type '{1}' is never used in the method.", parameter.Name, parameter.ParameterType); Runner.Report (parameter, Severity.Medium, Confidence.Normal, text); } } return Runner.CurrentRuleResult; }
public RuleResult CheckMethod (MethodDefinition method) { if (!method.HasBody || !method.HasParameters || method.IsCompilerControlled) return RuleResult.DoesNotApply; if (method.IsProperty () || method.IsGeneratedCode () || method.IsEventCallback ()) return RuleResult.DoesNotApply; // we cannot change parameter types if: // - we're overriding a base virtual method; or // - they were specified by an interface if (IsSignatureDictated (method)) return RuleResult.DoesNotApply; int pcount = method.Parameters.Count; if (pcount > types_least.Length) { // that should be quite rare (does not happen for mono 2.0 class libs) types_least = new TypeReference [pcount]; depths_least = new int [pcount]; } CheckParameters (method); CheckParametersSpecializationDelta (method); Array.Clear (types_least, 0, types_least.Length); Array.Clear (depths_least, 0, depths_least.Length); return Runner.CurrentRuleResult; }
public RuleResult CheckMethod (MethodDefinition method) { // we only check non static, non virtual methods and not constructors if (method.IsStatic || method.IsVirtual || method.IsConstructor) return RuleResult.DoesNotApply; // we only check methods with a body if (!method.HasBody) return RuleResult.DoesNotApply; // we also don't check event callbacks, as they usually bring a lot of false positive, // and that developers are tied to their signature if (method.IsEventCallback ()) return RuleResult.DoesNotApply; // that aren't compiler generated (e.g. anonymous methods) or generated by a tool (e.g. web services) if (method.IsGeneratedCode ()) return RuleResult.DoesNotApply; // methods with [Conditional] can be empty (not using 'this') IL-wise but not source-wise, ignore them if (method.HasCustomAttributes) { if (method.HasAttribute ("System.Diagnostics", "ConditionalAttribute")) return RuleResult.DoesNotApply; } // rule applies // if we find a use of the "this" reference, it's ok // in most (all?) case "this" is used with the ldarg_0 instruction if (OpCodeEngine.GetBitmask (method).Get (Code.Ldarg_0)) return RuleResult.Success; // but it's also valid to have an ldarg with a 0 value operand foreach (Instruction instr in method.Body.Instructions) { if (instr.OpCode.Code == Code.Ldarg) { ParameterDefinition pd = (instr.Operand as ParameterDefinition); if (pd.Index == -1) return RuleResult.Success; } } Runner.Report (method, Severity.Low, Confidence.Total); return RuleResult.Failure; }