private void CheckForLegalCall (MethodDefinition caller, Instruction ins) { MethodDefinition target = ((MethodReference) ins.Operand).Resolve (); if (target != null) { ThreadModel callerModel = caller.ThreadingModel (); ThreadModel targetModel = target.ThreadingModel (); if (!IsValidCall (callerModel, targetModel)) { string mesg = string.Format ("{0} {1} cannot call {2} {3}.", callerModel, caller.Name, targetModel, target.Name); ++DefectCount; Log.WriteLine (this, "Defect: {0}", mesg); Defect defect = new Defect (this, caller, caller, ins, Severity.High, Confidence.High, mesg); Runner.Report (defect); } } }
public RuleResult CheckMethod (MethodDefinition method) { if (ThreadRocks.ThreadedNamespace (method.DeclaringType.Namespace)) return RuleResult.DoesNotApply; Log.WriteLine (this); Log.WriteLine (this, "---------------------------------------"); Log.WriteLine (this, method); string name = method.Name; IList<ParameterDefinition> pdc = method.HasParameters ? method.Parameters : null; // Finalizers need to be single threaded. ThreadModel model = method.ThreadingModel (); if (method.IsFinalizer ()) { if ((model & ~ThreadModel.AllowEveryCaller) != ThreadModel.SingleThread) { string mesg = "Finalizers should be decorated with [ThreadModel (ThreadModel.SingleThreaded)]."; ReportDefect (method, Severity.High, Confidence.High, mesg); } } // Make sure all of the thread entry points are properly decorated and // that all calls are legit. if (method.HasBody && opcodes_mask.Intersect (OpCodeEngine.GetBitmask (method))) CheckMethodBody (method); // A delegate used with a threaded event must use the same threading model // as the event. if (method.IsAddOn) { ParameterDefinition p = pdc [0]; TypeDefinition delegateType = p.ParameterType.Resolve (); if (delegateType != null && !ThreadRocks.ThreadedNamespace (delegateType.Namespace)) { ThreadModel delegateModel = delegateType.ThreadingModel (); if (model != delegateModel && !delegateModel.AllowsEveryCaller ()) { string mesg = string.Format ("{0} event must match {1} delegate.", model, delegateModel); ReportDefect (method, Severity.High, Confidence.High, mesg); } } } // An override of a base method or an implementation of an interface method // must use the same threading model as the original method. if (method.IsVirtual) { IEnumerable<TypeDefinition> superTypes = method.DeclaringType.AllSuperTypes (); bool new_slot = method.IsNewSlot; superTypes = from s in superTypes where (s.IsInterface == new_slot) select s; string [] parameters = pdc != null ? (from p in pdc.Cast<ParameterDefinition> () select p.ParameterType.FullName).ToArray () : null; foreach (TypeDefinition type in superTypes) { MethodDefinition superMethod = type.GetMethod (name, method.ReturnType.FullName, parameters); if (superMethod != null && !ThreadRocks.ThreadedNamespace (superMethod.DeclaringType.Namespace)) { ThreadModel superModel = superMethod.ThreadingModel (); if (model != superModel) { string mesg = string.Format ("{0} {1} must match {2} {3} method.", model, name, superModel, new_slot ? "interface" : "base"); ReportDefect (method, Severity.High, Confidence.High, mesg); } } } } // Serializable cannot be applied to static methods, but can be applied to // operators because they're just sugar for normal calls. if (method.IsStatic && model.Is (ThreadModel.Serializable) && !name.StartsWith ("op_")) { string mesg = "Static members cannot be decorated with Serializable."; ReportDefect (method, Severity.High, Confidence.High, mesg); } return Runner.CurrentRuleResult; }