private void InjectStaticInitializerIfNoneSpecified(TypeNode typeNode){ if (typeNode.NodeType == NodeType.EnumNode) return; MemberList staticCons = typeNode.GetMembersNamed(StandardIds.CCtor); if (staticCons != null && staticCons.Count > 0) return; StatementList statements = null; MemberList members = typeNode.Members; for (int i = 0, n = members == null ? 0 : members.Count; i < n; i++){ Field f = members[i] as Field; if (f == null) continue; if (!f.IsStatic) continue; if (f.IsLiteral) continue; if (f.Initializer == null) continue; statements = new StatementList(1); break; } if (statements == null && typeNode.Contract != null && typeNode.Contract.FrameField != null) statements = new StatementList(1); if (statements != null){ FieldInitializerBlock finitBlock = new FieldInitializerBlock(typeNode, true); statements.Add(finitBlock); StaticInitializer cctor = new StaticInitializer(typeNode, null, new Block(statements)); typeNode.Members.Add(cctor); if (typeNode.PartiallyDefines != null){ staticCons = typeNode.PartiallyDefines.GetMembersNamed(StandardIds.CCtor); if (staticCons == null || staticCons.Count == 0){ finitBlock.Type = typeNode.PartiallyDefines; cctor.DeclaringType = typeNode.PartiallyDefines; typeNode.PartiallyDefines.Members.Add(cctor); } } } }
/// <summary> /// Returns correct version of the ContinueWith method. /// </summary> /// <remarks> /// This function returns ContinueWith overload that takes TaskContinuationOptions. /// </remarks> private static Method GetContinueWithMethod(Class closureClass, TypeNode taskTemplate, TypeNode taskType) { var continueWithCandidates = taskTemplate.GetMembersNamed(Identifier.For("ContinueWith")); // Looking for an overload with TaskContinuationOptions const int expectedNumberOfArguments = 2; for (int i = 0; i < continueWithCandidates.Count; i++) { var cand = continueWithCandidates[i] as Method; if (cand == null) continue; // For non-generic version we're looking for ContinueWith(Action<Task>, TaskContinuationOptions) if (!taskType.IsGeneric) { if (cand.IsGeneric) continue; if (cand.ParameterCount != expectedNumberOfArguments) continue; if (cand.Parameters[0].Type.GetMetadataName() != "Action`1") continue; if (cand.Parameters[1].Type.GetMetadataName() != "TaskContinuationOptions") continue; return cand; } // For generic version we're looking for ContinueWith(Func<Task, T>, TaskContinuationOptions) if (!cand.IsGeneric) continue; if (cand.TemplateParameters.Count != 1) continue; if (cand.ParameterCount != expectedNumberOfArguments) continue; if (cand.Parameters[0].Type.GetMetadataName() != "Func`2") continue; if (cand.Parameters[1].Type.GetMetadataName() != "TaskContinuationOptions") continue; // now create instance, first of task var taskInstance = taskTemplate.GetTemplateInstance( closureClass.DeclaringModule, taskType.TemplateArguments[0]); // ST: some black magic is happening, but it seems it is required to get ContinueWith // from generic instantiated version of the task var candMethod = (Method)taskInstance.GetMembersNamed(Identifier.For("ContinueWith"))[i]; // Candidate method would have following signature: // Task<T> ContinueWith(Task<T> t) for generic version return candMethod.GetTemplateInstance(null, taskType); } return null; }
public RuntimeContractMethods(TypeNode userContractType, ContractNodes contractNodes, AssemblyNode targetAssembly, bool throwOnFailure, int rewriteLevel, bool publicSurfaceOnly, bool callSiteRequires, int recursionGuard, bool hideFromDebugger, bool userExplicitValidation ) { this.contractNodes = contractNodes; this.targetAssembly = targetAssembly; this.ThrowOnFailure = throwOnFailure; this.RewriteLevel = rewriteLevel; this.PublicSurfaceOnly = publicSurfaceOnly; this.CallSiteRequires = callSiteRequires; this.regularRecursionGuard = recursionGuard; this.HideFromDebugger = hideFromDebugger; this.UseExplicitValidation = userExplicitValidation; // extract methods from user methods #region Get the user-specified rewriter methods (optional) REVIEW!! Needs a lot of error handling if (userContractType != null) { Method method = null; MethodList reqMethods = userContractType.GetMethods(Identifier.For("Requires"), SystemTypes.Boolean, SystemTypes.String, SystemTypes.String); for (int i = 0; i < reqMethods.Count; i++) { method = reqMethods[i]; if (method != null) { if (method.TemplateParameters == null || method.TemplateParameters.Count != 1) { /*if (method != null) */ this.requiresMethod = method; } else { this.requiresWithExceptionMethod = method; } } } method = userContractType.GetMethod(Identifier.For("Ensures"), SystemTypes.Boolean, SystemTypes.String, SystemTypes.String); if (method != null) this.ensuresMethod = method; method = userContractType.GetMethod(Identifier.For("EnsuresOnThrow"), SystemTypes.Boolean, SystemTypes.String, SystemTypes.String, SystemTypes.Exception); if (method != null) this.ensuresOnThrowMethod = method; method = userContractType.GetMethod(Identifier.For("Invariant"), SystemTypes.Boolean, SystemTypes.String, SystemTypes.String); if (method != null) this.invariantMethod = method; method = userContractType.GetMethod(Identifier.For("Assert"), SystemTypes.Boolean, SystemTypes.String, SystemTypes.String); if (method != null) this.assertMethod = method; method = userContractType.GetMethod(Identifier.For("Assume"), SystemTypes.Boolean, SystemTypes.String, SystemTypes.String); if (method != null) this.assumeMethod = method; // Need to make sure that the type ContractFailureKind is the one used in the user-supplied methods, which is not necessarily // the one that is defined in the assembly that defines the contract class. For instance, extracting/rewriting from a 4.0 assembly // but where the user-supplied assembly is pre-4.0. var mems = userContractType.GetMembersNamed(ContractNodes.ReportFailureName); TypeNode contractFailureKind = contractNodes.ContractFailureKind; //if (mems != null) { foreach(var mem in mems){ method = mem as Method; if (method == null) continue; if (method.Parameters.Count != 4) continue; if (method.Parameters[0].Type.Name != contractNodes.ContractFailureKind.Name) continue; if (method.Parameters[1].Type != SystemTypes.String) continue; if (method.Parameters[2].Type != SystemTypes.String) continue; if (method.Parameters[3].Type != SystemTypes.Exception) continue; this.failureMethod = method; contractFailureKind = method.Parameters[0].Type; break; } } if (this.failureMethod == null) { mems = userContractType.GetMembersNamed(ContractNodes.RaiseContractFailedEventName); // if (mems != null) { foreach (var mem in mems) { method = mem as Method; if (method == null) continue; if (method.Parameters.Count != 4) continue; if (method.Parameters[0].Type.Name.UniqueIdKey != contractNodes.ContractFailureKind.Name.UniqueIdKey) continue; if (method.Parameters[1].Type != SystemTypes.String) continue; if (method.Parameters[2].Type != SystemTypes.String) continue; if (method.Parameters[3].Type != SystemTypes.Exception) continue; this.raiseFailureEventMethod = method; contractFailureKind = method.Parameters[0].Type; break; } } } else { method = userContractType.GetMethod(ContractNodes.RaiseContractFailedEventName, contractFailureKind, SystemTypes.String, SystemTypes.String, SystemTypes.Exception); if (method != null) this.raiseFailureEventMethod = method; } if (this.raiseFailureEventMethod != null) { // either take all both RaiseContractFailedEvent and TriggerFailure or neither method = userContractType.GetMethod(ContractNodes.TriggerFailureName, contractFailureKind, SystemTypes.String, SystemTypes.String, SystemTypes.String, SystemTypes.Exception); if (method != null) this.triggerFailureMethod = method; } } #endregion Get the user-specified rewriter methods (optional) REVIEW!! Needs a lot of error handling }
private static Member FuzzilyGetMatchingMember(TypeNode t, Member m) { Contract.Requires(t != null); Contract.Requires(m != null); var candidates = t.GetMembersNamed(m.Name); Contract.Assert(candidates != null, "Clousot can prove it"); for (int i = 0, n = candidates.Count; i < n; i++) { Member mem = candidates[i]; if (mem == null) continue; if (!mem.Name.Matches(m.Name)) continue; // type case statement would be *so* nice right now // Can't test the NodeType because for mscorlib.Contracts, structs are read in as classes // because they don't extend the "real" System.ValueType, but the one declared in mscorlib.Contracts. //if (mem.NodeType != m.NodeType) continue; Method x = mem as Method; // handles regular Methods and InstanceInitializers if (x != null) { Method m_prime = m as Method; if (m_prime == null) continue; if ((x.TemplateParameters == null) != (m_prime.TemplateParameters == null)) continue; if (FuzzyEqual(m_prime.Parameters, x.Parameters) && FuzzyEqual(m_prime.ReturnType, x.ReturnType) && TemplateParameterCount(x) == TemplateParameterCount(m_prime)) { return mem; } continue; } Field memAsField = mem as Field; if (memAsField != null) { Field mAsField = m as Field; if (mAsField == null) continue; if (FuzzyEqual(mAsField.Type, memAsField.Type)) return mem; continue; } Event memAsEvent = mem as Event; if (memAsEvent != null) { Event mAsEvent = m as Event; if (mAsEvent == null) continue; if (FuzzyEqual(mAsEvent.HandlerType, memAsEvent.HandlerType)) return mem; continue; } Property memAsProperty = mem as Property; if (memAsProperty != null) { Property mAsProperty = m as Property; if (mAsProperty == null) continue; if (FuzzyEqual(mAsProperty.Type, memAsProperty.Type)) return mem; continue; } TypeNode memAsTypeNode = mem as TypeNode; // handles Class, Interface, etc. if (memAsTypeNode != null) { TypeNode mAsTypeNode = m as TypeNode; if (mAsTypeNode == null) continue; if (FuzzyEqual(mAsTypeNode, memAsTypeNode)) return mem; continue; } Contract.Assume(false, "Pseudo-typecase failed to find a match"); } return null; }