public RuleResult CheckMethod (MethodDefinition method)
		{
			// ingore methods without body and generated code
			if (!method.HasBody || method.IsGeneratedCode ())
				return RuleResult.DoesNotApply;

			int num = method.Body.MaxStackSize;
			if (num <= MaximumStackSize)
				return RuleResult.Success;

			string msg = String.Format ("Found {0} maximum stack size (maximum {1}).", num, MaximumStackSize);
			Runner.Report (method, Severity.High, Confidence.High, msg);
			return RuleResult.Failure;
		}
		public RuleResult CheckMethod (MethodDefinition method)
		{
			// rule does not apply to properties, events, without parameters or for generated code
			if (method.IsSpecialName || !method.HasParameters || method.IsGeneratedCode ())
				return RuleResult.DoesNotApply;

			foreach (ParameterDefinition parameter in method.Parameters) {
				if (parameter.ParameterType.FullName != "System.Object&")
					continue;

				// suggest using generics
				Runner.Report (parameter, Severity.Medium, Confidence.High);
			}
			return Runner.CurrentRuleResult;
		}
		public RuleResult CheckMethod (MethodDefinition method)
		{
			// rule only applies if the method has a body
			// rule doesn't not apply to generated code (out of developer's control)
			if (!method.HasBody || method.IsGeneratedCode ())
				return RuleResult.DoesNotApply;

			// check if the method contains a Pop instruction
			if (!OpCodeEngine.GetBitmask (method).Get (Code.Pop))
				return RuleResult.DoesNotApply;

			foreach (Instruction instruction in method.Body.Instructions) {
				if (instruction.OpCode.Code == Code.Pop) {
					CheckForViolation (method, instruction.Previous);
				}
			}
			return Runner.CurrentRuleResult;
		}
		public RuleResult CheckMethod (MethodDefinition method)
		{
			// rule does not apply to properties, events, without parameters or for generated code
			if (method.IsSpecialName || !method.HasParameters || method.IsGeneratedCode ())
				return RuleResult.DoesNotApply;

			// exclude the "bool Try* (ref)" pattern from the rule
			if (method.Name.StartsWith ("Try", StringComparison.Ordinal) && method.ReturnType.IsNamed ("System", "Boolean"))
				return RuleResult.DoesNotApply;

			foreach (ParameterDefinition parameter in method.Parameters) {
				if (!parameter.ParameterType.IsNamed ("System", "Object&"))
					continue;

				// suggest using generics
				Runner.Report (parameter, Severity.Medium, Confidence.High);
			}
			return Runner.CurrentRuleResult;
		}
		public RuleResult CheckMethod (MethodDefinition method)
		{
			// ingore methods without body and generated code
			if (!method.HasBody || method.IsGeneratedCode ())
				return RuleResult.DoesNotApply;

			// special case for System.Windows.Forms since it's designer does not
			// mark this code as generated :-(
			if (method.Name == "InitializeComponent") {
				if (method.DeclaringType.Inherits ("System.Windows.Forms.Form"))
					return RuleResult.DoesNotApply;
			}

			int num = method.Body.Variables.Count;
			if (num <= MaximumVariables)
				return RuleResult.Success;

			string msg = String.Format ("Found {0} local variables (maximum {1}).", num, MaximumVariables);
			Runner.Report (method, Severity.High, Confidence.High, msg);
			return RuleResult.Failure;
		}
		public RuleResult CheckMethod (MethodDefinition method)
		{
			// rule does not apply if there's no IL code
			// or if it was generated by the compiler or tools
			if (!method.HasBody || method.IsGeneratedCode ())
				return RuleResult.DoesNotApply;

			// is there a Newobj *and* a Throw instruction in this method
			if (!bitmask.IsSubsetOf (OpCodeEngine.GetBitmask (method)))
				return RuleResult.DoesNotApply;

			int n = 0;
			bool cond_branch = false;
			foreach (Instruction inst in method.Body.Instructions) {
				// check if the code is linear or with branches
				if (FlowControl.Cond_Branch == inst.OpCode.FlowControl)
					cond_branch = true;

				// if there are branch and it's long enough then assume it is implemented
				if (cond_branch && (++n > 10))
					break;

				// check for "throw new NotImplementedException (...)"
				if (inst.OpCode.Code != Code.Newobj)
					continue;
				MethodReference ctor = (MethodReference) inst.Operand;
				if ("System.NotImplementedException" != ctor.DeclaringType.FullName)
					continue;
				if (inst.Next.OpCode.Code != Code.Throw)
					continue;

				// the defect is more severe if the method is visible outside it's assembly
				Severity severity = method.IsPublic ? Severity.High : Severity.Medium;
				Runner.Report (method, severity, Confidence.Normal);
				return RuleResult.Failure;
			}

			return RuleResult.Success;
		}
