Example #1
0
        protected override void CheckMethod(MethodDefinition method, bool abstractWarning)
        {
            if ((method == null) || !method.HasBody)
            {
                return;
            }

            OpCodeBitmask bitmask = OpCodeEngine.GetBitmask(method);

            // method must have a CALL[VIRT] and either STFLD or STELEM_REF
            if (!bitmask.Intersect(OpCodeBitmask.Calls) || !bitmask.Intersect(StoreFieldBitmask))
            {
                return;
            }

            foreach (Instruction ins in method.Body.Instructions)
            {
                MethodReference mr = (ins.Operand as MethodReference);
                if (mr == null || mr.DeclaringType.IsNative())
                {
                    continue;
                }

                FieldDefinition field = null;
                Instruction     next  = ins.Next;
                if (next.Is(Code.Stfld))
                {
                    field = next.Operand as FieldDefinition;
                }
                else if (next.Is(Code.Stobj) || next.Is(Code.Stind_I))
                {
                    Instruction origin = next.TraceBack(method);
                    if (origin.Is(Code.Ldelema))
                    {
                        origin = origin.TraceBack(method);
                        if (origin != null)
                        {
                            field = origin.Operand as FieldDefinition;
                        }
                    }
                }

                if (field != null && FieldCandidates.Contains(field))
                {
                    Runner.Report(field, Severity.High, Confidence.High,
                                  abstractWarning ? AbstractTypeMessage : TypeMessage);
                }
            }
        }
Example #2
0
        protected override void CheckMethod(MethodDefinition method, bool abstractWarning)
        {
            if ((method == null) || !method.HasBody)
            {
                return;
            }

            OpCodeBitmask bitmask = OpCodeEngine.GetBitmask(method);

            // method must have a NEWOBJ and either STFLD or STELEM_REF
            if (!bitmask.Get(Code.Newobj) || !bitmask.Intersect(StoreFieldBitmask))
            {
                return;
            }

            foreach (Instruction ins in method.Body.Instructions)
            {
                if (!ins.Is(Code.Newobj))
                {
                    continue;
                }

                FieldDefinition field = null;
                Instruction     next  = ins.Next;
                if (next.Is(Code.Stfld))
                {
                    field = next.Operand as FieldDefinition;
                }
                else if (next.Is(Code.Stelem_Ref))
                {
                    Instruction origin = next.TraceBack(method);
                    if (origin != null)
                    {
                        field = origin.Operand as FieldDefinition;
                    }
                }

                if (field != null && FieldCandidates.Contains(field))
                {
                    Runner.Report(field, Severity.High, Confidence.High,
                                  abstractWarning ? AbstractTypeMessage : TypeMessage);
                }
            }
        }
        public RuleResult CheckType(TypeDefinition type)
        {
            // that will cover interfaces, delegates too
            if (!type.HasFields)
            {
                return(RuleResult.DoesNotApply);
            }

            // rule doesn't apply to enums, interfaces, structs, delegates or generated code
            if (type.IsEnum || type.IsValueType || type.IsGeneratedCode())
            {
                return(RuleResult.DoesNotApply);
            }

            MethodDefinition explicitDisposeMethod = null;
            MethodDefinition implicitDisposeMethod = null;

            bool abstractWarning = false;

            if (type.Implements("System", "IDisposable"))
            {
                implicitDisposeMethod = type.GetMethod(MethodSignatures.Dispose);
                explicitDisposeMethod = type.GetMethod(MethodSignatures.DisposeExplicit);

                if (IsAbstract(implicitDisposeMethod) || IsAbstract(explicitDisposeMethod))
                {
                    abstractWarning = true;
                }
                else
                {
                    return(RuleResult.Success);
                }
            }

            FieldCandidates.Clear();

            foreach (FieldDefinition field in type.Fields)
            {
                // we can't dispose static fields in IDisposable
                if (field.IsStatic)
                {
                    continue;
                }
                TypeDefinition fieldType = field.FieldType.GetElementType().Resolve();
                if (fieldType == null)
                {
                    continue;
                }
                if (FieldTypeIsCandidate(fieldType))
                {
                    FieldCandidates.Add(field);
                }
            }

            // if there are fields types that implements IDisposable
            if (type.HasMethods && (FieldCandidates.Count > 0))
            {
                // check if we're assigning new object to them
                foreach (MethodDefinition method in type.Methods)
                {
                    CheckMethod(method, abstractWarning);
                }
            }

            // Warn about possible confusion if the Dispose methods are abstract
            if (IsAbstract(implicitDisposeMethod))
            {
                Runner.Report(implicitDisposeMethod, Severity.Medium, Confidence.High, AbstractDisposeMessage);
            }

            return(Runner.CurrentRuleResult);
        }