private static bool IsBaseFinalizeCalled(MethodDefinition finalizer) { if (!OpCodeBitmask.Calls.Intersect(OpCodeEngine.GetBitmask(finalizer))) { return(false); } foreach (Instruction current in finalizer.Body.Instructions) { switch (current.OpCode.Code) { case Code.Call: case Code.Callvirt: MethodReference mr = (current.Operand as MethodReference); if ((mr != null) && mr.IsFinalizer()) { return(true); } break; } } return(false); }
public RuleResult CheckType(TypeDefinition type) { // rule applies only to type with a finalizer MethodDefinition finalizer = type.GetMethod(MethodSignatures.Finalize); if (finalizer == null) { return(RuleResult.DoesNotApply); } // rule applies // finalizer is present, look if it has any code within it // i.e. look if is does anything else than calling it's base class int nullify_fields = 0; foreach (Instruction ins in finalizer.Body.Instructions) { switch (ins.OpCode.Code) { case Code.Call: case Code.Callvirt: // it's empty if we're calling the base class finalizer MethodReference mr = (ins.Operand as MethodReference); if ((mr == null) || !mr.IsFinalizer()) { return(RuleResult.Success); } break; case Code.Nop: case Code.Leave: case Code.Leave_S: case Code.Ldarg_0: case Code.Endfinally: case Code.Ret: case Code.Ldnull: // ignore break; case Code.Stfld: // considered as empty as long as it's only to nullify them if (ins.Previous.OpCode.Code == Code.Ldnull) { nullify_fields++; continue; } return(RuleResult.Success); default: // finalizer isn't empty (normal) return(RuleResult.Success); } } // finalizer is empty (bad / useless) string msg = nullify_fields == 0 ? String.Empty : String.Format(CultureInfo.InvariantCulture, "Contains {0} fields being nullified needlessly", nullify_fields); Runner.Report(type, Severity.Medium, Confidence.Normal, msg); return(RuleResult.Failure); }