예제 #7
0
		public RuleResult CheckMethod (MethodDefinition method)
		{
			// ignore constructors (.ctor or .cctor) and compiler/tool-generated code
			if (method.IsConstructor || method.IsGeneratedCode ())
				return RuleResult.DoesNotApply;

			// don't consider private add / remove on events
			if ((method.IsAddOn || method.IsRemoveOn) && method.IsPrivate)
				return RuleResult.DoesNotApply;

			string name = method.Name;
			MethodSemanticsAttributes attrs = method.SemanticsAttributes;
			if ((attrs & mask) != 0) {
				// it's something special
				int underscore = name.IndexOf ('_');
				if (underscore != -1)
					name = name.Substring (underscore + 1);
			} else if (method.IsSpecialName) {
				return RuleResult.Success;
			}

			// like types, methods/props should all be PascalCased, too
			if (!IsPascalCase (name)) {
				string errorMessage = String.Format ("By existing naming conventions, all the method and property names should all be pascal-cased (e.g. MyOperation). Rename '{0}' to '{1}'.",
					name, PascalCase (name));
				Runner.Report (method, Severity.Medium, Confidence.High, errorMessage);
			}

			// check parameters
			if (method.HasParameters) {
				foreach (ParameterDefinition param in method.Parameters) {
					// params should all be camelCased
					if (!IsCamelCase (param.Name)) {
						string errorMessage = String.Format ("By existing naming conventions, the parameter names should all be camel-cased (e.g. myParameter). Rename '{0}' parameter to '{1}'.",
							param, CamelCase (param.Name));
						Runner.Report (method, Severity.Medium, Confidence.High, errorMessage);
					}
				}
			}

			return Runner.CurrentRuleResult;
		}
		public RuleResult CheckMethod (MethodDefinition method)
		{
			// rule does not apply to external methods (e.g. p/invokes)
			// and generated code (by compilers or tools)
			if (!method.HasBody || method.IsGeneratedCode ())
				return RuleResult.DoesNotApply;

			var variables = method.Body.Variables;
			int count = variables.Count;
			if (count == 0)
				return RuleResult.Success;

			if (used == null) {
				used = new BitArray (Math.Max (DefaultLength, count));
			} else if (count > used.Length) {
				used = new BitArray (count);
			}
			used.SetAll (false);

			foreach (Instruction ins in method.Body.Instructions) {
				VariableDefinition vd = ins.GetVariable (method);
				if (vd != null)
					used [vd.Index] = true;
			}

			for (int i = 0; i < count; i++) {
				if (!used [i]) {
					// sometimes the compilers generates some locals without really
					// using them (e.g. assign only a constant). In this case we need
					// to determine if the variable is "genuine" or a compiler
					// (*) seen in a while (true) loop over a switch
					VariableDefinition variable = variables [i];
					string var_name = variable.Name;
					if (var_name.StartsWith ("V_") || var_name.Contains ("$"))
						continue;

					string s = String.Format ("Variable '{0}' of type '{1}'", 
						var_name, variable.VariableType.FullName);
					Runner.Report (method, Severity.Low, Confidence.Normal, s);
				}
			}

			return Runner.CurrentRuleResult;
		}
