/// <summary> /// Replaces any MemberBindings of the form (this,x) in the methodContract with a method call where the method /// being called is P where x is a private field of the source type that has been marked as [ContractPublicPropertyName("P")]. /// </summary> /// <param name="targetType"></param> /// <param name="sourceType"></param> /// <param name="methodContract"></param> internal static void ReplacePrivateFieldsThatHavePublicProperties(TypeNode targetType, TypeNode sourceType, MethodContract methodContract, ContractNodes contractNodes ) { Contract.Requires(sourceType != null); Dictionary <Field, Method> field2Getter = new Dictionary <Field, Method>(); for (int i = 0, n = /*sourceType.Members == null ? 0 : */ sourceType.Members.Count; i < n; i++) { Field f = sourceType.Members[i] as Field; if (f == null) { continue; } string propertyName = HelperMethods.GetStringFromAttribute(f, ContractNodes.SpecPublicAttributeName); if (propertyName != null) { Property p = sourceType.GetProperty(Identifier.For(propertyName)); if (p != null) { field2Getter.Add(f, p.Getter); } } } if (0 < field2Getter.Count) { SubstitutePropertyGetterForField s = new SubstitutePropertyGetterForField(field2Getter); s.Visit(methodContract); } return; }
public ExtractorVisitor(ContractNodes /*!*/ contractNodes, AssemblyNode ultimateTargetAssembly, AssemblyNode realAssembly, bool verbose, bool fSharp) { Contract.Requires(contractNodes != null); Contract.Requires(realAssembly != null); this.contractNodes = contractNodes; this.verbose = verbose; this.fSharp = fSharp; this.visibility = new VisibilityHelper(); this.errorFound = false; this.extractionFinalizer = new ExtractionFinalizer(contractNodes); this.ultimateTargetAssembly = ultimateTargetAssembly; this.realAssembly = realAssembly; this.contractNodes.ErrorFound += delegate(CompilerError error) { // Commented out because the ErrorFound event already had a handler that was printing out a message // and so error messages were getting printed out twice //if (!error.IsWarning || warningLevel > 0) { // Console.WriteLine(error.ToString()); //} errorFound |= !error.IsWarning; }; this.TaskType = new Cache<TypeNode>(() => HelperMethods.FindType(realAssembly, Identifier.For("System.Threading.Tasks"), Identifier.For("Task"))); this.GenericTaskType = new Cache<TypeNode>(() => HelperMethods.FindType(realAssembly, Identifier.For("System.Threading.Tasks"), Identifier.For("Task" + TargetPlatform.GenericTypeNamesMangleChar + "1"))); }
public GenerateDocumentationFromPDB(ContractNodes contracts, int tabWidth, bool writeOutput) { this.contracts = contracts; this.tabWidth = tabWidth; this.tabStops = 0; this.writeOutput = writeOutput; }
public ClousotExtractor(ContractNodes contractNodes, AssemblyNode ultimateTargetAssembly, AssemblyNode realAssembly, Action <System.CodeDom.Compiler.CompilerError> errorHandler) : base(contractNodes, ultimateTargetAssembly, realAssembly) { Contract.Requires(contractNodes != null); Contract.Requires(realAssembly != null); }
public CollectOldExpressions(Module module, Method method, ContractNodes contractNodes, Dictionary <TypeNode, Local> closureLocals, int localCounterStart, Class initialClosureClass) : this(module, method, contractNodes, closureLocals, localCounterStart) { this.topLevelClosureClass = initialClosureClass; this.currentClosureClass = initialClosureClass; }
public CollectOldExpressions(Module module, Method method, ContractNodes contractNodes, Dictionary<TypeNode, Local> closureLocals, int localCounterStart, Class initialClosureClass) : this(module, method, contractNodes, closureLocals, localCounterStart) { this.topLevelClosureClass = initialClosureClass; this.currentClosureClass = initialClosureClass; }
public ClousotExtractor(ContractNodes contractNodes, AssemblyNode ultimateTargetAssembly, AssemblyNode realAssembly, Action<System.CodeDom.Compiler.CompilerError> errorHandler) : base(contractNodes, ultimateTargetAssembly, realAssembly) { Contract.Requires(contractNodes != null); Contract.Requires(realAssembly != null); }
public DuplicatorForContractsAndClosures(Module module, Method sourceMethod, Method targetMethod, ContractNodes contractNodes, bool mapParameters) : base(module, targetMethod.DeclaringType) { this.sourceMethod = sourceMethod; this.targetMethod = targetMethod; this.RemoveNameForLocals = true; Duplicator dup = this; if (mapParameters) { if (sourceMethod.ThisParameter != null) { if (targetMethod.ThisParameter != null) { dup.DuplicateFor[sourceMethod.ThisParameter.UniqueKey] = targetMethod.ThisParameter; } else { // target is a static wrapper. But duplicator cannot handle This -> Parameter conversion // so we handle it explicitly here in this visitor. replaceThisWithParameter = targetMethod.Parameters[0]; } } if (sourceMethod.Parameters != null && targetMethod.Parameters != null && sourceMethod.Parameters.Count == targetMethod.Parameters.Count) { for (int i = 0, n = sourceMethod.Parameters.Count; i < n; i++) { dup.DuplicateFor[sourceMethod.Parameters[i].UniqueKey] = targetMethod.Parameters[i]; } } } var originalType = HelperMethods.IsContractTypeForSomeOtherType(sourceMethod.DeclaringType, contractNodes); if (originalType != null) { var contractType = this.contractClass = sourceMethod.DeclaringType; while (contractType.Template != null) { contractType = contractType.Template; } while (originalType.Template != null) { originalType = originalType.Template; } // forward ContractType<A,B> -> originalType<A',B'> this.contractClassToForward = contractType; this.targetTypeToForwardTo = originalType; //dup.DuplicateFor[contractType.UniqueKey] = originalType; } }
public static bool UsesModel(Node node, ContractNodes contractNodes) { CodeInspector ifrv = new CodeInspector(ContractNodes.ModelAttributeName, contractNodes, null, false); ifrv.Visit(node); return(ifrv.foundAttribute); }
public static bool UsesModel(Node node, ContractNodes contractNodes) { CodeInspector ifrv = new CodeInspector(ContractNodes.ModelAttributeName, contractNodes, null, false); ifrv.Visit(node); return ifrv.foundAttribute; }
/// <summary> /// actualReturn type is null if Task is not generic, otherwise ,the Task result type. /// </summary> public static bool Contains(Node node, ContractNodes contractNodes, Method currentMethod, TypeNode actualReturnType) { var v = new AsyncReturnValueQuery(contractNodes, currentMethod, actualReturnType); v.Visit(node); return v.foundReturnValueTaskResult; }
public static bool IsRuntimeIgnored(Node node, ContractNodes contractNodes, TypeNode referencingType, bool skipQuantifiers) { CodeInspector ifrv = new CodeInspector( ContractNodes.RuntimeIgnoredAttributeName, contractNodes, referencingType, skipQuantifiers); ifrv.Visit(node); return(ifrv.foundAttribute); }
/// <summary> /// actualReturn type is null if Task is not generic, otherwise ,the Task result type. /// </summary> public static bool Contains(Node node, ContractNodes contractNodes, Method currentMethod, TypeNode actualReturnType) { var v = new AsyncReturnValueQuery(contractNodes, currentMethod, actualReturnType); v.Visit(node); return(v.foundReturnValueTaskResult); }
public static bool IsRuntimeIgnored(Node node, ContractNodes contractNodes, TypeNode referencingType, bool skipQuantifiers) { CodeInspector ifrv = new CodeInspector( ContractNodes.RuntimeIgnoredAttributeName, contractNodes, referencingType, skipQuantifiers); ifrv.Visit(node); return ifrv.foundAttribute; }
/// <summary> /// If <paramref name="assembly"/> is null then this looks for the contract class in mscorlib. /// If it isn't null then it searches in <paramref name="assembly"/> for the contract class. /// Returns null if the contract class is not found. /// </summary> public static ContractNodes GetContractNodes(AssemblyNode assembly, Action <System.CodeDom.Compiler.CompilerError> errorHandler) { ContractNodes contractNodes = new ContractNodes(assembly, errorHandler); if (contractNodes.ContractClass == null) { return(null); } return(contractNodes); }
public AbbreviationDuplicator(Method sourceMethod, Method targetMethod, ContractNodes contractNodes, Method abbreviation, Expression targetObject, ExpressionList actuals) : base(targetMethod.DeclaringType.DeclaringModule, sourceMethod, targetMethod, contractNodes, false) { this.targetObject = targetObject; this.abbreviation = abbreviation; this.actuals = actuals; this.localsInActuals = new TrivialHashtable(); PopulateLocalsInActuals(); }
private CodeInspector(Identifier attributeToFind, ContractNodes contractNodes, TypeNode referencingType, bool skipQuantifiers) { this.foundAttribute = false; this.attributeToFind = attributeToFind; this.contractNodes = contractNodes; this.skipQuantifiers = skipQuantifiers; this.referencingType = new Stack<TypeNode>(); if (referencingType != null) { this.referencingType.Push(referencingType); } }
public CollectOldExpressions(Module module, Method method, ContractNodes contractNodes, Dictionary <TypeNode, Local> closureLocals, int localCounterStart) { this.contractNodes = contractNodes; this.prestateValuesOfOldExpressions = new Block(new StatementList()); this.closureLocals = closureLocals; this.stackOfMethods = new List <MethodCall>(); this.stackOfBoundVariables = new List <Parameter>(); this.module = module; this.currentMethod = method; this.counter = localCounterStart; }
public CollectOldExpressions(Module module, Method method, ContractNodes contractNodes, Dictionary<TypeNode, Local> closureLocals, int localCounterStart) { this.contractNodes = contractNodes; this.prestateValuesOfOldExpressions = new Block(new StatementList()); this.closureLocals = closureLocals; this.stackOfMethods = new List<MethodCall>(); this.stackOfBoundVariables = new List<Parameter>(); this.module = module; this.currentMethod = method; this.counter = localCounterStart; }
private CodeInspector(Identifier attributeToFind, ContractNodes contractNodes, TypeNode referencingType, bool skipQuantifiers) { this.foundAttribute = false; this.attributeToFind = attributeToFind; this.contractNodes = contractNodes; this.skipQuantifiers = skipQuantifiers; this.referencingType = new Stack <TypeNode>(); if (referencingType != null) { this.referencingType.Push(referencingType); } }
public CopyOutOfBandContracts(AssemblyNode targetAssembly, AssemblyNode sourceAssembly, ContractNodes contractNodes, ContractNodes targetContractNodes) { Contract.Requires(targetAssembly != null); Contract.Requires(sourceAssembly != null); Contract.Requires(contractNodes != null); if (targetAssembly == sourceAssembly) { // this happened when a reference assembly for mscorlib had the assembly name "mscorlib" // instead of "mscorlib.Contracts" because only one assembly named "mscorlib" can be // loaded throw new ExtractorException("CopyOutOfBandContracts was given the same assembly as both the source and target!"); } this.outOfBandDuplicator = new ForwardingDuplicator(targetAssembly, null, contractNodes, targetContractNodes); this.targetAssembly = targetAssembly; FuzzilyForwardReferencesFromSource2Target(targetAssembly, sourceAssembly); CopyMissingMembers(); // FixupMissingProperties(); shouldn't be needed with new duplicator }
private static ContractNodes IdentifyContractAssemblyIfReferenced(ContractNodes contracts, AssemblyNode assemblyToVisit) { Contract.Requires(assemblyToVisit != null); if (contracts != null) { AssemblyNode assemblyContractsLiveIn = contracts.ContractClass == null ? null : contracts.ContractClass.DeclaringModule as AssemblyNode; if (assemblyContractsLiveIn != null) { if (assemblyContractsLiveIn == assemblyToVisit) { return(contracts); } string nameOfAssemblyContainingContracts = assemblyContractsLiveIn.Name; Contract.Assume(assemblyToVisit.AssemblyReferences != null); foreach (var ar in assemblyToVisit.AssemblyReferences) { Contract.Assume(ar != null); if (ar.Name == nameOfAssemblyContainingContracts) { // just do name matching to avoid loading the referenced assembly return(contracts); } } } } return(null); }
public Decompiler(ContractNodes cns, Local l) { this.contractNodes = cns; this.localToUseForResult = l; }
public PreconditionChecker(Action<CompilerError> errorHandler, ContractNodes usedToExtract) : base(errorHandler, usedToExtract) { // F: Contract.Requires(errorHandler != null); Contract.Requires(usedToExtract != null); }
public BasicChecker(Action<CompilerError> errorHandler, ContractNodes usedToExtract) { Contract.Requires(errorHandler != null); Contract.Requires(usedToExtract != null); this.errorHandler = errorHandler; this.usedToExtract = usedToExtract; }
public static TypeNode IsContractTypeForSomeOtherType(TypeNode t, ContractNodes contractNodes) { var unspecializedType = IsContractTypeForSomeOtherTypeUnspecialized(t, contractNodes); if (unspecializedType == null) return null; // else go search t's list of interfaces/base classes to find the specialized type // (which might be specialized only with a type parameter, but that's better than // returning the unspecialized one from the attribute, because the unspecialized one // will never be pointer equal to any specialized type. for (int i = 0, n = t.Interfaces == null ? 0 : t.Interfaces.Count; i < n; i++) { if (unspecializedType == t.Interfaces[i] || unspecializedType == t.Interfaces[i].Template) return t.Interfaces[i]; } if (unspecializedType == t.BaseType || unspecializedType == t.BaseType.Template) return t.BaseType; return null; }
internal static Local ExtractPreamble(Method m, ContractNodes contractNodes, Block contractInitializer, out Block postPreamble, ref StackDepthTracker dupStackTracker, bool isVB) { postPreamble = null; if (m == null || m.Body == null || m.Body.Statements == null || !(m.Body.Statements.Count > 0)) return null; Block firstBlock = m.Body.Statements[0] as Block; if (firstBlock == null) return null; Block preambleBlock = new PreambleBlock(new StatementList(0)); Local result; int nextInstructionInFirstBlock = ExtractClosureInitializationAndLocalThis(m, firstBlock, contractNodes, contractInitializer, preambleBlock, 0, out result, ref dupStackTracker); // Type (2): Base ctor or deferring ctor call if (m is InstanceInitializer) { int i, j; bool found; // Type (2a): Assignments to fields of class that had initializers // Just extract the statements for (2a) as part of what gets extracted for (2b) // Type (2b): base or deferring ctor call found = SearchClump(m.Body.Statements, delegate(Statement s) { if (s == null) return false; ExpressionStatement es = s as ExpressionStatement; if (es == null) return false; MethodCall mc = es.Expression as MethodCall; if (mc == null) return false; MemberBinding mb = mc.Callee as MemberBinding; if (mb == null) return false; Method callee = mb.BoundMember as Method; // can't depend on the TargetObject being "this": it could be "pop" if // the arguments to the call had any control flow // e.g., a boolean short-circuit expression or a ternary expression. //if (mb.TargetObject is This && callee is InstanceInitializer) return true; if (callee is InstanceInitializer && ((callee.DeclaringType == m.DeclaringType || callee.DeclaringType.Template == m.DeclaringType) // deferring ctor call || (callee.DeclaringType == m.DeclaringType.BaseType || // base ctor call callee.DeclaringType.Template == m.DeclaringType.BaseType.Template))) { return true; } return false; }, out i, out j); if (found) { // for VB constructors and C# constructors with closures, we need to extend the scope to include field initializers Block b = (Block) m.Body.Statements[i]; int k = j + 1; Local extraClosureLocal = null; int stackDepth = 0; for (; k < b.Statements.Count; k++) { // skip over auxiliary closure creation if (extraClosureLocal == null && IsClosureCreation(m, b.Statements[k], out extraClosureLocal)) { continue; } switch (b.Statements[k].NodeType) { case NodeType.Nop: continue; case NodeType.AssignmentStatement: { AssignmentStatement assgmt = (AssignmentStatement) b.Statements[k]; MemberBinding mb = assgmt.Target as MemberBinding; if (mb == null) { // we might be initializing locals for default values etc if (stackDepth > 0) continue; goto doneWithFieldInits; } if (!(mb.BoundMember is Field)) { // we might be initializing locals for default values etc if (stackDepth > 0) continue; goto doneWithFieldInits; } if (mb.TargetObject == null) { // we might be initializing locals for default values etc if (stackDepth > 0) continue; goto doneWithFieldInits; } // there are 2 cases here. Either we are assigning to this.f = ..., which is a field initialization, // or it is initializing the closure field for "this" with this. if (mb.TargetObject.NodeType == NodeType.This) { // okay field initialization continue; } if (mb.TargetObject.NodeType == NodeType.Pop) { // okay field initialization (popping this) stackDepth--; continue; } // we might also be initializing the extra closure fields, if the target is the extraClosureLocal. if (mb.TargetObject == extraClosureLocal) { continue; } if (mb.TargetObject.NodeType == NodeType.Local && assgmt.Source != null && assgmt.Source.NodeType == NodeType.This && mb.BoundMember.Name != null && (mb.BoundMember.Name.Name.EndsWith("_this") || mb.BoundMember.Name.Name == "$VB$Me")) { // closure initialization (storing this) // add it to postPreamble, since it needs to be inserted for duplicate closure object postPreamble = new Block(new StatementList(1)); postPreamble.Statements.Add((Statement) b.Statements[k].Clone()); continue; } goto doneWithFieldInits; } case NodeType.ExpressionStatement: { ExpressionStatement estmt = (ExpressionStatement) b.Statements[k]; if (estmt.Expression != null && estmt.Expression is This) { // handle special push/pop pattern occurring occasionally stackDepth++; continue; } // handle ctor calls on addresses of value types // NOTE: this could be mistakenly the first user statement. MethodCall mc = estmt.Expression as MethodCall; if (mc == null) goto doneWithFieldInits; MemberBinding mb = mc.Callee as MemberBinding; if (mb == null) goto doneWithFieldInits; if (!(mb.BoundMember is InstanceInitializer)) goto doneWithFieldInits; if (!mb.BoundMember.DeclaringType.IsValueType) goto doneWithFieldInits; if (mb.TargetObject.NodeType != NodeType.AddressOf) goto doneWithFieldInits; continue; } default: goto doneWithFieldInits; } } doneWithFieldInits: StatementList sl2 = ExtractClump(m.Body.Statements, 0, 0, i, k - 1); preambleBlock.Statements.Add(new Block(sl2)); ExtractVB_ENCCallToPreamble(m.Body.Statements[i] as Block, k, preambleBlock.Statements); } else { // for struct ctors, we may not have a "this" call // for C# constructors with closures, we need to extend the scope Block b = firstBlock; int k = nextInstructionInFirstBlock; Local extraClosureLocal = null; for (; k < b.Statements.Count; k++) { // skip over auxiliary closure creation and initialization if (extraClosureLocal == null && IsClosureCreation(m, b.Statements[k], out extraClosureLocal)) { continue; } switch (b.Statements[k].NodeType) { case NodeType.Nop: continue; case NodeType.AssignmentStatement: { AssignmentStatement assgmt = (AssignmentStatement) b.Statements[k]; MemberBinding mb = assgmt.Target as MemberBinding; if (mb == null) goto doneWithFieldInits; if (!(mb.BoundMember is Field)) goto doneWithFieldInits; if (mb.TargetObject == null) goto doneWithFieldInits; // we might be initializing the extra closure fields, if the target is the extraClosureLocal. if (mb.TargetObject == extraClosureLocal) { continue; } goto doneWithFieldInits; } default: goto doneWithFieldInits; } } doneWithFieldInits: for (int toCopy = nextInstructionInFirstBlock; toCopy < k; toCopy++) { preambleBlock.Statements.Add(firstBlock.Statements[toCopy]); firstBlock.Statements[toCopy] = null; } } } // Create a new body, add the preamble block, then all of the other blocks StatementList sl = new StatementList(m.Body.Statements.Count); sl.Add(preambleBlock); if (m.Body != null) { foreach (Block b in m.Body.Statements) { if (b != null) sl.Add(b); } } m.Body.Statements = sl; return result; }
internal static MethodContract DuplicateContractAndClosureParts( DuplicatorForContractsAndClosures dup, Method targetMethod, Method sourceMethod, ContractNodes contractNodes, bool copyValidations) { Contract.Ensures(Contract.Result<MethodContract>() != null); //System.Console.WriteLine(">>>" + sourceMethod.FullName); // materialize source contract: var sourceContract = sourceMethod.Contract; ForceSideEffect(sourceContract.ContractInitializer); TypeNode targetType = targetMethod.DeclaringType; TypeNode sourceType = sourceMethod.DeclaringType; // need to null out ProvideNestedTypes so the NestedTypes property doesn't use // metadata to fill in the list of nested types. Because maybe sourceType has // had nested types added to it in memory and those nested types don't exist // in the assembly that sourceType is defined in. // The source type itself shouldn't be duplicated, because any references to its // members (e.g., method calls) in a contract should remain as references to that // member. I.e., a contract on virtual method B.M might contain a call to "this.P()". When copying // the contract from B.M to an override C.M, "this" of type B should become "this" of type C (which // is why the self parameter is mapped below), but the member B.P() should remain B.P(). // However, any nested types within the source type, such as any closure classes, *should* be // duplicated. sourceType.ProvideNestedTypes = null; targetType.ProvideNestedTypes = null; // HACK // For some reason, it is important to materialize the name of the targetType here!!! // Otherwise the duplicator will fail. ForceSideEffect(targetType.Name.Name); Local closureLocal; FindClosureInitialization(sourceMethod, sourceContract.ContractInitializer, out closureLocal); // Duplicate anonymous delegates that turn into static methods (and their caching fields) FindClosurePartsToDuplicate fmd = new FindClosurePartsToDuplicate(sourceType, sourceMethod); fmd.VisitMethodContract(sourceContract); // special handling of closures that are not used. if (closureLocal != null) { var closureType = Unspecialize(closureLocal.Type); if (!fmd.MembersToDuplicate.Contains(closureType)) { // contracts do not depend on closure and won't copy it, so remove the initialization, otherwise debugger gets confused DeleteClosureInitialization(sourceMethod, sourceContract, closureLocal); } } // !Very important! // To get appropriate types mapping for duplicated members we have to have two steps approach. // First we need to copy all static closures (they're exists only for roslyn-based compiler) // Second we need to copy all other members (including closures). // The reason why the members are traversed backwards is following: // Nested scope can introduced nested closures. In this case, top level closures can reference // low level closures. Traversing them in backward order will allow to fill type mapping appropriately. for (var memindex = fmd.MembersToDuplicate.Count - 1; memindex >= 0; memindex--) { Member member = fmd.MembersToDuplicate[memindex]; if (IsRoslynBasedStaticClosure(member)) { DuplicateMember(dup, fmd, memindex, targetType); } } for (var memindex = fmd.MembersToDuplicate.Count - 1; memindex >= 0; memindex--) { var member = fmd.MembersToDuplicate[memindex]; if (IsRoslynBasedStaticClosure(member)) { continue; } DuplicateMember(dup, fmd, memindex, targetType); } var duplicateContract = dup.VisitMethodContract(sourceContract); if (copyValidations) { duplicateContract.Validations = dup.VisitRequiresList(sourceContract.Validations); } foreach (Member mem in sourceType.Members) { if (mem == null) continue; Member newMember = (Member) dup.DuplicateFor[mem.UniqueKey]; if (newMember != null && mem != (Member) targetType && newMember.DeclaringType == targetType && !targetType.Members.Contains(newMember)) { TypeNode nestedType = mem as TypeNode; if (nestedType != null && nestedType.Template != null) { // don't add instantiations continue; } Method nestedMethod = mem as Method; if (nestedMethod != null && nestedMethod.Template != null) { // don't add instantiations continue; } // second conjunct is to make sure we don't recursively add a nested type to itself // e.g., ArrayList+IListWrapper extends ArrayList and so inherits contracts from it // so this method could be called with sourceMethod "ArrayList.M" and targetMethod "ArrayList+IListWrapper.M" // But need to make sure that there isn't already a type with the same name!!! TypeNode possibleClash = targetType.GetNestedType(newMember.Name); if (possibleClash != null) { newMember.Name = Identifier.For(newMember.Name.Name + "_1"); } // System.Console.WriteLine("found nested member that wasn't there before closure and contract duplication: {0}", newMember.FullName); dup.SafeAddMember(targetType, newMember, mem); //targetType.Members.Add(newMember); } } return duplicateContract; }
public static bool ExtractContracts(AssemblyNode /*!*/ assembly, AssemblyNode /*?*/ referenceAssembly, ContractNodes /*?*/ contracts, ContractNodes /*?*/ backupContracts, ContractNodes /*?*/ targetContractNodes, out ContractNodes /*?*/ contractNodesUsedToExtract, Action<CompilerError> /*?*/ errorHandler, bool useClousotExtractor) { Contract.Requires(assembly != null); AssemblyNode assemblyToVisit = referenceAssembly ?? assembly; // Try to use supplied contracts, if present. But don't just try extracting and somehow // figuring out if any contracts had been present. Instead, see if: // a) the contract methods are defined in the assembly we are extracting from, or // b) the assembly reference microsoft.contracts.dll (the backup contracts and we found that assembly) // c) the assembly we are extracting from has an external reference to the assembly // the supplied contract methods came from. // d) the contracts found in mscorlib // // see if the assembly references the backup contracts (Microsoft.Contracts.dll) contractNodesUsedToExtract = IdentifyContractAssemblyIfReferenced(backupContracts, assemblyToVisit); // see if assembly defines the contracts itself if (contractNodesUsedToExtract == null) { contractNodesUsedToExtract = ContractNodes.GetContractNodes(assemblyToVisit, errorHandler); } // see if the assembly references the supplied contract assembly if (contractNodesUsedToExtract == null) { contractNodesUsedToExtract = IdentifyContractAssemblyIfReferenced(contracts, assemblyToVisit); } // see if the contracts are in the system assembly if (contractNodesUsedToExtract == null && assemblyToVisit != SystemTypes.SystemAssembly) { contractNodesUsedToExtract = ContractNodes.GetContractNodes(SystemTypes.SystemAssembly, errorHandler); } if (contractNodesUsedToExtract == null) return false; var fSharp = false; // TODO: Thread the program options through here somehow and let this be specified as an option Contract.Assume(assemblyToVisit.Attributes != null); foreach (var attr in assemblyToVisit.Attributes) { Contract.Assume(attr != null); Contract.Assume(attr.Type != null); Contract.Assume(attr.Type.Name != null); Contract.Assume(attr.Type.Name.Name != null); if (attr.Type.Name.Name.Contains("FSharpInterfaceDataVersionAttribute")) { fSharp = true; break; } } var ultimateTarget = (referenceAssembly != null) ? assembly : null; Contract.Assert(assembly != null); ExtractorVisitor ev = useClousotExtractor ? new ClousotExtractor(contractNodesUsedToExtract, ultimateTarget, assembly, errorHandler) : new ExtractorVisitor(contractNodesUsedToExtract, ultimateTarget, assembly, false, fSharp); ev.Visit(assemblyToVisit); if (!useClousotExtractor) { FilterForRuntime eoar = new FilterForRuntime(contractNodesUsedToExtract, targetContractNodes); assemblyToVisit = eoar.TransformForTarget(assemblyToVisit); } if (referenceAssembly != null) { CopyOutOfBandContracts coob = new CopyOutOfBandContracts(assembly, referenceAssembly, contractNodesUsedToExtract, targetContractNodes); coob.VisitAssembly(referenceAssembly); } return true; }
public GenerateDocumentationFromPDB(ContractNodes contracts) : this(contracts, 2, false) { }
internal LookForBadStuff(ContractNodes contractNodes) { this.contractNodes = contractNodes; }
public AsyncReturnValueQuery(ContractNodes contractNodes, Method currentMethod, TypeNode actualResultType) { this.contractNodes = contractNodes; this.CurrentMethod = currentMethod; this.actualResultType = actualResultType; }
public DuplicatorForContractsAndClosures(Module module, Method sourceMethod, Method targetMethod, ContractNodes contractNodes) : this(module, sourceMethod, targetMethod, contractNodes, true) { }
/// <summary> /// Creates a new instance of this class. /// </summary> /// <param name="owner">Parent checker that is used to report errors.</param> public PurityChecker(Action<System.CodeDom.Compiler.CompilerError> errorHandler, bool fSharp, ContractNodes contractNodes) { Contract.Requires(errorHandler != null); Contract.Requires(contractNodes != null); this.errorHandler = errorHandler; this.fSharp = fSharp; this.contractNodes = contractNodes; }
public Decompiler(AssemblyNode assemblyNode) { this.contractNodes = ContractNodes.GetContractNodes(assemblyNode, null); }
/// <summary> /// Extract prefix code prior to contracts such as closure initialization and locals /// </summary> internal static int ExtractClosureInitializationAndLocalThis( Method m, Block firstBlock, ContractNodes contractNodes, Block contractInitializer, Block preambleBlock, int currentIndex, out Local localAliasingThis, ref StackDepthTracker dupStackTracker) { localAliasingThis = null; // Any prefix of null statements and nops should go into the preamble block // In addition, for VB structure ctors, they start with initobj this // ------------------------------------------------------------------------ Contract.Assert(currentIndex <= firstBlock.Statements.Count); while (currentIndex < firstBlock.Statements.Count) { Statement s = firstBlock.Statements[currentIndex]; if (s != null && s.NodeType != NodeType.Nop) { // check for VB "initobj this" if (!m.DeclaringType.IsValueType) break; if (!(m is InstanceInitializer)) break; AssignmentStatement initObj = s as AssignmentStatement; if (initObj == null) break; AddressDereference addrderef = initObj.Target as AddressDereference; if (addrderef == null) break; if (addrderef.Address != m.ThisParameter) break; Literal initObjArg = initObj.Source as Literal; if (initObjArg == null) break; if (initObjArg.Value != null) break; } preambleBlock.Statements.Add(s); var oldCount = firstBlock.Statements.Count; var oldStats = firstBlock.Statements; firstBlock.Statements[currentIndex] = null; Contract.Assert(oldStats == firstBlock.Statements); Contract.Assert(oldCount == firstBlock.Statements.Count); currentIndex++; Contract.Assert(currentIndex <= firstBlock.Statements.Count); } Contract.Assert(currentIndex <= firstBlock.Statements.Count); // Type (1): Closure creation and initialization // --------------------------------------------- TypeNode closureType; currentIndex = MovePastClosureInit(m, firstBlock, contractNodes, contractInitializer.Statements, preambleBlock, currentIndex, ref dupStackTracker, out closureType); // Local @this in contract classes // ------------------------------- // For contract classes, since we require that they use explicit interface implementation, // allow the single assignment statement "J this_j = this;" as part of the prelude so that // explicit casts are not needed all over the contracts. Interface iface = HelperMethods.IsContractTypeForSomeOtherType(m.DeclaringType, contractNodes) as Interface; if (iface != null && currentIndex < firstBlock.Statements.Count) { AssignmentStatement assgn = firstBlock.Statements[currentIndex] as AssignmentStatement; if (assgn != null) { if (assgn.Target is Local && assgn.Target.Type == iface && assgn.Source is This) { // we currently keep the local initializer in both "contractLocalsInitializer" for static decoding // AND in the preamble block for runtime checking code generation. localAliasingThis = (Local) assgn.Target; // contractInitializer.Statements.Add((Statement)(firstBlock.Statements[currentIndex].Clone())); // preambleBlock.Statements.Add(firstBlock.Statements[currentIndex]); firstBlock.Statements[currentIndex] = null; currentIndex++; } } } // VB hoists some other literal assignments to the start of the method. while (currentIndex < firstBlock.Statements.Count) { Statement s = firstBlock.Statements[currentIndex]; if (s != null && s.NodeType != NodeType.Nop) { // check for VB literal assignments if (!s.SourceContext.Hidden) break; AssignmentStatement litAssgn = s as AssignmentStatement; if (litAssgn == null) break; var local = litAssgn.Target as Local; if (local == null) break; if (local.Name == null) break; if (!local.Name.Name.StartsWith("VB$t_ref$L")) break; // okay, we are assigning one of these locals. Put it into the preamble. } preambleBlock.Statements.Add(s); var oldCount = firstBlock.Statements.Count; var oldStats = firstBlock.Statements; firstBlock.Statements[currentIndex] = null; Contract.Assert(oldStats == firstBlock.Statements); Contract.Assert(oldCount == firstBlock.Statements.Count); currentIndex++; Contract.Assert(currentIndex <= firstBlock.Statements.Count); } Contract.Assert(currentIndex <= firstBlock.Statements.Count); return currentIndex; }
public DuplicatorForContractsAndClosures(Module module, Method sourceMethod, Method targetMethod, ContractNodes contractNodes, bool mapParameters) : base(module, targetMethod.DeclaringType) { this.sourceMethod = sourceMethod; this.targetMethod = targetMethod; this.RemoveNameForLocals = true; Duplicator dup = this; if (mapParameters) { if (sourceMethod.ThisParameter != null) { if (targetMethod.ThisParameter != null) { dup.DuplicateFor[sourceMethod.ThisParameter.UniqueKey] = targetMethod.ThisParameter; } else { // target is a static wrapper. But duplicator cannot handle This -> Parameter conversion // so we handle it explicitly here in this visitor. replaceThisWithParameter = targetMethod.Parameters[0]; } } if (sourceMethod.Parameters != null && targetMethod.Parameters != null && sourceMethod.Parameters.Count == targetMethod.Parameters.Count) { for (int i = 0, n = sourceMethod.Parameters.Count; i < n; i++) { dup.DuplicateFor[sourceMethod.Parameters[i].UniqueKey] = targetMethod.Parameters[i]; } } // This code makes sure that generic method parameters used by contracts inherited from contract class // are correctly replaced by the one defined in the target method. // Without this mapping <c>CheckPost</c> method in generated async closure class would contain an invalid // reference to a generic contract method parameter instead of generic async closure type parameter. // For more about this problem see comments for Microsoft.Contracts.Foxtrot.EmitAsyncClosure.GenericTypeMapper class // and issue #380. if (sourceMethod.TemplateParameters != null && targetMethod.TemplateParameters != null && sourceMethod.TemplateParameters.Count == targetMethod.TemplateParameters.Count) { for (int i = 0, n = sourceMethod.TemplateParameters.Count; i < n; i++) { dup.DuplicateFor[sourceMethod.TemplateParameters[i].UniqueKey] = targetMethod.TemplateParameters[i]; } } } var originalType = HelperMethods.IsContractTypeForSomeOtherType(sourceMethod.DeclaringType, contractNodes); if (originalType != null) { var contractType = this.contractClass = sourceMethod.DeclaringType; while (contractType.Template != null) { contractType = contractType.Template; } while (originalType.Template != null) { originalType = originalType.Template; } // forward ContractType<A,B> -> originalType<A',B'> this.contractClassToForward = contractType; this.targetTypeToForwardTo = originalType; //dup.DuplicateFor[contractType.UniqueKey] = originalType; } }
/// <summary> /// Copies the closure initialization into the contractinitializer and preambleBlock (if non-null) /// </summary> internal static int MovePastClosureInit(Method m, Block firstBlock, ContractNodes contractNodes, StatementList contractInitializer, Block preambleBlock, int currentIndex, ref StackDepthTracker dupStackTracker, out TypeNode closureType) { int indexForClosureCreationStatement = currentIndex; closureType = null; Local introducedClosureLocal = null; while (indexForClosureCreationStatement < firstBlock.Statements.Count) { var closureCreationCandidate = firstBlock.Statements[indexForClosureCreationStatement]; closureType = IsClosureCreation(m, closureCreationCandidate); if (closureType != null) break; if (contractNodes.IsContractOrValidatorOrAbbreviatorCall(closureCreationCandidate)) { // found contracts before closure creation, so get out return currentIndex; } if (closureCreationCandidate != null && closureCreationCandidate.SourceContext.IsValid) return currentIndex; indexForClosureCreationStatement++; } if (closureType != null && indexForClosureCreationStatement < firstBlock.Statements.Count) { // then there is a set of statements to add to the preamble block // up to and including "local := new ClosureClass();" for (int i = currentIndex; i <= indexForClosureCreationStatement; i++) { if (firstBlock.Statements[i] == null) continue; if (preambleBlock != null) { preambleBlock.Statements.Add(firstBlock.Statements[i]); } Local existingClosureLocal; if (IsClosureCreation(m, firstBlock.Statements[i], out existingClosureLocal)) { if (existingClosureLocal == null) { // introduce one ExpressionStatement estmt = firstBlock.Statements[i] as ExpressionStatement; if (estmt != null) { introducedClosureLocal = new Local(closureType); contractInitializer.Add( new AssignmentStatement(introducedClosureLocal, (Expression) estmt.Expression.Clone())); } else { contractInitializer.Add((Statement) firstBlock.Statements[i].Clone()); } } else { contractInitializer.Add((Statement) firstBlock.Statements[i].Clone()); } } else { contractInitializer.Add((Statement) firstBlock.Statements[i].Clone()); } if (preambleBlock != null) { firstBlock.Statements[i] = null; // need to null them out so search below can be done starting at beginning of m's body } } // Some number of assignment statements of the form "local.f := f;" where "f" is a parameter // that is captured by the closure. // // Roslyn generates code as follows: // new Closure() // dup // ldarg f // stfld f // dup // ldarg q // stfld q // dup... // int endOfAssignmentsToClosureFields = indexForClosureCreationStatement + 1; for (; endOfAssignmentsToClosureFields < firstBlock.Statements.Count; endOfAssignmentsToClosureFields++) { Statement s = firstBlock.Statements[endOfAssignmentsToClosureFields]; if (s == null) continue; if (s.NodeType == NodeType.Nop) continue; if (s.SourceContext.IsValid) break; // end of closure if (s is Return) break; // Return is also an ExpressionStatement ExpressionStatement exprSt = s as ExpressionStatement; if (exprSt != null && exprSt.Expression.NodeType == NodeType.Dup) { // dup of closure node continue; } AssignmentStatement assign = s as AssignmentStatement; if (assign == null) break; MemberBinding mb = assign.Target as MemberBinding; if (mb == null) break; if (mb.TargetObject == null || (mb.TargetObject.Type != closureType && mb.TargetObject.NodeType != NodeType.Pop)) break; } if (endOfAssignmentsToClosureFields - 1 < firstBlock.Statements.Count && endOfAssignmentsToClosureFields >= 1 && IsDup(firstBlock.Statements[endOfAssignmentsToClosureFields - 1])) { endOfAssignmentsToClosureFields--; // last dup is not part of closure init } dupStackTracker = new StackDepthTracker(introducedClosureLocal); for (int i = indexForClosureCreationStatement + 1; i < endOfAssignmentsToClosureFields; i++) { var stmt = firstBlock.Statements[i]; if (stmt == null) continue; if (preambleBlock != null) { preambleBlock.Statements.Add(stmt); } if (stmt.NodeType != NodeType.Nop) { // don't add nop's to contract initializer if (dupStackTracker.IsValid) { contractInitializer.Add(dupStackTracker.Visit(stmt)); } else { contractInitializer.Add((Statement) stmt.Clone()); } } if (preambleBlock != null) { firstBlock.Statements[i] = null; // need to null them out so search below can be done starting at beginning of m's body } } currentIndex = endOfAssignmentsToClosureFields; } return currentIndex; }
public ExtractionFinalizer(ContractNodes contractNodes) { this.contractNodes = contractNodes; }
public static MethodContract DuplicateContractAndClosureParts(Method targetMethod, Method sourceMethod, ContractNodes contractNodes, bool copyValidations) { Module targetModule = targetMethod.DeclaringType.DeclaringModule; var dup = new DuplicatorForContractsAndClosures(targetModule, sourceMethod, targetMethod, contractNodes); if (sourceMethod.Contract.AsyncEnsuresCount != 0) { // Removing the name lead to NRE for async method that uses Contract.Ensures(Contract.ForAll) // with a capturing lambda. // To preserve as much of backward compatible behavior as possible the fix will affect // only method contracts with async closures. It still possible that this fix will break existing code // and it is possible that there is no any issues by preserving name of the locals. // This fix could be enhanced in the future when this issue would be clear. dup.RemoveNameForLocals = false; } return DuplicateContractAndClosureParts(dup, targetMethod, sourceMethod, contractNodes, copyValidations); }
private StatementList GetContractClumpFromMoveNext(Method iteratorMethod, Method moveNext, ContractNodes contractNodes, StatementList contractInitializer, out SourceContext defaultSourceContext, ref HelperMethods.StackDepthTracker dupStackTracker, out AssumeBlock originalContractPosition) { Contract.Requires(moveNext != null); Contract.Requires(moveNext.Body != null); Contract.Requires(moveNext.Body.Statements != null); Contract.Requires(contractInitializer != null); Contract.Requires(iteratorMethod != null); var linkerVersion = 0; if (iteratorMethod.DeclaringType != null && iteratorMethod.DeclaringType.DeclaringModule != null) { linkerVersion = iteratorMethod.DeclaringType.DeclaringModule.LinkerMajorVersion; } var initialState = moveNext.IsAsync ? -1 : 0; moveNext.MoveNextStartState = initialState; originalContractPosition = null; int statementIndex; Contract.Assume(moveNext.Body != null); Contract.Assume(moveNext.Body.Statements != null); int blockIndex = ContractStartInMoveNext(this.contractNodes, moveNext, out statementIndex, iteratorMethod); Contract.Assert(statementIndex >= 0, "should follow from the postcondiiton"); if (blockIndex < 0) { // Couldn't find state 0 in MoveNext method // This can happen if the iterator is trivial (like yield break; ) defaultSourceContext = default(SourceContext); return null; } int beginning = blockIndex; // the block number in the body of movenext int sbeginning = statementIndex; // the statement no. in the beginnning block after the preamble int blast = -1; // the block number in the body of movenext, of the last block where there is a contract call int slast = -1; // the statement no. in the blast block // Next we move sbeginning past the preamble area sbeginning = MovePastPreamble(iteratorMethod, moveNext, beginning, sbeginning, contractInitializer, contractNodes, ref dupStackTracker); Contract.Assert(moveNext.Body != null, "should be provable"); Contract.Assert(moveNext.Body.Statements != null, "should be provable"); if (sbeginning < 0 || !this.FindLastBlockWithContracts(moveNext.Body.Statements, beginning, out blast, out slast)) { if (verbose) { if (moveNext.Name != null) { Console.WriteLine("Method {0} doesnt have a contract method invocation at the right place.", moveNext.Name.Name); } } defaultSourceContext = default(SourceContext); return null; } Block methodBody = moveNext.Body; Block lastBlock = methodBody.Statements[blast] as Block; SourceContext lastContractSourceContext; if (lastBlock != null) { lastContractSourceContext = lastBlock.SourceContext; // probably not a good context, what to do if one can't be found? if (lastBlock.Statements != null && 0 <= slast && slast < lastBlock.Statements.Count) { if (lastBlock.Statements[slast] != null) { lastContractSourceContext = lastBlock.Statements[slast].SourceContext; } } } else { lastContractSourceContext = default(SourceContext); } // TODO: check the clump is not in a try-catch block. originalContractPosition = new AssumeBlock(new StatementList()); StatementList result = HelperMethods.ExtractClump( moveNext.Body.Statements, beginning, sbeginning, blast, slast, assumeBlock: originalContractPosition); defaultSourceContext = lastContractSourceContext; return result; }
public static TypeNode IsContractTypeForSomeOtherTypeUnspecialized(TypeNode t, ContractNodes contractNodes) { TypeNode unspecializedType = GetTypeFromAttribute(t, ContractNodes.ContractClassForAttributeName); return unspecializedType; }
private static int MovePastPreamble([Pure] Method iteratorMethod, [Pure] Method moveNext, int beginning, int currentIndex, StatementList contractInitializer, ContractNodes contractNodes, ref HelperMethods.StackDepthTracker dupStackTracker) { Contract.Requires(moveNext != null); Contract.Requires(moveNext.Body != null); Contract.Requires(moveNext.Body.Statements != null); Contract.Requires(beginning >= 0); Contract.Requires(beginning < moveNext.Body.Statements.Count); Contract.Requires(currentIndex >= 0); Contract.Requires(contractInitializer != null); var state0Block = moveNext.Body.Statements[beginning] as Block; while (state0Block == null && beginning + 1 < moveNext.Body.Statements.Count) { state0Block = moveNext.Body.Statements[++beginning] as Block; if (state0Block != null && (state0Block.Statements == null || state0Block.Statements.Count == 0)) { // skip empty blocks state0Block = null; } } if (state0Block == null) return -1; if (state0Block.Statements == null) return -1; #if true TypeNode closureType; currentIndex = HelperMethods.MovePastClosureInit(iteratorMethod, state0Block, contractNodes, contractInitializer, null, currentIndex, ref dupStackTracker, out closureType); #else int indexForClosureCreationStatement = currentIndex; TypeNode closureType = null; while (indexForClosureCreationStatement < state0Block.Statements.Count) { closureType = HelperMethods.IsClosureCreation(iteratorMethod, state0Block.Statements[indexForClosureCreationStatement]); if (closureType != null) { break; } indexForClosureCreationStatement++; } if (closureType != null && indexForClosureCreationStatement < state0Block.Statements.Count) { // then there is a set of statements to add to the preamble block // up to and including "this.<>local := new ClosureClass();" for (int i = currentIndex; i <= indexForClosureCreationStatement; i++) { // preambleBlock.Statements.Add(state0Block.Statements[i]); if (state0Block.Statements[i] == null) continue; contractInitializer.Add((Statement)state0Block.Statements[i].Clone()); // state0Block.Statements[i] = null; } // Some number of assignment statements of the form "this.local.f := f;" where "f" is a parameter // Or of the form local.f := f; // that is captured by the closure. int endOfAssignmentsToClosureFields = indexForClosureCreationStatement + 1; for (; endOfAssignmentsToClosureFields < state0Block.Statements.Count; endOfAssignmentsToClosureFields++) { Statement s = state0Block.Statements[endOfAssignmentsToClosureFields]; if (s == null) continue; if (s.NodeType == NodeType.Nop) continue; AssignmentStatement assign = s as AssignmentStatement; if (assign == null) break; MemberBinding mb = assign.Target as MemberBinding; if (mb == null) break; if (mb.TargetObject == null) break; if (mb.TargetObject.Type != closureType) break; } for (int i = indexForClosureCreationStatement + 1; i < endOfAssignmentsToClosureFields; i++) { // preambleBlock.Statements.Add(state0Block.Statements[i]); if (state0Block.Statements[i] == null) continue; contractInitializer.Add((Statement)state0Block.Statements[i].Clone()); // state0Block.Statements[i] = null; // need to null them out so search below can be done starting at beginning of m's body } currentIndex = endOfAssignmentsToClosureFields; } #endif return currentIndex; }
/// <summary> /// Replaces any MemberBindings of the form (this,x) in the methodContract with a method call where the method /// being called is P where x is a private field of the source type that has been marked as [ContractPublicPropertyName("P")]. /// </summary> /// <param name="targetType"></param> /// <param name="sourceType"></param> /// <param name="methodContract"></param> internal static void ReplacePrivateFieldsThatHavePublicProperties(TypeNode targetType, TypeNode sourceType, MethodContract methodContract, ContractNodes contractNodes ) { Contract.Requires(sourceType != null); Dictionary<Field, Method> field2Getter = new Dictionary<Field, Method>(); for (int i = 0, n = /*sourceType.Members == null ? 0 : */ sourceType.Members.Count; i < n; i++) { Field f = sourceType.Members[i] as Field; if (f == null) continue; string propertyName = HelperMethods.GetStringFromAttribute(f, ContractNodes.SpecPublicAttributeName); if (propertyName != null) { Property p = sourceType.GetProperty(Identifier.For(propertyName)); if (p != null) { field2Getter.Add(f, p.Getter); } } } if (0 < field2Getter.Count) { SubstitutePropertyGetterForField s = new SubstitutePropertyGetterForField(field2Getter); s.Visit(methodContract); } return; }
private static int ContractStartInMoveNext(ContractNodes contractNodes, Method moveNext, out int statementIndex, Method origMethod) { Contract.Requires(contractNodes != null); Contract.Requires(moveNext != null); Contract.Requires(moveNext.Body != null); Contract.Requires(moveNext.Body.Statements != null); Contract.Ensures(Contract.ValueAtReturn(out statementIndex) >= 0); Contract.Ensures(Contract.Result<int>() >= -1); Contract.Ensures(Contract.Result<int>() < moveNext.Body.Statements.Count); Block body = moveNext.Body; bool isAsync = moveNext.IsAsync; statementIndex = 0; var blocks = body.Statements; bool stateIsRead = false; var fieldScanner = new HelperMethods.ExpressionScanner((field, isStore) => { if (isStore) return; if (field != null && field.Name != null && field.Name.Name.Contains("<>") && field.Name.Name.Contains("__state")) { stateIsRead = true; } }); fieldScanner.Visit(body.Statements); // Dictionary tracks local variable values and a bit saying if the value is the state (in that case it is 0). Dictionary<Variable, Pair<int, EvalKind>> env = new Dictionary<Variable, Pair<int, EvalKind>>(); int currentBlockIndex = 0; bool seenFinalCompare = false; bool lastBranchNonConditional = false; while (currentBlockIndex >= 0 && currentBlockIndex < blocks.Count) { var block = blocks[currentBlockIndex] as Block; if (block == null || block.Statements == null) continue; for (int i = 0; i < block.Statements.Count; i++) { var stmt = block.Statements[i]; if (stmt == null) continue; if (contractNodes.IsContractOrValidatorOrAbbreviatorCall(stmt)) { statementIndex = i; return currentBlockIndex; } Branch branch = stmt as Branch; if (branch != null) { if (branch.Condition == null) { currentBlockIndex = FindTargetBlock(blocks, branch.Target, currentBlockIndex); lastBranchNonConditional = true; goto OuterLoop; } var value = EvaluateExpression(branch.Condition, env, seenFinalCompare, isAsync); if (value.Two == EvalKind.IsDisposingTest) { if (value.One != 0) { return FindTargetBlock(blocks, branch.Target, currentBlockIndex); } if (i + 1 < block.Statements.Count) { statementIndex = i + 1; return currentBlockIndex; } if (currentBlockIndex + 1 < body.Statements.Count) { return currentBlockIndex + 1; } return -1; } if (seenFinalCompare) { // must be the end. statementIndex = i; return currentBlockIndex; } seenFinalCompare = (value.Two == EvalKind.IsFinalCompare || value.Two == EvalKind.IsStateValue); if (value.One != 0) { currentBlockIndex = FindTargetBlock(blocks, branch.Target, currentBlockIndex); goto OuterLoop; } continue; } if (isAsync && lastBranchNonConditional) { // not a branch and last one was non-conditional // must be the end. statementIndex = i; return currentBlockIndex; } var swtch = stmt as SwitchInstruction; if (swtch != null) { if (seenFinalCompare) { // must be the end. statementIndex = i; return currentBlockIndex; } var value = EvaluateExpression(swtch.Expression, env, seenFinalCompare, isAsync); if (value.One < 0 || swtch.Targets == null || value.One >= swtch.Targets.Count) { // fall through if (isAsync) { seenFinalCompare = true; } continue; } currentBlockIndex = FindTargetBlock(blocks, swtch.Targets[value.One], currentBlockIndex); // assume seen final compare seenFinalCompare = true; goto OuterLoop; } if (HelperMethods.IsClosureCreation(origMethod, stmt) != null) { // end of trace statementIndex = i; return currentBlockIndex; } AssignmentStatement assign = stmt as AssignmentStatement; if (assign != null) { if (assign.Source is ConstructArray) { // treat as beginning of contract (typically a params array) statementIndex = i; return currentBlockIndex; } var value = EvaluateExpression(assign.Source, env, seenFinalCompare, isAsync); if (IsThisDotState(assign.Target)) { // end of trace if (i + 1 < block.Statements.Count) { statementIndex = i + 1; return currentBlockIndex; } if (currentBlockIndex + 1 < body.Statements.Count) { return currentBlockIndex + 1; } return -1; } if (IsDoFinallyBodies(assign.Target) && !stateIsRead) { // end of trace if (i + 1 < block.Statements.Count) { statementIndex = i + 1; return currentBlockIndex; } if (currentBlockIndex + 1 < body.Statements.Count) { return currentBlockIndex + 1; } return -1; } var target = assign.Target as Variable; if (target != null) env[target] = value; if (seenFinalCompare && !(value.Two == EvalKind.IsDisposingTest)) { // must be the end. statementIndex = i; return currentBlockIndex; } continue; } if (seenFinalCompare) { // must be the end. statementIndex = i; return currentBlockIndex; } switch (stmt.NodeType) { case NodeType.Nop: case NodeType.ExpressionStatement: // skip: C# compiler emits funky pushes then pops break; default: Contract.Assume(false, string.Format("Unexpected node type '{0}'", stmt.NodeType)); return -1; } } // next block in body currentBlockIndex++; OuterLoop: ; } return -1; }
// Public API /// <summary> /// Modifies <paramref name="assembly"/> by extracting any Code Contracts /// from the method bodies in the assembly. /// <param name="assembly"> /// The assembly to which the contracts will be added (i.e., the AST for the assembly /// will be enriched with method contracts and object invariants). /// </param> /// <param name="referenceAssembly"> /// When not null, then the contracts are extracted from this assembly and then copied over /// to <paramref name="assembly"/>. Note that in that case, no contracts are extracted /// directly from <paramref name="assembly"/>: all of the contracts in <paramref name="assembly"/> /// after this method returns came from this assembly. /// </param> /// <param name="contracts"> /// When not null, this will be used for the definitions of the contract methods (and /// attributes) in <paramref name="assembly"/> (or <paramref name="referenceAssembly"/>, if that /// is not null). When null, then we will make an effort to find the contract methods. In /// either case, the definitions might be found within <paramref name="assembly"/> (or /// <paramref name="referenceAssembly"/>) anyway. /// </param> /// <param name="targetContractNodes"> /// This parameter is used for the definitions of the contract methods (and /// attributes) that are the definitions that are embedded within the contracts, /// e.g., the definition of the ForAll method are found in the return value. /// It may be the same as <paramref name="contracts"/>. If it is passed in as null, /// then it will be filled in with the nodes used by the Extractor. /// </param> /// <param name="useClousotExtractor"> /// When true, use a "Clousot" extractor, which does some extra processing needed for static /// analysis. /// </param> /// <returns> /// True iff extraction was possible. (I.e., a set of contractNodes was found to use for /// the extraction --- it does *not* guarantee that any contracts were found in the assembly.) /// </returns> /// </summary> /// public static bool ExtractContracts(AssemblyNode /*!*/ assembly, AssemblyNode /*?*/ referenceAssembly, ContractNodes /*?*/ contracts, ContractNodes /*?*/ backupContracts, ContractNodes /*?*/ targetContractNodes, out ContractNodes /*?*/ contractNodesUsedToExtract, Action <CompilerError> /*?*/ errorHandler, bool useClousotExtractor) { Contract.Requires(assembly != null); AssemblyNode assemblyToVisit = referenceAssembly ?? assembly; // Try to use supplied contracts, if present. But don't just try extracting and somehow // figuring out if any contracts had been present. Instead, see if: // a) the contract methods are defined in the assembly we are extracting from, or // b) the assembly reference microsoft.contracts.dll (the backup contracts and we found that assembly) // c) the assembly we are extracting from has an external reference to the assembly // the supplied contract methods came from. // d) the contracts found in mscorlib // // see if the assembly references the backup contracts (Microsoft.Contracts.dll) contractNodesUsedToExtract = IdentifyContractAssemblyIfReferenced(backupContracts, assemblyToVisit); // see if assembly defines the contracts itself if (contractNodesUsedToExtract == null) { contractNodesUsedToExtract = ContractNodes.GetContractNodes(assemblyToVisit, errorHandler); } // see if the assembly references the supplied contract assembly if (contractNodesUsedToExtract == null) { contractNodesUsedToExtract = IdentifyContractAssemblyIfReferenced(contracts, assemblyToVisit); } // see if the contracts are in the system assembly if (contractNodesUsedToExtract == null && assemblyToVisit != SystemTypes.SystemAssembly) { contractNodesUsedToExtract = ContractNodes.GetContractNodes(SystemTypes.SystemAssembly, errorHandler); } if (contractNodesUsedToExtract == null) { return(false); } var fSharp = false; // TODO: Thread the program options through here somehow and let this be specified as an option Contract.Assume(assemblyToVisit.Attributes != null); foreach (var attr in assemblyToVisit.Attributes) { Contract.Assume(attr != null); Contract.Assume(attr.Type != null); Contract.Assume(attr.Type.Name != null); Contract.Assume(attr.Type.Name.Name != null); if (attr.Type.Name.Name.Contains("FSharpInterfaceDataVersionAttribute")) { fSharp = true; break; } } var ultimateTarget = (referenceAssembly != null) ? assembly : null; Contract.Assert(assembly != null); ExtractorVisitor ev = useClousotExtractor ? new ClousotExtractor(contractNodesUsedToExtract, ultimateTarget, assembly, errorHandler) : new ExtractorVisitor(contractNodesUsedToExtract, ultimateTarget, assembly, false, fSharp); ev.Visit(assemblyToVisit); if (!useClousotExtractor) { FilterForRuntime eoar = new FilterForRuntime(contractNodesUsedToExtract, targetContractNodes); assemblyToVisit = eoar.TransformForTarget(assemblyToVisit); } if (referenceAssembly != null) { CopyOutOfBandContracts coob = new CopyOutOfBandContracts(assembly, referenceAssembly, contractNodesUsedToExtract, targetContractNodes); coob.VisitAssembly(referenceAssembly); } return(true); }
// Constructors /// <summary> /// /// </summary> /// <param name="contractNodes"></param> /// <param name="targetContractNodes"></param> /// <param name="ultimateTargetAssembly">specify X if extracting from X.Contracts.dll, otherwise null</param> public ExtractorVisitor(ContractNodes /*!*/ contractNodes, AssemblyNode ultimateTargetAssembly, AssemblyNode realAssembly) : this(contractNodes, ultimateTargetAssembly, realAssembly, false, false) { Contract.Requires(contractNodes != null); Contract.Requires(realAssembly != null); }
public MethodBodyChecker(Action<CompilerError> handleError, ContractNodes usedToExtract) : base(handleError, usedToExtract) { // F: Contract.Requires(handleError != null); Contract.Requires(usedToExtract != null); }
public ForwardingDuplicator(Module /*!*/ module, TypeNode type, ContractNodes contractNodes, ContractNodes targetContractNodes) : base(module, type) { this.contractNodes = contractNodes; this.targetContractNodes = targetContractNodes; }
public VisibilityChecker(Action<CompilerError> errorHandler, ContractNodes usedToExtract) { Contract.Requires(errorHandler != null); this.errorHandler = errorHandler; this.contractNodes = usedToExtract; }
public Decompiler(ContractNodes cns) { this.contractNodes = cns; }
public PostExtractorChecker( ContractNodes usedToExtract, Action<System.CodeDom.Compiler.CompilerError> errorHandler, bool allowPreconditionsInOverrides, bool fSharp, bool explicitUserValidations, bool addInterfaceWrappersWhenNeeded, int runtimeCheckingLevel) { Contract.Requires(errorHandler != null); Contract.Requires(usedToExtract != null); this.m_errorHandler = errorHandler; this.allowPreconditionsInOverrides = allowPreconditionsInOverrides; this.explicitUserValidations = explicitUserValidations; this.addInterfaceWrappersWhenNeeded = addInterfaceWrappersWhenNeeded; this.runtimeCheckingLevel = runtimeCheckingLevel; this.purityChecker = new PurityChecker(this.HandleError, fSharp, usedToExtract); this.preconditionChecker = new PreconditionChecker(this.HandleError, usedToExtract); this.postconditionChecker = new PostconditionChecker(this.HandleError, fSharp); this.invariantCallChecker = new CheckForCallsToInvariantMethods(this); this.methodBodyChecker = new MethodBodyChecker(this.HandleError, usedToExtract); this.invariantChecker = new InvariantChecker(this.HandleError, usedToExtract); this.contractNodes = usedToExtract; this.visibilityChecker = new VisibilityChecker(this.HandleError, usedToExtract); this.invariantMethods = new TrivialHashtable(0); }
public FilterForRuntime(ContractNodes contractNodes, ContractNodes targetContractNodes) { this.contractNodes = contractNodes; this.targetContractNodes = targetContractNodes; }