private IEnumerable <Instruction> Sources(Instruction instruction, CFG cdfg) { switch (instruction.Operation.OperationCode) { case OperationCode.Newobj: var constructorReference = instruction.Operation.Value as IMethodReference; var type = constructorReference.ContainingType; if (constructorReference != null && !type.IsCompilerGenerated() && IsDisposableType(type)) { yield return(instruction); // produces the source object } break; case OperationCode.Call: case OperationCode.Callvirt: var methodRef = instruction.Operation.Value as IMethodReference; if (methodRef != null) { if (methodRef != null && !methodRef.IsGetter()) { if (!methodRef.Type.IsCompilerGenerated() && IsDisposableType(methodRef.Type)) { yield return(instruction); // produces the source object } var args = instruction.Operand2 as Instruction[]; if (args != null) { foreach (var p in methodRef.Parameters) { if (p.IsByReference && !p.Type.IsCompilerGenerated() && IsDisposableType(p.Type) && p.Index < args.Length) { var arg = args[p.Index]; if (arg != null) { var loc = cdfg.LocalOrParameter(arg); var pseudoDef = instruction[loc]; if (pseudoDef != null) { yield return(pseudoDef); } } } } } } } break; } }
private IEnumerable <Instruction> Sinks(BasicBlock <Instruction> block, Instruction instruction, CFG cdfg) { switch (instruction.Operation.OperationCode) { case OperationCode.Call: case OperationCode.Callvirt: { var methodRef = instruction.Operation.Value as IMethodReference; if (methodRef != null) { if (IsDisposeMethod(methodRef)) { var constraint = block.CallConstraint(instruction); if (methodRef.ContainingType.IsValueType || constraint != null && (constraint.IsValueType || constraint is IGenericParameter)) { // passing the address, figure out what local var loc = cdfg.LocalOrParameter(instruction.Operand1); var toDispose = instruction[loc]; yield return(toDispose); } else { yield return(instruction.Operand1); // consumes the "this" parameter } } var args = instruction.Operand2 as Instruction[]; if (args != null) { foreach (var p in methodRef.Parameters) { if (p.IsByReference && IsDisposableType(p.Type) && p.Index < args.Length || PassingObligationTo(methodRef, p)) { var arg = args[p.Index]; if (arg != null) { yield return(arg); } } } } } break; } case OperationCode.Stfld: // consider fields escaping yield return(instruction.Operand2 as Instruction); break; case OperationCode.Stsfld: // consider fields escaping yield return(instruction.Operand1); break; case OperationCode.Ret: if (instruction.Operand1 != null && IsDisposableType(this.currentMethod.Type)) { yield return(instruction.Operand1); // consumes the returned value } // by ref parameters are also sinks foreach (var p in this.currentMethod.Parameters) { Instruction finalParameterValue; if ((p.IsByReference || p.IsOut) && IsDisposableType(p.Type) && instruction.PostParamDefs != null && instruction.PostParamDefs.TryGetValue(p, out finalParameterValue)) { yield return(finalParameterValue); } } break; } }