예제 #9
0
 // looking for 'protected override void Dispose (bool disposing)' with generated code
 bool IsGeneratedDispose(MethodDefinition method)
 {
     if (!method.IsFamily || !method.IsVirtual || method.IsNewSlot || !method.HasParameters || !method.HasBody)
         return false;
     return ((method.Name == "Dispose") && method.IsGeneratedCode ());
 }
		public RuleResult CheckMethod (MethodDefinition method)
		{
			// exclude constrcutors, non-visible methods and generated code
			if (method.IsConstructor || !method.IsVisible () || method.IsGeneratedCode ())
				return RuleResult.DoesNotApply;

			// the rule does not apply if the code is an interface to COM objects
			if (UsedForComInterop (method.DeclaringType as TypeDefinition))
				return RuleResult.DoesNotApply;

			// check the method name
			if (!CheckName (method.Name, method.IsSpecialName))
				Runner.Report (method, Severity.Medium, Confidence.High);

			if (method.HasParameters) {
				foreach (ParameterDefinition parameter in method.Parameters) {
					if (!CheckName (parameter.Name, false))
						Runner.Report (parameter, Severity.Medium, Confidence.High);
				}
			}

			return Runner.CurrentRuleResult;
		}
		public RuleResult CheckMethod (MethodDefinition method)
		{
			// rule does not apply if 
			// - the method has no body (e.g. p/invokes, icalls don't)
			// - the method is static
			// - the method was generated by the compiler or a tool
			if (!method.HasBody || method.IsStatic || method.IsGeneratedCode ())
				return RuleResult.DoesNotApply;

			// avoid looping if we're sure there's no call in the method
			if (!OpCodeEngine.GetBitmask (method).Get (Code.Stsfld))
				return RuleResult.DoesNotApply;

			// *** ok, the rule applies! ***

			foreach (Instruction ins in method.Body.Instructions) {
				// look for stsfld instructions
				if (ins.OpCode.Code == Code.Stsfld) {
					FieldReference fr = (ins.Operand as FieldReference);
					if (CheckField (fr)) {
						string text = String.Format ("The static field '{0}', of type '{1}'. is being set in an instance method.", fr.Name, fr.FieldType);
						Runner.Report (method, ins, Severity.Medium, Confidence.High, text);
					}
				}
			}

			return Runner.CurrentRuleResult;
		}
		public RuleResult CheckMethod (MethodDefinition method)
		{
			if (!method.HasBody)
				return RuleResult.DoesNotApply;
			
			// Don't want to count the code generated by yield statements.
			if (method.IsGeneratedCode ())
				return RuleResult.DoesNotApply;
			
			if (Preflight (method)) {
				Log.WriteLine (this);
				Log.WriteLine (this, "-----------------------------------------");
				Log.WriteLine (this, method);
				
				call_using_this = false;
				field_access_using_this = false;
				creates_exception = false;
				has_dispose_check = false;
				
				CheckBody (method);
				
				if ((call_using_this || field_access_using_this) && !creates_exception) {
					if (!has_dispose_check) {
						Runner.Report (method, Severity.Medium, Confidence.High);
					}
				}
			}
			
			return Runner.CurrentRuleResult;
		}
		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)
		{
			// rule applies only if the method has generic type parameters
			if (!method.HasGenericParameters || method.IsGeneratedCode ())
				return RuleResult.DoesNotApply;

			// look if every generic type parameter...
			foreach (GenericParameter gp in method.GenericParameters) {
				Severity severity = Severity.Medium;
				bool found = false;
				string nspace = gp.Namespace;
				string name = gp.Name;
				// ... is being used by the method parameters
				foreach (ParameterDefinition pd in method.Parameters) {
					if (IsGenericType (pd.ParameterType, nspace, name)) {
						found = true;
						break;
					}
				}
				if (!found) {
					// it's a defect when used only for the return value - but we reduce its severity
					if (IsGenericType (method.ReturnType, nspace, name))
						severity = Severity.Low;
				}
				if (!found) {
					string msg = String.Format (CultureInfo.InvariantCulture,
						"Generic parameter '{0}' is not used by the method parameters.", name);
					Runner.Report (method, severity, Confidence.High, msg);
				}
			}
			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;
		}
		public RuleResult CheckMethod (MethodDefinition method)
		{
			// rules do not apply to constructors, methods returning an array, properties
			if (method.IsConstructor || method.IsSpecialName)
				return RuleResult.DoesNotApply;

			// we don't apply the rule to overrides since the base method can be
			// outside the developer's control (and if not this is the *one* that
			// should be reported)
			if (method.IsVirtual && !method.IsNewSlot)
				return RuleResult.DoesNotApply;

			// ignore methods returning arrays
			TypeReference return_type = method.ReturnType;
			if (return_type.IsArray)
				return RuleResult.DoesNotApply;

			// rules do not apply to code generated by the compiler (e.g. anonymous methods)
			// or generated by a tool (e.g. web services)
			if (method.IsGeneratedCode ())
				return RuleResult.DoesNotApply;

			string name = method.Name;
			// ignore the some common Get* method names used in the framework
			foreach (string s in whitelist) {
				if (name == s)
					return RuleResult.DoesNotApply;
			}

			// rule applies

			// If it starts with "get" or "is" or "has", has no parameters and returns something
			bool get = name.StartsWith ("get", StringComparison.OrdinalIgnoreCase);
			bool isp = name.StartsWith ("is", StringComparison.OrdinalIgnoreCase);
			bool has = name.StartsWith ("has", StringComparison.OrdinalIgnoreCase);
			if ((get || isp || has) && (method.Parameters.Count == 0) && (return_type.FullName != Void)) {
				// if it's a getter then look for a setter (to complete the report)
				string msg = get ? ReportAssociatedSetter (method) : String.Empty;
				Runner.Report (method, Severity.Low, Confidence.Normal, msg);
				return RuleResult.Failure;
			}

			return RuleResult.Success;
		}
		public RuleResult CheckMethod (MethodDefinition method)
		{
			if (!method.HasBody || method.IsGeneratedCode ())
				return RuleResult.DoesNotApply;

			// is there any Call or Callvirt instructions in the method
			OpCodeBitmask calls = OpCodeBitmask.Calls;
			if (!calls.Intersect (OpCodeEngine.GetBitmask (method)))
				return RuleResult.DoesNotApply;

			foreach (Instruction ins in method.Body.Instructions) {
				if (!calls.Get (ins.OpCode.Code))
					continue;

				MethodReference calledMethod = (MethodReference) ins.Operand;
				if (calledMethod.DeclaringType.FullName != DateTime)
					continue;
				if (!MethodSignatures.op_Subtraction.Matches (calledMethod))
					continue;

				if (CheckUsage (method, ins))
					Runner.Report (method, ins, Severity.Low, Confidence.High);
			}

			return Runner.CurrentRuleResult;
		}
        public RuleResult CheckMethod(MethodDefinition method)
        {
            // rule apply only if the method has a body (e.g. p/invokes, icalls don't)
            if (!method.HasBody || method.IsGeneratedCode ())
                return RuleResult.DoesNotApply;

            // is there any Call or Callvirt instructions in the method
            OpCodeBitmask bitmask = OpCodeEngine.GetBitmask (method);
            if (!OpCodeBitmask.Calls.Intersect (bitmask))
                return RuleResult.DoesNotApply;

            foreach (Instruction ins in method.Body.Instructions) {
                Code code = ins.OpCode.Code;
                if ((code != Code.Call) && (code != Code.Callvirt))
                    continue;

                MethodReference mref = (ins.Operand as MethodReference);

                // covers Equals(string) method and both == != operators
                switch (mref.Name) {
                case "Equals":
                    if (mref.Parameters.Count > 1)
                        continue;
                    TypeReference type = mref.DeclaringType;
                    if (type.Namespace != "System")
                        continue;
                    string name = type.Name;
                    if ((name != "String") && (name != "Object"))
                        continue;
                    break;
                case "op_Equality":
                case "op_Inequality":
                    if (!mref.DeclaringType.IsNamed ("System", "String"))
                        continue;
                    break;
                default:
                    continue;
                }

                Instruction prev = ins.Previous;
                switch (prev.OpCode.Code) {
                case Code.Ldstr:
                    if ((prev.Operand as string).Length > 0)
                        continue;
                    break;
                case Code.Ldsfld:
                    FieldReference field = (prev.Operand as FieldReference);
                    if (!field.DeclaringType.IsNamed ("System", "String"))
                        continue;
                    // unlikely to be anything else (at least with released fx)
                    if (field.Name != "Empty")
                        continue;
                    break;
                default:
                    continue;
                }

                Runner.Report (method, ins, Severity.Medium, Confidence.High);
            }

            return Runner.CurrentRuleResult;
        }
