public static MethodContract /*?*/ ExtractContracts(IContractAwareHost contractAwareHost, PdbReader /*?*/ pdbReader, ContractExtractor extractor, ISourceMethodBody methodBody) { var definingUnit = TypeHelper.GetDefiningUnit(methodBody.MethodDefinition.ContainingType.ResolvedType); var methodIsInReferenceAssembly = ContractHelper.IsContractReferenceAssembly(contractAwareHost, definingUnit); var oldAndResultExtractor = new OldAndResultExtractor(contractAwareHost, methodBody, extractor.IsContractMethod); var localsInitializedWithFields = FindLocals.FindSetOfLocals(methodBody); var har = new HermansAlwaysRight(contractAwareHost, extractor, methodBody, methodIsInReferenceAssembly, oldAndResultExtractor, pdbReader); har.Rewrite(methodBody); if (har.extractor.currentMethodContract == null) { return(null); } // The decompiler will have introduced locals if there were any anonymous delegates in the contracts // Such locals are initialized with the fields of the iterator class. // The contract that comes back from here will have those fields replaced with whatever the iterator captured // (parameters, locals). So the locals in the contract need to be replaced with the iterator fields so that // next replacement will see the right thing (i.e., the fields) and replace them! Phew! var localReplacer = new LocalReplacer(contractAwareHost, localsInitializedWithFields); localReplacer.Rewrite(har.extractor.currentMethodContract); // also need to rewrite the remainder of the body localReplacer.Rewrite(methodBody); return(har.extractor.currentMethodContract); }
private HermansAlwaysRight(IContractAwareHost contractAwareHost, ContractExtractor extractor, ISourceMethodBody sourceMethodBody, bool methodIsInReferenceAssembly, OldAndResultExtractor oldAndResultExtractor, PdbReader /*?*/ pdbReader) : base(contractAwareHost) { this.contractAwareHost = contractAwareHost; this.extractor = extractor; this.sourceMethodBody = sourceMethodBody; this.methodIsInReferenceAssembly = methodIsInReferenceAssembly; this.oldAndResultExtractor = oldAndResultExtractor; this.pdbReader = pdbReader; }
private IUnit unit; // the module this is a lazy provider for /// <summary> /// Allocates an object that can be used to query for contracts by asking questions about specific methods/types, etc. /// </summary> /// <param name="host">The host that loaded the unit for which this is to be a contract provider.</param> /// <param name="unit">The unit to retrieve the contracts from.</param> /// <param name="contractMethods">A collection of methods that can be called in a way that provides tools with information about contracts.</param> /// <param name="usePdb">Whether to use the PDB file (and possibly the source files if available) during extraction.</param> public LazyContractExtractor(IContractAwareHost host, IUnit unit, IContractMethods contractMethods, bool usePdb) { this.host = host; this.underlyingContractProvider = new ContractProvider(contractMethods, unit); if (usePdb) { string pdbFile = Path.ChangeExtension(unit.Location, "pdb"); if (File.Exists(pdbFile)) { using (var pdbStream = File.OpenRead(pdbFile)) { this.pdbReader = new PdbReader(pdbStream, host); } } } this.unit = unit; }
// TODO: First search the moveNextBody to see if there are any contracts at all. /// <summary> /// /// </summary> /// <param name="host"></param> /// <param name="extractor"></param> /// <param name="iteratorMethodBody"></param> /// <param name="moveNextBody"></param> /// <param name="pdbReader"></param> /// <returns></returns> public static MethodContract GetMethodContractFromMoveNext( IContractAwareHost host, ContractExtractor extractor, ISourceMethodBody iteratorMethodBody, ISourceMethodBody moveNextBody, PdbReader pdbReader ) { // Walk the iterator method and collect all of the state that is assigned to fields in the iterator class // That state needs to replace any occurrences of the fields in the contracts (if they exist...) var iteratorStmts = new List <IStatement>(iteratorMethodBody.Block.Statements); Dictionary <uint, IExpression> capturedThings = new Dictionary <uint, IExpression>(); // Find all of the state captured for the IEnumerable // REVIEW: Is this state ever used in the contracts? Since they're all sitting in the MoveNext // method, maybe they always use the IEnumerator state? if (1 < iteratorStmts.Count) { // First statement should be the creation of the iterator class int j = 1; while (j < iteratorStmts.Count) { var es = iteratorStmts[j++] as IExpressionStatement; if (es == null) { break; } var assign = es.Expression as IAssignment; if (assign == null) { break; } var field = assign.Target.Definition as IFieldReference; var capturedThing = assign.Source; var k = field.InternedKey; var spec = field as ISpecializedFieldReference; if (spec != null) { k = spec.UnspecializedVersion.InternedKey; } capturedThings.Add(k, capturedThing); } } else { var ret = iteratorStmts[0] as IReturnStatement; if (ret != null) { var be = ret.Expression as IBlockExpression; if (be != null) { var beStmts = new List <IStatement>(be.BlockStatement.Statements); var j = 1; while (j < beStmts.Count) { var es = beStmts[j++] as IExpressionStatement; if (es == null) { break; } var assign = es.Expression as IAssignment; if (assign == null) { break; } var field = assign.Target.Definition as IFieldReference; var capturedThing = assign.Source; var k = field.InternedKey; var spec = field as ISpecializedFieldReference; if (spec != null) { k = spec.UnspecializedVersion.InternedKey; } capturedThings.Add(k, capturedThing); } } } } // Find all of the state captured for the IEnumerator // That state is captured at the beginning of the IEnumerable<T>.GetEnumerator method IMethodDefinition getEnumerator = null; var t = moveNextBody.MethodDefinition.ContainingTypeDefinition; foreach (IMethodImplementation methodImplementation in t.ExplicitImplementationOverrides) { if (methodImplementation.ImplementedMethod.Name == host.NameTable.GetNameFor("GetEnumerator")) { var gtir = methodImplementation.ImplementedMethod.ContainingType as IGenericTypeInstanceReference; if (gtir != null && TypeHelper.TypesAreEquivalent(gtir.GenericType, host.PlatformType.SystemCollectionsGenericIEnumerable)) { getEnumerator = methodImplementation.ImplementingMethod.ResolvedMethod as IMethodDefinition; break; } } } if (getEnumerator != null) { IMethodBody geBody = getEnumerator.Body; var sourceGeBody = geBody as ISourceMethodBody; if (sourceGeBody == null) { sourceGeBody = Decompiler.GetCodeModelFromMetadataModel(host, geBody, pdbReader, DecompilerOptions.AnonymousDelegates); } foreach (var stmt in sourceGeBody.Block.Statements) { var es = stmt as IExpressionStatement; if (es == null) { continue; } var assign = es.Expression as IAssignment; if (assign == null) { continue; } var field2 = assign.Target.Definition as IFieldReference; if (field2 == null) { continue; } var k = field2.InternedKey; var spec = field2 as ISpecializedFieldReference; if (spec != null) { k = spec.UnspecializedVersion.InternedKey; } var sourceBe = assign.Source as IBoundExpression; if (sourceBe == null) { continue; } var field3 = sourceBe.Definition as IFieldReference; if (field3 == null) { continue; } var k3 = field3.InternedKey; var spec3 = field3 as ISpecializedFieldReference; if (spec3 != null) { k3 = spec3.UnspecializedVersion.InternedKey; } IExpression capturedThing = null; if (!capturedThings.TryGetValue(k3, out capturedThing)) { continue; } capturedThings[k] = capturedThing; } } var mc = HermansAlwaysRight.ExtractContracts(host, pdbReader, extractor, moveNextBody); if (mc == null) { return(mc); } // substitute all field references in contract with the captured state var replacer = new Replacer(host, capturedThings, iteratorMethodBody.MethodDefinition, moveNextBody.MethodDefinition); replacer.RewriteChildren(mc); if (moveNextBody.MethodDefinition.ContainingTypeDefinition.IsGeneric) { var genericParameterMapper = new GenericMethodParameterMapper(host, iteratorMethodBody.MethodDefinition, moveNextBody.MethodDefinition.ContainingType as INestedTypeReference); mc = genericParameterMapper.Rewrite(mc) as MethodContract; } return(mc); }
public CciQueryGenerator() { host = CciHostEnvironment.GetInstance(); }
private IUnit unit; // the module this is a lazy provider for #endregion Fields #region Constructors /// <summary> /// Allocates an object that can be used to query for contracts by asking questions about specific methods/types, etc. /// </summary> /// <param name="host">The host that loaded the unit for which this is to be a contract provider.</param> /// <param name="unit">The unit to retrieve the contracts from.</param> /// <param name="contractMethods">A collection of methods that can be called in a way that provides tools with information about contracts.</param> /// <param name="usePdb">Whether to use the PDB file (and possibly the source files if available) during extraction.</param> public LazyContractExtractor(IContractAwareHost host, IUnit unit, IContractMethods contractMethods, bool usePdb) { this.host = host; this.underlyingContractProvider = new ContractProvider(contractMethods, unit); if (usePdb) { string pdbFile = Path.ChangeExtension(unit.Location, "pdb"); if (File.Exists(pdbFile)) { using (var pdbStream = File.OpenRead(pdbFile)) { this.pdbReader = new PdbReader(pdbStream, host); } } } this.unit = unit; }
protected CciActionQueryGenerator(IContractAwareHost host) { this.host = host; }
/// <summary> /// Returns a method contract containing the 'effective' contract for the given /// method definition. The effective contract contains all contracts for the method: /// any that it has on its own, as well as all those inherited from any methods /// that it overrides or interface methods that it implements (either implicitly /// or explicitly). /// All parameters in inherited contracts are substituted for by /// the method's own parameters. /// If there are no contracts, then it returns null. /// Any preconditions that were written as legacy-preconditions or calls to Requires<E> are /// included iff <paramref name="keepLegacyPreconditions"/>. /// </summary> public static IMethodContract GetMethodContractForIncludingInheritedContracts(IContractAwareHost host, IMethodDefinition methodDefinition, bool keepLegacyPreconditions = true) { MethodContract cumulativeContract = new MethodContract(); bool atLeastOneContract = false; IMethodContract/*?*/ mc = ContractHelper.GetMethodContractFor(host, methodDefinition); if (mc != null) { Microsoft.Cci.MutableContracts.ContractHelper.AddMethodContract(cumulativeContract, mc); atLeastOneContract = true; } #region Overrides of base class methods if (!methodDefinition.IsNewSlot) { // REVIEW: Is there a better test? IMethodDefinition overriddenMethod = MemberHelper.GetImplicitlyOverriddenBaseClassMethod(methodDefinition) as IMethodDefinition; while (overriddenMethod != null && !(overriddenMethod is Dummy)) { IMethodContract/*?*/ overriddenContract = ContractHelper.GetMethodContractFor(host, overriddenMethod); if (overriddenContract != null) { overriddenContract = CopyContractIntoNewContext(host, overriddenContract, methodDefinition, overriddenMethod); overriddenContract = FilterUserMessageAndLegacyPreconditions(host, overriddenContract, methodDefinition.ContainingTypeDefinition, keepLegacyPreconditions); // if the method is generic, then need to specialize the contract to have the same method type parameters as the method if (methodDefinition.IsGeneric) { var d = new Dictionary<uint, ITypeReference>(); IteratorHelper.Zip(overriddenMethod.GenericParameters, methodDefinition.GenericParameters, (i, j) => d.Add(i.InternedKey, j)); var cs = new CodeSpecializer(host, d); overriddenContract = cs.Rewrite(overriddenContract); } Microsoft.Cci.MutableContracts.ContractHelper.AddMethodContract(cumulativeContract, overriddenContract); atLeastOneContract = true; } overriddenMethod = MemberHelper.GetImplicitlyOverriddenBaseClassMethod(overriddenMethod) as IMethodDefinition; } } #endregion Overrides of base class methods #region Implicit interface implementations foreach (IMethodDefinition ifaceMethod in ContractHelper.GetAllImplicitlyImplementedInterfaceMethods(methodDefinition)) { IMethodContract/*?*/ ifaceContract = ContractHelper.GetMethodContractFor(host, ifaceMethod); if (ifaceContract == null) continue; ifaceContract = CopyContractIntoNewContext(host, ifaceContract, methodDefinition, ifaceMethod); ifaceContract = FilterUserMessageAndLegacyPreconditions(host, ifaceContract, methodDefinition.ContainingTypeDefinition, keepLegacyPreconditions); Microsoft.Cci.MutableContracts.ContractHelper.AddMethodContract(cumulativeContract, ifaceContract); atLeastOneContract = true; } #endregion Implicit interface implementations #region Explicit interface implementations and explicit method overrides foreach (IMethodReference ifaceMethodRef in MemberHelper.GetExplicitlyOverriddenMethods(methodDefinition)) { IMethodDefinition/*?*/ ifaceMethod = ifaceMethodRef.ResolvedMethod; if (ifaceMethod == null) continue; IMethodContract/*?*/ ifaceContract = ContractHelper.GetMethodContractFor(host, ifaceMethod); if (ifaceContract == null) continue; ifaceContract = CopyContractIntoNewContext(host, ifaceContract, methodDefinition, ifaceMethod); ifaceContract = FilterUserMessageAndLegacyPreconditions(host, ifaceContract, methodDefinition.ContainingTypeDefinition, keepLegacyPreconditions); Microsoft.Cci.MutableContracts.ContractHelper.AddMethodContract(cumulativeContract, ifaceContract); atLeastOneContract = true; } #endregion Explicit interface implementations and explicit method overrides return atLeastOneContract ? cumulativeContract : null; }
// TODO: First search the moveNextBody to see if there are any contracts at all. /// <summary> /// /// </summary> /// <param name="host"></param> /// <param name="extractor"></param> /// <param name="iteratorMethodBody"></param> /// <param name="moveNextBody"></param> /// <param name="pdbReader"></param> /// <returns></returns> public static MethodContract GetMethodContractFromMoveNext( IContractAwareHost host, ContractExtractor extractor, ISourceMethodBody iteratorMethodBody, ISourceMethodBody moveNextBody, PdbReader pdbReader ) { // Walk the iterator method and collect all of the state that is assigned to fields in the iterator class // That state needs to replace any occurrences of the fields in the contracts (if they exist...) var iteratorStmts = new List<IStatement>(iteratorMethodBody.Block.Statements); Dictionary<uint, IExpression> capturedThings = new Dictionary<uint, IExpression>(); // Find all of the state captured for the IEnumerable // REVIEW: Is this state ever used in the contracts? Since they're all sitting in the MoveNext // method, maybe they always use the IEnumerator state? if (1 < iteratorStmts.Count) { // First statement should be the creation of the iterator class int j = 1; while (j < iteratorStmts.Count) { var es = iteratorStmts[j++] as IExpressionStatement; if (es == null) break; var assign = es.Expression as IAssignment; if (assign == null) break; var field = assign.Target.Definition as IFieldReference; var capturedThing = assign.Source; var k = field.InternedKey; var spec = field as ISpecializedFieldReference; if (spec != null) k = spec.UnspecializedVersion.InternedKey; capturedThings.Add(k, capturedThing); } } else { var ret = iteratorStmts[0] as IReturnStatement; if (ret != null) { var be = ret.Expression as IBlockExpression; if (be != null) { var beStmts = new List<IStatement>(be.BlockStatement.Statements); var j = 1; while (j < beStmts.Count) { var es = beStmts[j++] as IExpressionStatement; if (es == null) break; var assign = es.Expression as IAssignment; if (assign == null) break; var field = assign.Target.Definition as IFieldReference; var capturedThing = assign.Source; var k = field.InternedKey; var spec = field as ISpecializedFieldReference; if (spec != null) k = spec.UnspecializedVersion.InternedKey; capturedThings.Add(k, capturedThing); } } } } // Find all of the state captured for the IEnumerator // That state is captured at the beginning of the IEnumerable<T>.GetEnumerator method IMethodDefinition getEnumerator = null; var t = moveNextBody.MethodDefinition.ContainingTypeDefinition; foreach (IMethodImplementation methodImplementation in t.ExplicitImplementationOverrides) { if (methodImplementation.ImplementedMethod.Name == host.NameTable.GetNameFor("GetEnumerator")) { var gtir = methodImplementation.ImplementedMethod.ContainingType as IGenericTypeInstanceReference; if (gtir != null && TypeHelper.TypesAreEquivalent(gtir.GenericType, host.PlatformType.SystemCollectionsGenericIEnumerable)) { getEnumerator = methodImplementation.ImplementingMethod.ResolvedMethod as IMethodDefinition; break; } } } if (getEnumerator != null) { IMethodBody geBody = getEnumerator.Body; var sourceGeBody = geBody as ISourceMethodBody; if (sourceGeBody == null) sourceGeBody = Decompiler.GetCodeModelFromMetadataModel(host, geBody, pdbReader, DecompilerOptions.AnonymousDelegates); foreach (var stmt in sourceGeBody.Block.Statements) { var es = stmt as IExpressionStatement; if (es == null) continue; var assign = es.Expression as IAssignment; if (assign == null) continue; var field2 = assign.Target.Definition as IFieldReference; if (field2 == null) continue; var k = field2.InternedKey; var spec = field2 as ISpecializedFieldReference; if (spec != null) k = spec.UnspecializedVersion.InternedKey; var sourceBe = assign.Source as IBoundExpression; if (sourceBe == null) continue; var field3 = sourceBe.Definition as IFieldReference; if (field3 == null) continue; var k3 = field3.InternedKey; var spec3 = field3 as ISpecializedFieldReference; if (spec3 != null) k3 = spec3.UnspecializedVersion.InternedKey; IExpression capturedThing = null; if (!capturedThings.TryGetValue(k3, out capturedThing)) continue; capturedThings[k] = capturedThing; } } var mc = HermansAlwaysRight.ExtractContracts(host, pdbReader, extractor, moveNextBody); if (mc == null) return mc; // substitute all field references in contract with the captured state var replacer = new Replacer(host, capturedThings, iteratorMethodBody.MethodDefinition, moveNextBody.MethodDefinition); replacer.RewriteChildren(mc); if (moveNextBody.MethodDefinition.ContainingTypeDefinition.IsGeneric) { var genericParameterMapper = new GenericMethodParameterMapper(host, iteratorMethodBody.MethodDefinition, moveNextBody.MethodDefinition.ContainingType as INestedTypeReference); mc = genericParameterMapper.Rewrite(mc) as MethodContract; } return mc; }
internal SeparateContractsFromCode(IContractAwareHost host, PdbReader/*?*/ pdbReader, ILocalScopeProvider/*?*/ localScopeProvider, ContractProvider contractProvider) { this.contractAwareHost = host; this.pdbReader = pdbReader; this.localScopeProvider = localScopeProvider; this.contractProvider = contractProvider; this.TraverseIntoMethodBodies = true; }
/// <summary> /// Given a mutable module that is a "declarative" module, i.e., it has contracts expressed as contract calls /// at the beginning of method bodies, this method will extract them, leaving the method bodies without those /// calls and return a contract provider for the module containing any extracted contracts. /// </summary> public static ContractProvider ExtractContracts(IContractAwareHost host, Module module, PdbReader/*?*/ pdbReader, ILocalScopeProvider/*?*/ localScopeProvider) { var contractMethods = new ContractMethods(host); var cp = new Microsoft.Cci.MutableContracts.ContractProvider(contractMethods, module); var extractor = new SeparateContractsFromCode(host, pdbReader, localScopeProvider, cp); extractor.Traverse(module); return cp; }
private static List<IThrownException> FilterUserMessage(IContractAwareHost host, IEnumerable<IThrownException> thrownExceptions, ITypeDefinition typeDefinition) { int n = (int)IteratorHelper.EnumerableCount(thrownExceptions); var filteredThrownExceptions = new IThrownException[n]; var i = 0; foreach (var te in thrownExceptions) { if (CanAccess(te.Postcondition.Description, typeDefinition)) { filteredThrownExceptions[i] = te; } else { var newP = new Postcondition(te.Postcondition); newP.Description = null; filteredThrownExceptions[i] = new ThrownException() { ExceptionType = te.ExceptionType, Postcondition = newP, }; } i++; } return new List<IThrownException>(filteredThrownExceptions); }
private static List<IPrecondition> FilterUserMessageAndLegacyPreconditions(IContractAwareHost host, IEnumerable<IPrecondition> preconditions, ITypeDefinition typeDefinition, bool keepLegacy) { var filteredPreconditions = new List<IPrecondition>(); foreach (var p in preconditions) { if (!keepLegacy && p.ExceptionToThrow != null) continue; if (CanAccess(p.Description, typeDefinition)) { filteredPreconditions.Add(p); } else { var newP = new Precondition(p); newP.Description = null; filteredPreconditions.Add(newP); } } return filteredPreconditions; }
private static List<IPostcondition> FilterUserMessage(IContractAwareHost host, IEnumerable<IPostcondition> postconditions, ITypeDefinition typeDefinition) { int n = (int)IteratorHelper.EnumerableCount(postconditions); var filteredPostconditions = new IPostcondition[n]; var i = 0; foreach (var p in postconditions) { if (CanAccess(p.Description, typeDefinition)) { filteredPostconditions[i] = p; } else { var newP = new Postcondition(p); newP.Description = null; filteredPostconditions[i] = newP; } i++; } return new List<IPostcondition>(filteredPostconditions); }
private static MethodContract FilterUserMessageAndLegacyPreconditions(IContractAwareHost host, IMethodContract contract, ITypeDefinition typeDefinition, bool keepLegacy) { var mc = new MethodContract(contract); mc.Postconditions = FilterUserMessage(host, contract.Postconditions, typeDefinition); mc.Preconditions = FilterUserMessageAndLegacyPreconditions(host, contract.Preconditions, typeDefinition, keepLegacy); mc.ThrownExceptions = FilterUserMessage(host, contract.ThrownExceptions, typeDefinition); return mc; }
private HermansAlwaysRight(IContractAwareHost contractAwareHost, ContractExtractor extractor, ISourceMethodBody sourceMethodBody, bool methodIsInReferenceAssembly, OldAndResultExtractor oldAndResultExtractor, PdbReader/*?*/ pdbReader) : base(contractAwareHost) { this.contractAwareHost = contractAwareHost; this.extractor = extractor; this.sourceMethodBody = sourceMethodBody; this.methodIsInReferenceAssembly = methodIsInReferenceAssembly; this.oldAndResultExtractor = oldAndResultExtractor; this.pdbReader = pdbReader; }
public Traverser(IContractAwareHost host, bool showInherited) { this.host = host; this.showInherited = showInherited; }
public static MethodContract/*?*/ ExtractContracts(IContractAwareHost contractAwareHost, PdbReader/*?*/ pdbReader, ContractExtractor extractor, ISourceMethodBody methodBody) { var definingUnit = TypeHelper.GetDefiningUnit(methodBody.MethodDefinition.ContainingType.ResolvedType); var methodIsInReferenceAssembly = ContractHelper.IsContractReferenceAssembly(contractAwareHost, definingUnit); var oldAndResultExtractor = new OldAndResultExtractor(contractAwareHost, methodBody, extractor.IsContractMethod); var localsInitializedWithFields = FindLocals.FindSetOfLocals(methodBody); var har = new HermansAlwaysRight(contractAwareHost, extractor, methodBody, methodIsInReferenceAssembly, oldAndResultExtractor, pdbReader); har.Rewrite(methodBody); if (har.extractor.currentMethodContract == null) return null; // The decompiler will have introduced locals if there were any anonymous delegates in the contracts // Such locals are initialized with the fields of the iterator class. // The contract that comes back from here will have those fields replaced with whatever the iterator captured // (parameters, locals). So the locals in the contract need to be replaced with the iterator fields so that // next replacement will see the right thing (i.e., the fields) and replace them! Phew! var localReplacer = new LocalReplacer(contractAwareHost, localsInitializedWithFields); localReplacer.Rewrite(har.extractor.currentMethodContract); // also need to rewrite the remainder of the body localReplacer.Rewrite(methodBody); return har.extractor.currentMethodContract; }
public CciPositiveActionQueryGenerator(IContractAwareHost host) : base(host) { }
/// <summary> /// Returns a (possibly-null) method contract relative to a contract-aware host. /// If the method is instantiated or specialized, then the contract is looked /// for on the uninstantiated and unspecialized method. /// Note that this behavior is *not* necessarily present in any individual /// contract provider. /// However, if you already know which unit the method is defined in and/or /// already have the contract provider for the unit in which the method is /// defined, and you know the method is uninstantiated and unspecialized, /// then you would do just as well to directly query that contract provider. /// </summary> public static IMethodContract GetMethodContractFor(IContractAwareHost host, IMethodReference methodReference) { if (methodReference is Dummy) return null; var u = TypeHelper.GetDefiningUnitReference(methodReference.ContainingType); if (u == null) return null; var cp = host.GetContractExtractor(u.UnitIdentity); if (cp == null) return null; var mc = cp.GetMethodContractFor(methodReference); return mc; }