private void RemoveObsoleteCodeForArgumentExpression(MethodDefinition method, Collection<Instruction> instructions, TypeDefinition displayClassType) { // Display class is used when there are still calls to load a field from the display class if (instructions.UsesType(displayClassType, OpCodes.Ldfld, OpCodes.Ldftn)) { return; } FodyEnvironment.LogDebug($"Method '{method.GetFullName()}' no longer uses display class '{displayClassType.GetFullName()}', removing the display class from the method"); // Remove display class from container if (method.DeclaringType.NestedTypes.Contains(displayClassType)) { method.DeclaringType.NestedTypes.Remove(displayClassType); } // Remove display class - variables for (var i = 0; i < method.Body.Variables.Count; i++) { var variable = method.Body.Variables[i]; if (string.Equals(variable.VariableType.Name, displayClassType.Name)) { method.Body.Variables.RemoveAt(i--); } } // Remove display class creation, can be either: // // Msbuild // L_0000: newobj instance void Catel.Fody.TestAssembly.ArgumentChecksAsExpressionsClass/<>c__DisplayClass1a::.ctor() // L_0005: stloc.0 // // Roslyn // L_0000: newobj instance void Catel.Fody.TestAssembly.ArgumentChecksAsExpressionsClass/<>c__DisplayClass1a::.ctor() // L_0005: dup for (var i = 0; i < instructions.Count; i++) { var innerInstruction = instructions[i]; if (innerInstruction.OpCode == OpCodes.Newobj) { var remove = false; var methodReference = innerInstruction.Operand as MethodReference; if (methodReference != null) { if (string.Equals(methodReference.DeclaringType.Name, displayClassType.Name)) { remove = true; } } var methodDefinition = innerInstruction.Operand as MethodDefinition; if (methodDefinition != null) { if (string.Equals(methodDefinition.DeclaringType.Name, displayClassType.Name)) { remove = true; } } if (remove) { // Delete 2 instructions, same location since remove will move everything 1 place up instructions.RemoveAt(i); // Special case in .net core if (instructions[i].OpCode == OpCodes.Dup) { instructions.RemoveAt(i); } instructions.RemoveAt(i); } } } //// Remove all assignments to the display class //// ldarg.0 //// stfld class MyClass/<>c__DisplayClass0_0`1<!!T>::myArgument //for (var i = 0; i < instructions.Count; i++) //{ // var innerInstruction = instructions[i]; //} // Remove display class allocation and assigments // L_0014: ldloc.0 (can also be dup) // L_0015: ldarg.3 // L_0016: stfld object Catel.Fody.TestAssembly.ArgumentChecksAsExpressionsClass/<>c__DisplayClass28::myObject3 for (var i = 0; i < instructions.Count; i++) { var innerInstruction = instructions[i]; if (innerInstruction.UsesType(displayClassType, OpCodes.Stfld)) { // Remove the stfld + 2 previous operations instructions.RemoveAt(i); instructions.RemoveAt(i - 1); instructions.RemoveAt(i - 2); i -= 3; } } // Remove duplicate nop instructions at the start of a method if (instructions.Count > 0) { var startInstruction = instructions[0]; if (startInstruction.IsOpCode(OpCodes.Nop)) { instructions.RemoveAt(0); } } }
private void CheckTypeVisibility (TypeDefinition type) { // *NativeMethods types should never be visible outside the assembly if (type.IsVisible ()) { string msg = String.Format (CultureInfo.InvariantCulture, "'{0}' should not be visible outside the assembly.", type.GetFullName ()); Runner.Report (type, Severity.High, Confidence.Total, msg); } if (CanInstantiateType (type)) { string msg = String.Format (CultureInfo.InvariantCulture, "'{0}' should not be static or sealed with no visible constructor.", type.GetFullName ()); Runner.Report (type, Severity.High, Confidence.Total, msg); } }
public RuleResult CheckType (TypeDefinition type) { // rule does not apply to enums, delegates and to generated code if (type.IsEnum || type.IsDelegate () || type.IsGeneratedCode ()) return RuleResult.DoesNotApply; // rule applies only if the type overrides Equals(object) if (!type.HasMethod (MethodSignatures.Equals)) return RuleResult.DoesNotApply; // if so then the type should also implement Equals(type) since this avoid a cast // operation (for reference types) and also boxing (for value types). // we suggest to implement IEquatable<T> if // * the assembly targets the 2.0 (or later) runtime // * and it does not already implement it if (type.Module.Runtime >= TargetRuntime.Net_2_0) { if (!type.Implements ("System", "IEquatable`1")) { Runner.Report (type, Severity.Medium, Confidence.Total, "Implement System.IEquatable<T>"); } return Runner.CurrentRuleResult; } parameters [0] = type.GetFullName (); if (type.GetMethod (MethodAttributes.Public, "Equals", "System.Boolean", parameters) != null) return RuleResult.Success; // we consider this a step more severe for value types since it will need // boxing/unboxing with Equals(object) Severity severity = type.IsValueType ? Severity.Medium : Severity.Low; string msg = String.Format (CultureInfo.InvariantCulture, "Implement 'bool Equals({0})'", type.Name); Runner.Report (type, severity, Confidence.High, msg); return RuleResult.Failure; }