예제 #19
0
		private void CheckMethodBody (MethodDefinition method)
		{
			var synchronizedEvents = new Dictionary<MethodReference, List<MethodReference>> ();
			var thisSynchronized = new List<TypeReference> ();
			
			foreach (Instruction ins in method.Body.Instructions) {
				MethodReference candidate = null;
				
				switch (ins.OpCode.Code) {
				case Code.Newobj:
					if (ins.Previous != null && ins.Previous.OpCode.Code == Code.Ldftn) {
						MethodReference ctor = (MethodReference) ins.Operand;
						TypeReference type = ctor.DeclaringType;
						if (type.IsDelegate ()) {
							string nspace = type.Namespace;
							// ldftn entry-point
							// newobj System.Void System.Threading.XXX::.ctor (System.Object,System.IntPtr)
							// i.e. creation of a System.Threading delegate
							if (nspace == "System.Threading") {
								string name = type.Name;
								if (name == "ThreadStart" ||
									name == "ParameterizedThreadStart" ||
									name == "WaitCallback" ||
									name == "WaitOrTimerCallback" ||
									name == "TimerCallback") {
										candidate = (MethodReference) ins.Previous.Operand;
								}
							
							// ldftn entry-point
							// newobj System.Void System.AsyncCallback::.ctor (System.Object,System.IntPtr)
							// i.e. creation of a async delegate
							} else if (nspace == "System") {
								if (type.Name == "AsyncCallback") {
									candidate = (MethodReference) ins.Previous.Operand;
								}
							
							// ldftn entry-point
							// newobj System.Void ThreadedDelegate::.ctor (System.Object,System.IntPtr)
							// i.e. creation of a delegate which is decorated with a threading attribute
							} else if (!ThreadRocks.ThreadedNamespace (nspace)) {
								// Delegates must be able to call the methods they are bound to.
								MethodDefinition target = ((MethodReference) ins.Previous.Operand).Resolve ();
								if (target != null) {
									ThreadModel callerModel = type.ThreadingModel ();
									if (!target.IsGeneratedCode () || target.IsProperty ()) {
										ThreadModel targetModel = target.ThreadingModel ();
										if (!IsValidCall (callerModel, targetModel)) {
											string mesg = string.Format ("{0} delegate cannot be bound to {1} {2} method.", callerModel, targetModel, target.Name);
											
											++DefectCount;
											Log.WriteLine (this, "Defect: {0}", mesg);
											Defect defect = new Defect (this, method, method, ins, Severity.High, Confidence.High, mesg);
											Runner.Report (defect);
										}
										
									} else if (!callerModel.Is (ThreadModel.MainThread)) {
										anonymous_entry_points.Add (target);
									}
								}
							}
						}
					}
					break;
				
				case Code.Call:
				case Code.Callvirt:
					if (!method.IsGeneratedCode () || method.IsProperty ())
						CheckForLegalCall (method, ins);
					
					// ldftn entry-point
					// newobj XXX
					// callvirt System.Void SynchronizedType::add_Name (XXX)	
					// i.e. adding a delegate to an event in a type which uses SynchronizingObject
					MethodReference call = (MethodReference) ins.Operand;
					TypeReference call_type = call.DeclaringType;
					if (ins.Previous.Is (Code.Newobj) && ins.Previous.Previous.Is (Code.Ldftn)) {
						// A few events are blacklisted because they do not use SynchronizingObject and
						// are therefore always threaded.
						if (IsNonSynchronizedSetter (call)) {
							candidate = (MethodReference) ins.Previous.Previous.Operand;
						
						// But most events do use SynchronizingObject and therefore their threading
						// depends on whether and how SynchronizingObject is initialized.
						} else if (HasSynchronizingObject (call_type)) {
							List<MethodReference> methods;
							if (!synchronizedEvents.TryGetValue (call, out methods)) {
								methods = new List<MethodReference> ();
								synchronizedEvents.Add (call, methods);
							}
							
							methods.AddIfNew ((MethodReference) ins.Previous.Previous.Operand);
						
						// Misc threaded events.
						} else if (call_type.FullName == "System.ComponentModel.BackgroundWorker") {
							if (call.Name == "add_DoWork") {
								candidate = (MethodReference) ins.Previous.Previous.Operand;
							}
						}
					
					// callvirt System.Void System.Diagnostics.Process::set_SynchronizingObject (System.ComponentModel.ISynchronizeInvoke)
					} else if (SetSynchronizingObject.Matches (call)) {
						if (ins.Previous.OpCode.Code == Code.Ldarg_0) {
							thisSynchronized.Add (call_type);
						}
					}
					break;
				}
				
				if (candidate != null) {
					Log.WriteLine (this, "{0} is a thread entry point", candidate);
					CheckEntryPoint (candidate);
				}
			}
			
			// For every method added to a threaded event,
			ThreadModel? method_model = null;
			foreach (KeyValuePair<MethodReference, List<MethodReference>> entry in synchronizedEvents) {
				// if the event is synchronized on this then the target must have the same thread
				// as the current method's type or better and it should not be treated as a entry point.
				if (thisSynchronized.Contains (entry.Key.DeclaringType)) {
					if (method_model == null)
						method_model = method.DeclaringType.ThreadingModel ();
					foreach (MethodReference mr in entry.Value) {
						MethodDefinition target = mr.Resolve ();
						if (target != null) {
							ThreadModel targetModel = target.ThreadingModel ();
							if (!IsValidCall (method_model.Value, targetModel)) {
								string mesg = string.Format ("{0} {1} cannot be bound to {2} {3} method.", method_model, entry.Key, targetModel, target.Name);
								ReportDefect (method, Severity.High, Confidence.High, mesg);
							}
						}
					}
				
				// otherwise the method has to be treated as a thread entry point.
				} else {
					foreach (MethodReference mr in entry.Value) {
						Log.WriteLine (this, "{0} is a thread entry point", mr);
						CheckEntryPoint (mr);
					}
				}
			}
		}
예제 #20
0
		public RuleResult CheckMethod (MethodDefinition method)
		{
			//does rule apply?
			if (!method.HasBody || method.IsGeneratedCode () || method.IsCompilerControlled)
				return RuleResult.DoesNotApply;

			//yay! rule do apply!

			// quick optimization: if the number of instructions is lower
			// than our SuccessThreshold then it cannot be too complex
			if (method.Body.Instructions.Count < SuccessThreshold)
				return RuleResult.Success;

			int cc = GetCyclomaticComplexity (method);
			if (cc < SuccessThreshold)
				return RuleResult.Success;

			//how's severity?
			Severity sev = GetCyclomaticComplexitySeverity(cc);

			Runner.Report (method, sev, Confidence.High, String.Format ("Method's cyclomatic complexity : {0}.", cc));
			return RuleResult.Failure;
		}
		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;
		}
예제 #22
0
		public RuleResult CheckMethod (MethodDefinition method)
		{
			// rule does not apply if method as no code (e.g. abstract, p/invoke)
			// rule does not apply to code outside the developer's control
			// rule does not apply to autogenerated code from some tools
			if (!method.HasBody || method.IsGeneratedCode () || IsAutogeneratedByTools (method))
				return RuleResult.DoesNotApply;

			// rule applies!

			int field_count = 0;
			if (method.IsConstructor)
				field_count = GetFieldCount ((method.DeclaringType as TypeDefinition), method.IsStatic);

			// if we have debugging information available and we're not asked to use IL approximation
			if (!UseIlApproximation && method.DeclaringType.Module.HasSymbols) {
				// add a few extra lines to let the constructors initialize the fields
				int max = MaxSourceLineOfCode + field_count;
				int sloc = CountSourceLinesOfCode (method);
				if (sloc <= max)
					return RuleResult.Success;

				string message = String.Format ("Logical SLOC: {0}. Maximum : {1}", sloc, max);
				Runner.Report (method, Severity.High, Confidence.High, message);
			} else {
				// success if the instruction count is below the defined threshold
				// add a few extra lines to let the constructors initialize the fields
				int max = MaxInstructions + field_count * AssignationRatio;
				int count = CountInstructions (method);
				if (count <= max)
					return RuleResult.Success;

				string message = String.Format ("Method IL Size: {0}. Maximum Size: {1}", count, max);
				Runner.Report (method, Severity.High, Confidence.Normal, message);
			}

			return RuleResult.Failure;
		}
예제 #23
0
		public RuleResult CheckMethod (MethodDefinition method)
		{
			// Check property getters/setters. In order to prevent the property from
			// being reported twice, setters are only checked if the property has no getter.
			PropertyDefinition property = method.IsProperty () ? method.GetPropertyByAccessor () : null;
			if (property != null) {
				// however do not exclude automatic properties (getter/setter marked a generated code)
				if ((method.IsSetter && property.GetMethod != null) || property.IsGeneratedCode ())
					return RuleResult.DoesNotApply;
				if (!IsOkay (property.PropertyType, property.Name))
					Runner.Report (property, Severity.Medium, Confidence.Normal);
			} else {
				// exclude generated code like webservices
				if (method.IsGeneratedCode ())
					return RuleResult.DoesNotApply;

				// Check the method's parameters.
				if (method.HasParameters)
					CheckParameters (method);

				// Check the method's return type.
				if (!IsOkay (method.ReturnType, method.Name))
					Runner.Report (method, Severity.Medium, Confidence.Normal);
			}
			return Runner.CurrentRuleResult;
		}
		public RuleResult CheckMethod (MethodDefinition method)
		{
			// rule does not apply to method without IL (e.g. p/invoke) or generated code (e.g. compiler or tools)
			if (!method.HasBody || method.IsGeneratedCode ())
				return RuleResult.DoesNotApply;

			// avoid looping if we're sure there's no call in the method
			if (!OpCodeBitmask.Calls.Intersect (OpCodeEngine.GetBitmask (method)))
				return RuleResult.DoesNotApply;

			foreach (Instruction ins in method.Body.Instructions) {
				if ((ins.OpCode.Code != Code.Callvirt) && (ins.OpCode.Code != Code.Call))
					continue;

				// look for calls to .Invoke
				MethodReference mr = (ins.Operand as MethodReference);
				if (!MethodSignatures.Invoke.Matches (mr))
					continue;

				// limit ourself to events
				if (!mr.IsEventCallback ())
					continue;

				// first check if we're looking from a variable or directly from 
				// the field (bad, it could be null)
				Instruction caller = ins.TraceBack (method);
				FieldDefinition field = caller.GetField ();
				if (field != null) {
					string msg = String.Format (CultureInfo.InvariantCulture, "Possible race condition since field '{0}' is accessed directly.", field.Name);
					Runner.Report (method, ins, Severity.High, Confidence.High, msg);
				} else {
					// look for the variable, if it's not then stop analysis
					VariableDefinition load = caller.GetVariable (method);
					if ((load != null) && !CheckVariable (method, caller, load)) {
						string msg = String.Format (CultureInfo.InvariantCulture, "Variable '{0}' does not seems to be checked against null.", load.Name);
						Runner.Report (method, ins, Severity.High, Confidence.Normal, msg);
					}
				}
			}

			return Runner.CurrentRuleResult;
		}
		public RuleResult CheckMethod (MethodDefinition method)
		{
			// rule apply only if the method has a body (e.g. p/invokes, icalls don't)
			// and was not generated by the compiler or a tool (outside of developer's control)
			if (!method.HasBody || method.IsGeneratedCode ())
				return RuleResult.DoesNotApply;

			// is there any IsInst or Castclass instructions in the method ?
			if (!Casts.Intersect (OpCodeEngine.GetBitmask (method)))
				return RuleResult.DoesNotApply;

//			Console.WriteLine ();
//			Console.WriteLine ("-----------------------------------------");
//			Console.WriteLine (new MethodPrinter(method));

			foreach (Instruction ins in method.Body.Instructions) {
				Code code = ins.OpCode.Code;
				// IsInst -> if (t is T) ...
				//        -> t = t as T; ...
				// Castclass -> t = (T) t; ...
				if ((code == Code.Isinst) || (code == Code.Castclass))
					casts.Add (ins);
			}

			// if there's only one then it can't be a duplicate cast
			while (casts.Count > 1) {
				Instruction ins = casts [0];
				TypeReference type = (ins.Operand as TypeReference);
				Instruction origin = GetOrigin (ins);

				int count = FindDuplicates (method, type, origin);
				if (count > 1) {
//					Console.WriteLine ("found {0} duplicates for {1:X4}", count, ins.Offset);

					// rare, but it's possible to cast a null value (ldnull)
					object name = origin.GetOperand (method) ?? "Null";
					string msg = String.Format (CultureInfo.InvariantCulture,
						"'{0}' is cast {1} times for type '{2}'.", name, count, type.GetFullName ());
					Runner.Report (method, ins, Severity.Medium, Confidence.Normal, msg);
				}
				casts.RemoveAt (0);
			}
			casts.Clear ();

			return Runner.CurrentRuleResult;
		}
		// note: it's tempting to use IType rule here, since it would avoid iterating
		// all non-constructors methods. However the reporting would be less precise
		// since we want to report which source line inside a ctor is problematic

		public RuleResult CheckMethod (MethodDefinition method)
		{
			if (!method.IsConstructor || !method.HasBody || method.IsGeneratedCode ())
				return RuleResult.DoesNotApply;

			TypeReference type = method.DeclaringType;

			foreach (Instruction ins in method.Body.Instructions) {
				// check for assignation on instance or static fields
				Code code = ins.OpCode.Code;
				bool is_static = (code == Code.Stsfld);
				bool is_instance = (code == Code.Stfld);
				if (!is_static && !is_instance)
					continue;

				// special case: a struct ctor MUST assign every instance fields
				if (type.IsValueType && is_instance)
					continue;

				// make sure we assign to this type (and not another one)
				FieldReference fr = (ins.Operand as FieldReference);
				if (fr.DeclaringType != type)
					continue;

				bool unneeded = false;
				if (fr.FieldType.IsValueType) {
					unneeded = ins.Previous.IsOperandZero ();
				} else {
					unneeded = ins.Previous.OpCode.Code == Code.Ldnull;
				}

				if (unneeded) {
					// we're more confident about the unneeded initialization
					// on static ctor, since another (previous) ctor, can't set
					// the values differently
					Confidence c = method.IsStatic ? Confidence.High : Confidence.Normal;
					Runner.Report (method, ins, Severity.Medium, c, fr.Name);
				}
			}

			return Runner.CurrentRuleResult;
		}
        public RuleResult CheckMethod(MethodDefinition method)
        {
            // applies only to methods with IL that are not generated by the compiler or tools
            if (!method.HasBody || method.IsGeneratedCode ())
                return RuleResult.DoesNotApply;

            // avoid processing methods that do not call any methods
            if (!OpCodeBitmask.Calls.Intersect (OpCodeEngine.GetBitmask (method)))
                return RuleResult.DoesNotApply;

            calls.Clear ();

            foreach (Instruction ins in method.Body.Instructions) {
                MethodReference mr = ins.GetMethod ();
                if ((mr == null) || mr.HasParameters)
                    continue;

                MethodDefinition md = mr.Resolve ();
                // md can be null for things like: new byte[,];
                if ((md == null) || !md.IsGetter)
                    continue;

                if ((!md.IsVirtual || md.IsFinal) && IsInliningCandidate (md))
                    continue;

                // some properties are known, by design, to be called several time
                if (Filter (md))
                    continue;

                string key = GetKey (method, md, ins);

                KeyValuePair<MethodDefinition,int> kvp;
                if (calls.TryGetValue (key, out kvp)) {
                    kvp = new KeyValuePair<MethodDefinition, int> (md, kvp.Value + 1);
                    calls [key] = kvp;
                } else {
                    kvp = new KeyValuePair<MethodDefinition, int> (md, 1);
                    calls.Add (key, kvp);
                }
            }

            return ReportResults (method);
        }
		private static bool IsResource (MethodDefinition method)
		{
			return method.IsStatic && method.IsGetter && method.IsGeneratedCode ();
		}
        public RuleResult CheckMethod(MethodDefinition method)
        {
            if (!method.IsVirtual || !method.HasParameters || method.IsGeneratedCode ())
                return RuleResult.DoesNotApply;

            MethodDefinition baseMethod = null;
            if (!method.IsNewSlot)
                baseMethod = GetBaseMethod (method);
            if (baseMethod == null)
                baseMethod = GetInterfaceMethod (method);
            if (baseMethod == null)
                return RuleResult.Success;

            IList<ParameterDefinition> base_pdc = baseMethod.Parameters;
            //do not trigger false positives on Boo macros
            if (IsBooAssemblyUsingMacro && IsBooMacroParameter (base_pdc [0]))
                return RuleResult.Success;

            IList<ParameterDefinition> pdc = method.Parameters;
            for (int i = 0; i < pdc.Count; i++) {
                if (pdc [i].Name != base_pdc [i].Name) {
                    string s = String.Format (CultureInfo.InvariantCulture,
                        "The name of parameter #{0} ({1}) does not match the name of the parameter in the overriden method ({2}).",
                        i + 1, pdc [i].Name, base_pdc [i].Name);
                    Runner.Report (method, Severity.Medium, Confidence.High, s);
                }
            }
            return Runner.CurrentRuleResult;
        }
		static private bool Applicable (MethodDefinition method)
		{
			// rule doesn't apply to static ctor (called by the runtime)
			if (method.IsStatic && method.IsConstructor)
				return false;

			// don't consider the compiler generated add / remove on events
			if (((method.IsAddOn || method.IsRemoveOn) && method.IsSynchronized))
				return false;

			// rule doesn't apply if the method is the assembly entry point or Main
			if (method.IsEntryPoint () || method.IsMain ())
				return false;

			// rule doesn't apply if the method is generated by the compiler or by a tool
			if (method.IsGeneratedCode ())
				return false;

			// does not apply if the method is used to register/unregister COM objects
			// or it is decorated with a [Conditional("x")] attribute
			if (method.HasCustomAttributes) {
				if (method.CustomAttributes.ContainsAnyType (SpecialAttributes))
					return false;
			}

			return true;
		}