private static bool IsSpecPublic(Field f) { // F: Contract.Requires(f != null); return f.Attributes.HasAttribute(ContractNodes.SpecPublicAttributeName); }
/// <summary> /// Find shadow field in given type corresponding to field. /// </summary> public static Field FindShadow(this TypeNode parent, Field field) { if (field == null || field.Name == null) { return null; } MemberList members = parent.GetMembersNamed(field.Name); for (int i = 0, n = members == null ? 0 : members.Count; i < n; i++) { Field f = members[i] as Field; if (f != null) return f; } return null; }
private Field GetReturnValueClosureField(TypeNode declaringType, TypeNode resultType, FieldFlags flags, int uniqueKey) { Contract.Requires(declaringType != null); Contract.Assume(declaringType.Template == null); Identifier name = Identifier.For("_result" + uniqueKey.ToString()); // unique name for this field Field f = declaringType.GetField(name); if (f != null) return f; f = new Field(declaringType, null, flags, name, resultType, null); declaringType.Members.Add(f); // remember we added it so we can make it part of initializations if (f.IsStatic) { topLevelStaticResultField = f; } else { topLevelClosureResultField = f; } return f; }
public static List<int> FieldElementsPeerPositions(Field f) { List<int> res = new List<int>(); if (f == null) return res; AttributeList al = f.GetAllAttributes(SystemTypes.ElementsPeerAttribute); if (al == null) return res; foreach (AttributeNode attr in al) { ExpressionList exprs = attr.Expressions; int value = -10; if (exprs == null || exprs.Count == 0) value = -1; // default value for attribute w/o param else { Expression arg = exprs[0]; Literal lit = arg as Literal; if (lit != null && lit.Value is int) value = (int)lit.Value; } if (value == -1) // all positions are ElementsPeer { return ElementsPositions(f.Type); } else // a specific type argument is ElementsPeer { res.Add(value); } } return res; }
public override void VisitField(Field field) { base.VisitField(field); var type = HelperMethods.Unspecialize(field.Type); if (type == contractClass) { if (field.Type.TemplateArguments != null) { var inst = this.OriginalType.GetTemplateInstance(field.Type, field.Type.TemplateArguments); field.Type = inst; } else { field.Type = this.OriginalType; } } }
private static string GetFieldQualifiers(Field field) { string qualifiers = string.Empty; if (field.IsStatic) qualifiers += "static "; return qualifiers; }
public override void VisitField(Field field) { if (field == null) return; this.CheckField(field); }
private void PrepareGuardedClass(TypeNode typeNode) { SpecSharpCompilerOptions options = this.currentOptions as SpecSharpCompilerOptions; if (!(options != null && (options.DisableGuardedClassesChecks || options.Compatibility))) { if (typeNode is Class && typeNode.Contract != null && (typeNode.Contract.InvariantCount > 0 || typeNode.Contract.ModelfieldContractCount > 0) || typeNode is Class && this.currentPreprocessorDefinedSymbols != null && this.currentPreprocessorDefinedSymbols.ContainsKey("GuardAllClasses")) { if (typeNode.Interfaces == null) { typeNode.Interfaces = new InterfaceList(); } if (typeNode.Template == null) { //we have to be careful when we are passed a typeNode of a specialized generic type as it shares the contract of the 'real' generic typeNode #region Add the field "frame" to the class. Field frameField = new Field(typeNode, null, FieldFlags.Public, Identifier.For("SpecSharp::frameGuard"), SystemTypes.Guard, null); frameField.CciKind = CciMemberKind.Auxiliary; typeNode.Contract.FrameField = frameField; typeNode.Members.Add(frameField); This thisParameter = new This(typeNode); Method frameGetter = new Method(typeNode, NoDefaultExpose(), Identifier.For("get_SpecSharp::FrameGuard"), null, OptionalModifier.For(SystemTypes.NonNullType, SystemTypes.Guard), new Block(new StatementList(new Return(new BinaryExpression(new MemberBinding(thisParameter, frameField), new Literal(SystemTypes.NonNullType, SystemTypes.Type), System.Compiler.NodeType.ExplicitCoercion, OptionalModifier.For(SystemTypes.NonNullType, SystemTypes.Guard)))))); // Pretend this method is [Delayed] so that we can call it from a delayed constructor. frameGetter.Attributes.Add(new AttributeNode(new Literal(ExtendedRuntimeTypes.DelayedAttribute, SystemTypes.Type), null, AttributeTargets.Method)); frameGetter.CciKind = CciMemberKind.FrameGuardGetter; frameGetter.Attributes.Add(new AttributeNode(new Literal(SystemTypes.PureAttribute, SystemTypes.Type), null, AttributeTargets.Method)); frameGetter.Flags = MethodFlags.Public | MethodFlags.HideBySig | MethodFlags.SpecialName; frameGetter.CallingConvention = CallingConventionFlags.HasThis; frameGetter.ThisParameter = thisParameter; typeNode.Contract.FramePropertyGetter = frameGetter; typeNode.Members.Add(frameGetter); Property frameProperty = new Property(typeNode, null, PropertyFlags.None, Identifier.For("SpecSharp::FrameGuard"), frameGetter, null); typeNode.Members.Add(frameProperty); typeNode.Contract.FrameProperty = frameProperty; #endregion typeNode.Contract.InitFrameSetsMethod = new Method(typeNode, NoDefaultExpose(), Identifier.For("SpecSharp::InitGuardSets"), null, SystemTypes.Void, null); typeNode.Contract.InitFrameSetsMethod.CciKind = CciMemberKind.Auxiliary; typeNode.Contract.InitFrameSetsMethod.Flags = MethodFlags.Public | MethodFlags.HideBySig | MethodFlags.SpecialName; } } } }
internal static void TryAddDebuggerBrowsableNeverAttribute(Field field) { Contract.Requires(field != null); TryAddDebuggerBrowsableNeverAttribute(field, System.AttributeTargets.Field); }
private static bool FieldAssociatedWithParameter(Field field, Method originalMethod, out Parameter p) { string fname = field.Name.Name; if (fname.EndsWith("__this")) { // check that it is not a nested one if (fname.Length > 8 && !fname.Substring(2, fname.Length - 8).Contains("__")) { p = originalMethod.ThisParameter; return true; } } foreach (Parameter par in originalMethod.Parameters) { string pname = par.Name.Name; if (fname == pname) { p = par; return true; } } p = null; return false; }
public static bool IsClosureField(TypeNode container, Field field) { Contract.Requires(container != null); Contract.Requires(field != null); var type = Unspecialize(field.DeclaringType); if (IsClosureType(container, type)) return true; // can be a direct member of a type inside container for caching delegates if (!field.IsPrivate) return false; if (!(field.Type.IsDelegateType())) return false; if (!IsInsideOf(field, container)) return false; if (!IsCompilerGenerated(field)) return false; return true; }
bool IsAccessibleFrom(Field field, Method from) { }
public override Expression VisitLocal(Local local) { if (HelperMethods.IsClosureType(this.declaringType, local.Type)) { MemberBinding mb; if (!closureLocals.TryGetValue(local, out mb)) { // Forwarder would be null, if enclosing method with async closure is not generic var localType = forwarder != null ? forwarder.VisitTypeReference(local.Type) : local.Type; var closureField = new Field(this.closureClass, null, FieldFlags.Public, local.Name, localType, null); this.closureClass.Members.Add(closureField); mb = new MemberBinding(this.checkMethod.ThisParameter, closureField); closureLocals.Add(local, mb); // initialize the closure field var instantiatedField = GetMemberInstanceReference(closureField, this.closureClassInstance); this.ClosureInitializer.Statements.Add(new AssignmentStatement(new MemberBinding(this.ClosureLocal, instantiatedField), local)); } return mb; } return local; }
private static Expression CreateProperResultAccess(ReturnValue returnValue, Expression closureObject, Field resultField) { Contract.Requires(returnValue != null); Contract.Requires(resultField != null); var fieldAccess = new MemberBinding(closureObject, resultField); if (resultField.Type != returnValue.Type) { // must cast to generic type expected in this context (box instance unbox.any Generic) return new BinaryExpression(new BinaryExpression(fieldAccess, new Literal(resultField.Type), NodeType.Box), new Literal(returnValue.Type), NodeType.UnboxAny); } else { return fieldAccess; } }
private Method FindAndInstantiateBaseClassInvariantMethod(Class asClass, out Field baseReentrancyFlag) { baseReentrancyFlag = null; if (asClass == null || asClass.BaseClass == null) return null; if (!this.Emit(RuntimeContractEmitFlags.InheritContracts)) return null; // don't call base class invariant if we don't inherit var baseClass = asClass.BaseClass; if (!this.InheritInvariantsAcrossAssemblies && (baseClass.DeclaringModule != asClass.DeclaringModule)) return null; var result = baseClass.GetMethod(Identifier.For("$InvariantMethod$"), null); if (result != null && !HelperMethods.IsVisibleFrom(result, asClass)) return null; if (result == null && baseClass.Template != null) { // instantiation of generated method has not happened. var generic = baseClass.Template.GetMethod(Identifier.For("$InvariantMethod$"), null); if (generic != null) { if (!HelperMethods.IsVisibleFrom(generic, asClass)) return null; // generate proper reference. result = GetMethodInstanceReference(generic, baseClass); } } // extract base reentrancy flag if (result != null) { var instantiatedParent = result.DeclaringType; baseReentrancyFlag = instantiatedParent.GetField(Identifier.For("$evaluatingInvariant$")); if (baseReentrancyFlag == null && baseClass.Template != null) { // instantiation of generated baseReentrancy flag has not happened. var generic = baseClass.Template.GetField(Identifier.For("$evaluatingInvariant$")); if (generic != null) { if (HelperMethods.IsVisibleFrom(generic, asClass)) { baseReentrancyFlag = GetFieldInstanceReference(generic, baseClass); } } } } return result; }
public override void VisitTypeNode(TypeNode typeNode) { if (typeNode == null) return; if (HelperMethods.IsContractTypeForSomeOtherType(typeNode, this.rewriterNodes) != null) { return; } Method savedInvariantMethod = this.InvariantMethod; Field savedReentrancyFlag = this.ReentrancyFlag; this.InvariantMethod = null; this.ReentrancyFlag = null; var savedState = this.currentState; this.currentState = new CurrentState(typeNode); var savedEmitFlags = this.AdaptRuntimeOptionsBasedOnAttributes(typeNode.Attributes); try { if (this.Emit(RuntimeContractEmitFlags.Invariants) && rewriterNodes.InvariantMethod != null) { InvariantList userWrittenInvariants = typeNode.Contract == null ? null : typeNode.Contract.Invariants; Class asClass = typeNode as Class; Field baseReentrancyFlag; Method baseInvariantMethod = FindAndInstantiateBaseClassInvariantMethod(asClass, out baseReentrancyFlag); if ((userWrittenInvariants != null && 0 < userWrittenInvariants.Count) || baseInvariantMethod != null) { Field reEntrancyFlag = null; var isStructWithExplicitLayout = IsStructWithExplicitLayout(typeNode as Struct); if (isStructWithExplicitLayout) { this.HandleError(new Warning(1044, String.Format("Struct '{0}' has explicit layout and an invariant. Invariant recursion guards will not be emitted and evaluation of invariants may occur too eagerly.", typeNode.FullName), new SourceContext())); } else { #region Find or create re-entrancy flag to the class if (baseReentrancyFlag != null) { // grab base reEntrancyFlag reEntrancyFlag = baseReentrancyFlag; } else { FieldFlags reentrancyFlagProtection; if (typeNode.IsSealed) { reentrancyFlagProtection = FieldFlags.Private | FieldFlags.CompilerControlled; } else if (this.InheritInvariantsAcrossAssemblies) { reentrancyFlagProtection = FieldFlags.Family | FieldFlags.CompilerControlled; } else { reentrancyFlagProtection = FieldFlags.FamANDAssem | FieldFlags.CompilerControlled; } reEntrancyFlag = new Field(typeNode, null, reentrancyFlagProtection, Identifier.For("$evaluatingInvariant$"), SystemTypes.Boolean, null); RewriteHelper.TryAddCompilerGeneratedAttribute(reEntrancyFlag); RewriteHelper.TryAddDebuggerBrowsableNeverAttribute(reEntrancyFlag); typeNode.Members.Add(reEntrancyFlag); } #endregion Add re-entrancy flag to the class } Block newBody = new Block(new StatementList(3)); // newBody ::= // if (this.$evaluatingInvariant$){ // return (true); // don't really return true since this is a void method, but it means the invariant is assumed to hold // this.$evaluatingInvariant$ := true; // try{ // <evaluate invariants and call base invariant method> // } finally { // this.$evaluatingInvariant$ := false; // } Method invariantMethod = new Method( typeNode, new AttributeList(), Identifier.For("$InvariantMethod$"), null, SystemTypes.Void, newBody); RewriteHelper.TryAddCompilerGeneratedAttribute(invariantMethod); invariantMethod.CallingConvention = CallingConventionFlags.HasThis; if (this.InheritInvariantsAcrossAssemblies) invariantMethod.Flags = MethodFlags.Family | MethodFlags.Virtual; else invariantMethod.Flags = MethodFlags.FamANDAssem | MethodFlags.Virtual; invariantMethod.Attributes.Add(new AttributeNode(new MemberBinding(null, this.runtimeContracts.ContractNodes.InvariantMethodAttribute.GetConstructor()), null)); #region call base class invariant if (baseInvariantMethod != null) { newBody.Statements.Add( new ExpressionStatement( new MethodCall( new MemberBinding(invariantMethod.ThisParameter, baseInvariantMethod), null, NodeType.Call, SystemTypes.Void))); } #endregion #region Add re-entrancy test to the method Block invariantExit = new Block(); if (reEntrancyFlag != null) { Block reEntrancyTest = new Block(new StatementList()); reEntrancyTest.Statements.Add( new Branch(new MemberBinding(invariantMethod.ThisParameter, reEntrancyFlag), invariantExit)); reEntrancyTest.Statements.Add( new AssignmentStatement(new MemberBinding(invariantMethod.ThisParameter, reEntrancyFlag), Literal.True) ); newBody.Statements.Add(reEntrancyTest); } #endregion Add re-entrancy test to the method Block invariantChecks = new Block(new StatementList()); if (userWrittenInvariants != null) { #region Filter out invariants that aren't runtime checkable var filteredInvariants = new InvariantList(); foreach (var i in userWrittenInvariants) { if (!EmitInvariant(i, this.skipQuantifiers)) continue; filteredInvariants.Add(i); } #endregion Filter out invariants that aren't runtime checkable #region Duplicate the invariants // need to duplicate the invariants so they aren't shared Duplicator d = new Duplicator(typeNode.DeclaringModule, typeNode); InvariantList duplicatedInvariants = d.VisitInvariantList(filteredInvariants); // F: seems to have the invariant duplictedInvariants != null Contract.Assume(duplicatedInvariants != null); #endregion Duplicate the invariants #region Rewrite the body of the invariant method // then we need to replace calls to Contract.Invariant with calls to Contract.RewriterInvariant // in the body of the invariant method RewriteInvariant rc = new RewriteInvariant(this.runtimeContracts); rc.VisitInvariantList(duplicatedInvariants); #endregion Rewrite the body of the invariant method for (int i = 0, n = duplicatedInvariants.Count; i < n; i++) { Expression e = duplicatedInvariants[i].Condition; var blockExpr = e as BlockExpression; if (blockExpr != null) { invariantChecks.Statements.Add(blockExpr.Block); } else { invariantChecks.Statements.Add(new ExpressionStatement(e)); } } } Block finallyB = new Block(new StatementList(1)); if (reEntrancyFlag != null) { finallyB.Statements.Add( new AssignmentStatement(new MemberBinding(invariantMethod.ThisParameter, reEntrancyFlag), Literal.False) ); } this.cleanUpCodeCoverage.VisitBlock(invariantChecks); Block b = RewriteHelper.CreateTryFinallyBlock(invariantMethod, invariantChecks, finallyB); newBody.Statements.Add(b); newBody.Statements.Add(invariantExit); newBody.Statements.Add(new Return()); // set the field "this.InvariantMethod" to this one so it is used in calls within each method // but don't add it yet to the class so it doesn't get visited! this.InvariantMethod = invariantMethod; this.ReentrancyFlag = reEntrancyFlag; } } base.VisitTypeNode(typeNode); // Now add invariant method to the class if (this.InvariantMethod != null) { typeNode.Members.Add(this.InvariantMethod); } return; } finally { this.InvariantMethod = savedInvariantMethod; this.ReentrancyFlag = savedReentrancyFlag; this.currentState = savedState; this.contractEmitFlags = savedEmitFlags; } }
private Class MakeContractException() { Class contractExceptionType; #region If we're rewriting an assembly for v4 or above and it *isn't* Silverlight (so serialization support is needed), then use new embedded dll as the type if (4 <= TargetPlatform.MajorVersion) { var iSafeSerializationData = SystemTypes.SystemAssembly.GetType(Identifier.For("System.Runtime.Serialization"), Identifier.For("ISafeSerializationData")) as Interface; if (iSafeSerializationData != null) { // Just much easier to write the C# and have the compiler generate everything than to try and create it all manually System.Reflection.Assembly embeddedAssembly; Stream embeddedAssemblyStream; embeddedAssembly = System.Reflection.Assembly.GetExecutingAssembly(); embeddedAssemblyStream = embeddedAssembly.GetManifestResourceStream("Microsoft.Contracts.Foxtrot.InternalException.dll"); byte[] data = new byte[0]; using (var br = new BinaryReader(embeddedAssemblyStream)) { var len = embeddedAssemblyStream.Length; if (len < Int32.MaxValue) data = br.ReadBytes((int)len); AssemblyNode assemblyNode = AssemblyNode.GetAssembly(data, TargetPlatform.StaticAssemblyCache, true, false, true); contractExceptionType = assemblyNode.GetType(Identifier.For(""), Identifier.For("ContractException")) as Class; } if (contractExceptionType == null) throw new RewriteException("Tried to create the ContractException type from the embedded dll, but failed"); var d = new Duplicator(this.targetAssembly, this.RuntimeContractType); d.FindTypesToBeDuplicated(new TypeNodeList(contractExceptionType)); var ct = d.Visit(contractExceptionType); contractExceptionType = (Class)ct; contractExceptionType.Flags |= TypeFlags.NestedPrivate; this.RuntimeContractType.Members.Add(contractExceptionType); return contractExceptionType; } } #endregion contractExceptionType = new Class(this.targetAssembly, this.RuntimeContractType, new AttributeList(), TypeFlags.Class | TypeFlags.NestedPrivate | TypeFlags.Serializable, null, Identifier.For("ContractException"), SystemTypes.Exception, null, null); RewriteHelper.TryAddCompilerGeneratedAttribute(contractExceptionType); var kindField = new Field(contractExceptionType, null, FieldFlags.Private, Identifier.For("_Kind"), contractNodes.ContractFailureKind, null); var userField = new Field(contractExceptionType, null, FieldFlags.Private, Identifier.For("_UserMessage"), SystemTypes.String, null); var condField = new Field(contractExceptionType, null, FieldFlags.Private, Identifier.For("_Condition"), SystemTypes.String, null); contractExceptionType.Members.Add(kindField); contractExceptionType.Members.Add(userField); contractExceptionType.Members.Add(condField); #region Constructor for setting the fields var parameters = new ParameterList(); var kindParam = new Parameter(Identifier.For("kind"), this.contractNodes.ContractFailureKind); var failureParam = new Parameter(Identifier.For("failure"), SystemTypes.String); var usermsgParam = new Parameter(Identifier.For("usermsg"), SystemTypes.String); var conditionParam = new Parameter(Identifier.For("condition"), SystemTypes.String); var innerParam = new Parameter(Identifier.For("inner"), SystemTypes.Exception); parameters.Add(kindParam); parameters.Add(failureParam); parameters.Add(usermsgParam); parameters.Add(conditionParam); parameters.Add(innerParam); var body = new Block(new StatementList()); var ctor = new InstanceInitializer(contractExceptionType, null, parameters, body); ctor.Flags |= MethodFlags.Public | MethodFlags.HideBySig; ctor.CallingConvention = CallingConventionFlags.HasThis; body.Statements.Add(new ExpressionStatement(new MethodCall(new MemberBinding(ctor.ThisParameter, contractExceptionType.BaseClass.GetConstructor(SystemTypes.String, SystemTypes.Exception)), new ExpressionList(failureParam, innerParam)))); body.Statements.Add(new AssignmentStatement(new MemberBinding(ctor.ThisParameter, kindField), kindParam)); body.Statements.Add(new AssignmentStatement(new MemberBinding(ctor.ThisParameter, userField), usermsgParam)); body.Statements.Add(new AssignmentStatement(new MemberBinding(ctor.ThisParameter, condField), conditionParam)); body.Statements.Add(new Return()); contractExceptionType.Members.Add(ctor); #endregion if (SystemTypes.SerializationInfo != null && SystemTypes.SerializationInfo.BaseClass != null) { // Silverlight (e.g.) is a platform that doesn't support serialization. So check to make sure the type really exists. // var baseCtor = SystemTypes.Exception.GetConstructor(SystemTypes.SerializationInfo, SystemTypes.StreamingContext); if (baseCtor != null) { #region Deserialization Constructor parameters = new ParameterList(); var info = new Parameter(Identifier.For("info"), SystemTypes.SerializationInfo); var context = new Parameter(Identifier.For("context"), SystemTypes.StreamingContext); parameters.Add(info); parameters.Add(context); body = new Block(new StatementList()); ctor = new InstanceInitializer(contractExceptionType, null, parameters, body); ctor.Flags |= MethodFlags.Private | MethodFlags.HideBySig; ctor.CallingConvention = CallingConventionFlags.HasThis; // : base(info, context) body.Statements.Add(new ExpressionStatement(new MethodCall(new MemberBinding(ctor.ThisParameter, baseCtor), new ExpressionList(info, context)))); // _Kind = (ContractFailureKind)info.GetInt32("Kind"); var getInt32 = SystemTypes.SerializationInfo.GetMethod(Identifier.For("GetInt32"), SystemTypes.String); body.Statements.Add(new AssignmentStatement( new MemberBinding(new This(), kindField), new MethodCall(new MemberBinding(info, getInt32), new ExpressionList(new Literal("Kind", SystemTypes.String))) )); // _UserMessage = info.GetString("UserMessage"); var getString = SystemTypes.SerializationInfo.GetMethod(Identifier.For("GetString"), SystemTypes.String); body.Statements.Add(new AssignmentStatement( new MemberBinding(new This(), userField), new MethodCall(new MemberBinding(info, getString), new ExpressionList(new Literal("UserMessage", SystemTypes.String))) )); // _Condition = info.GetString("Condition"); body.Statements.Add(new AssignmentStatement( new MemberBinding(new This(), condField), new MethodCall(new MemberBinding(info, getString), new ExpressionList(new Literal("Condition", SystemTypes.String))) )); body.Statements.Add(new Return()); contractExceptionType.Members.Add(ctor); #endregion #region GetObjectData var securityCriticalCtor = SystemTypes.SecurityCriticalAttribute.GetConstructor(); var securityCriticalAttribute = new AttributeNode(new MemberBinding(null, securityCriticalCtor), null, System.AttributeTargets.Method); var attrs = new AttributeList(securityCriticalAttribute); parameters = new ParameterList(); info = new Parameter(Identifier.For("info"), SystemTypes.SerializationInfo); context = new Parameter(Identifier.For("context"), SystemTypes.StreamingContext); parameters.Add(info); parameters.Add(context); body = new Block(new StatementList()); var getObjectDataName = Identifier.For("GetObjectData"); var getObjectData = new Method(contractExceptionType, attrs, getObjectDataName, parameters, SystemTypes.Void, body); getObjectData.CallingConvention = CallingConventionFlags.HasThis; // public override getObjectData.Flags = MethodFlags.Public | MethodFlags.Virtual; // base.GetObjectData(info, context); var baseGetObjectData = SystemTypes.Exception.GetMethod(getObjectDataName, SystemTypes.SerializationInfo, SystemTypes.StreamingContext); body.Statements.Add(new ExpressionStatement( new MethodCall(new MemberBinding(new This(), baseGetObjectData), new ExpressionList(info, context), NodeType.Call, SystemTypes.Void) )); // info.AddValue("Kind", _Kind); var addValueObject = SystemTypes.SerializationInfo.GetMethod(Identifier.For("AddValue"), SystemTypes.String, SystemTypes.Object); body.Statements.Add(new ExpressionStatement( new MethodCall(new MemberBinding(info, addValueObject), new ExpressionList(new Literal("Kind", SystemTypes.String), new BinaryExpression(new MemberBinding(new This(), kindField), new Literal(contractNodes.ContractFailureKind), NodeType.Box)), NodeType.Call, SystemTypes.Void) )); // info.AddValue("UserMessage", _UserMessage); body.Statements.Add(new ExpressionStatement( new MethodCall(new MemberBinding(info, addValueObject), new ExpressionList(new Literal("UserMessage", SystemTypes.String), new MemberBinding(new This(), userField)), NodeType.Call, SystemTypes.Void) )); // info.AddValue("Condition", _Condition); body.Statements.Add(new ExpressionStatement( new MethodCall(new MemberBinding(info, addValueObject), new ExpressionList(new Literal("Condition", SystemTypes.String), new MemberBinding(new This(), condField)), NodeType.Call, SystemTypes.Void) )); body.Statements.Add(new Return()); contractExceptionType.Members.Add(getObjectData); #endregion } } this.RuntimeContractType.Members.Add(contractExceptionType); return contractExceptionType; }
public static bool FieldIsAdditive(Field field) { if (field == null) return false; AttributeNode attr = field.GetAttribute(SystemTypes.AdditiveAttribute); if (attr == null) return false; ExpressionList exprs = attr.Expressions; if (exprs == null || exprs.Count != 1) return true; Literal lit = exprs[0] as Literal; if (lit != null && (lit.Value is bool)) return (bool)lit.Value; else return false; }
public override Field VisitField(Field field) { if (field == null) return null; if (!this.IncludeModels && HelperMethods.HasAttribute(field.Attributes, ContractNodes.ModelAttributeName)) return null; return base.VisitField(field); }
private static Field GetInstanceField(TypeNode originalReturnType, Field possiblyGenericField, TypeNode instanceDeclaringType) { Contract.Requires(instanceDeclaringType != null); if (instanceDeclaringType.Template == null) return possiblyGenericField; var declaringTemplate = instanceDeclaringType; while (declaringTemplate.Template != null) { declaringTemplate = declaringTemplate.Template; } Contract.Assume(declaringTemplate == possiblyGenericField.DeclaringType); return Rewriter.GetFieldInstanceReference(possiblyGenericField, instanceDeclaringType); #if false Field f = instanceDeclaringType.GetField(possiblyGenericField.Name); if (f != null) { // already instantiated return f; } // pseudo instance Field instance = new Field(instanceDeclaringType, possiblyGenericField.Attributes, possiblyGenericField.Flags, possiblyGenericField.Name, originalReturnType, null); instanceDeclaringType.Members.Add(instance); return instance; #endif }
public override void VisitMemberBinding(MemberBinding memberBinding) { Field f = memberBinding.BoundMember as Field; if (f != null) { this.Found = f; return; } base.VisitMemberBinding(memberBinding); }
private static void AddEnumValue(EnumNode enumType, string name, object value) { var enumValue = new Field(enumType, null, FieldFlags.Assembly | FieldFlags.HasDefault | FieldFlags.Literal | FieldFlags.Static, Identifier.For(name), enumType, new Literal(value, SystemTypes.Int32)); enumType.Members.Add(enumValue); }
internal static void TryAddCompilerGeneratedAttribute(Field field) { Contract.Requires(field != null); TryAddCompilerGeneratedAttribute(field, System.AttributeTargets.Field); }
internal static Field GetFieldInstanceReference(Field fieldOfGenericType, TypeNode instantiatedParentType) { return (Field)GetMemberInstanceReference(fieldOfGenericType, instantiatedParentType); }
/// <summary> /// Write out a field name /// </summary> /// <param name="field">The field for which to write out the name</param> /// <param name="sb">The string builder to which the name is written</param> private static void WriteField(Field field, StringBuilder sb) { WriteType(field.DeclaringType, sb); sb.Append('.'); sb.Append(field.Name.Name); }
public override Expression VisitOldExpression(OldExpression oldExpression) { if (this.topLevelClosureClass != null) { #region In Closure ==> Create a field // Since we're within a closure, we can't create a local to hold the value of the old expression // but instead have to create a field for it. That field can be a member of the top-level // closure class since nothing mentioned in the old expression (except possibly for the // bound variables of enclosing quantifications) should be anything captured from // an inner anonymous delegate. // BUT, first we have to know if the old expression depends on any of the bound // variables of the closures in which it is located. If not, then we can implement // it as a scalar and just generate the assignment "closure_class.field := e" for // "Old(e)" to take a snapshot of e's value in the prestate. If it does depend on // any of the bound variables, then we need to generate a set of for-loops that // compute the indices and values of e for each tuple of indices so it can be retrieved // (given the indices) in the post-state. CollectBoundVariables cbv = new CollectBoundVariables(this.stackOfBoundVariables); cbv.VisitExpression(oldExpression.expression); SubstituteClosureClassWithinOldExpressions subst = new SubstituteClosureClassWithinOldExpressions(this.closureLocals); Expression e = subst.VisitExpression(oldExpression.expression); if (cbv.FoundVariables.Count == 0) { #region Use a scalar for the old variable Local closureLocal; if (!this.closureLocals.TryGetValue(this.topLevelClosureClass, out closureLocal)) { Contract.Assume(false, "can't find closure local!"); } #region Define a scalar var clTemplate = HelperMethods.Unspecialize(this.topLevelClosureClass); Field f = new Field(clTemplate, null, FieldFlags.CompilerControlled | FieldFlags.Public, Identifier.For("_old" + oldExpression.expression.UniqueKey.ToString()), // unique name for this old expr. oldExpression.Type, null); clTemplate.Members.Add(f); // now produce properly instantiated field f = (Field)Rewriter.GetMemberInstanceReference(f, this.topLevelClosureClass); #endregion #region Generate code to store value in prestate this.prestateValuesOfOldExpressions.Statements.Add(new AssignmentStatement(new MemberBinding(closureLocal, f), e)); #endregion #region Return expression to be used in poststate // Return an expression that will evaluate in the poststate to the value of the old // expression in the prestate. This will be this.up.f where "up" is the field C# // generated to point to the instance of the top-level closure class. if (this.PointerToTopLevelClosureClass == null) { // then the old expression occurs in the top-level closure class. Just return "this.f" // where "this" refers to the top-level closure class. return new MemberBinding(new This(this.currentClosureClass), f); } else { return new MemberBinding( new MemberBinding(new This(this.currentClosureClass), this.PointerToTopLevelClosureClass), f); } #endregion #endregion } else { // the Old expression *does* depend upon at least one of the bound variable // in a ForAll or Exists expression #region Use an indexed variable for the old variable TypeNode oldVariableTypeDomain; #region Decide if domain is one-dimensional or not bool oneDimensional = cbv.FoundVariables.Count == 1 && cbv.FoundVariables[0].Type.IsValueType; if (oneDimensional) { // a one-dimensional old-expression can use the index variable directly oldVariableTypeDomain = cbv.FoundVariables[0].Type; } else { oldVariableTypeDomain = SystemTypes.GenericList.GetTemplateInstance(this.module, SystemTypes.Int32); } #endregion TypeNode oldVariableTypeRange = oldExpression.Type; TypeNode oldVariableType = SystemTypes.GenericDictionary.GetTemplateInstance(this.module, oldVariableTypeDomain, oldVariableTypeRange); Local closureLocal; if (!this.closureLocals.TryGetValue(this.topLevelClosureClass, out closureLocal)) { Contract.Assume(false, "can't find closure local"); } #region Define an indexed variable var clTemplate = HelperMethods.Unspecialize(this.topLevelClosureClass); Field f = new Field(clTemplate, null, FieldFlags.CompilerControlled | FieldFlags.Assembly, // can't be private or protected because it needs to be accessed from inner (closure) classes that don't inherit from the class this field is added to. Identifier.For("_old" + oldExpression.expression.UniqueKey.ToString()), // unique name for this old expr. oldVariableType, null); clTemplate.Members.Add(f); // instantiate f f = (Field)Rewriter.GetMemberInstanceReference(f, closureLocal.Type); #endregion #region Generate code to initialize the indexed variable Statement init = new AssignmentStatement( new MemberBinding(closureLocal, f), new Construct(new MemberBinding(null, oldVariableType.GetConstructor()), null)); this.prestateValuesOfOldExpressions.Statements.Add(init); #endregion #region Generate code to store values in prestate #region Create assignment: this.closure.f[i,j,k,...] = e; Method setItem = oldVariableType.GetMethod(Identifier.For("set_Item"), oldVariableTypeDomain, oldVariableTypeRange); Expression index; if (oneDimensional) { index = cbv.FoundVariables[0]; } else { //InstanceInitializer ctor = // ContractNodes.TupleClass.GetConstructor(SystemTypes.Int32.GetArrayType(1)); //Expression index = new Construct(new MemberBinding(null,ctor),new ExpressionList( index = Literal.Null; } MethodCall mc = new MethodCall(new MemberBinding(new MemberBinding(closureLocal, f), setItem), new ExpressionList(index, e)); Statement stat = new ExpressionStatement(mc); #endregion List<Local> locals = new List<Local>(this.stackOfBoundVariables.Count); TrivialHashtable paramMap = new TrivialHashtable(); #region Generate a local for each bound variable to use in for-loop foreach (Variable v in this.stackOfBoundVariables) { Local l = new Local(Identifier.Empty, v.Type); paramMap[v.UniqueKey] = l; locals.Add(l); } #endregion #region Substitute locals for bound variables in old expression *AND* in inner loop bounds SubstituteParameters sps = new SubstituteParameters(paramMap, this.stackOfBoundVariables); sps.Visit(stat); #endregion #region Create nested for-loops around assignment // keep track of when the first variable is used (from innermost to outermost) // as soon as the first one is needed because the old expression depends on it, // then keep all enclosing loops. It would be possible to keep only those where // the necessary loops have loop bounds that depend on an enclosing loop, but I // haven't calculated that, so just keep them all. For instance, if the old expression // depends on j and the loops are "for i,0,n" and inside that "for j,0,i", then need // both loops. If the inner loop bounds were 0 and n, then wouldn't need the outer // loop. bool usedAVariable = false; for (int i = this.stackOfBoundVariables.Count - 1; 0 <= i; i--) { if (!usedAVariable && !cbv.FoundVariables.Contains(this.stackOfBoundVariables[i])) continue; usedAVariable = true; Expression lowerBound = new Duplicator(this.module, this.currentClosureClass).VisitExpression( this.stackOfMethods[i].Operands[0]); lowerBound = subst.VisitExpression(lowerBound); lowerBound = sps.VisitExpression(lowerBound); Expression upperBound = new Duplicator(this.module, this.currentClosureClass).VisitExpression( this.stackOfMethods[i].Operands[1]); upperBound = subst.VisitExpression(upperBound); upperBound = sps.VisitExpression(upperBound); stat = RewriteHelper.GenerateForLoop(locals[i], lowerBound, upperBound, stat); } #endregion this.prestateValuesOfOldExpressions.Statements.Add(stat); #endregion #region Return expression to be used in poststate Method getItem = oldVariableType.GetMethod(Identifier.For("get_Item"), oldVariableTypeDomain); if (oneDimensional) { index = cbv.FoundReferences[0]; } else { //InstanceInitializer ctor = // ContractNodes.TupleClass.GetConstructor(SystemTypes.Int32.GetArrayType(1)); //Expression index = new Construct(new MemberBinding(null,ctor),new ExpressionList( index = Literal.Null; } // Return an expression that will evaluate in the poststate to the value of the old // expression in the prestate. This will be this.up.f[i,j,k,...] where "up" is the field C# // generated to point to the instance of the top-level closure class. MemberBinding thisDotF; if (this.PointerToTopLevelClosureClass == null) { // then the old expression occurs in the top-level closure class. Just return "this.f" // where "this" refers to the top-level closure class. Contract.Assume(f != null); thisDotF = new MemberBinding(new This(clTemplate), HelperMethods.Unspecialize(f)); } else { thisDotF = new MemberBinding( new MemberBinding(new This(clTemplate), this.PointerToTopLevelClosureClass), f); } return new MethodCall(new MemberBinding(thisDotF, getItem), new ExpressionList(index)); #endregion #endregion } #endregion } else { #region Not in closure ==> Create a local variable Local l = GetLocalForOldExpression(oldExpression); #region Make sure local can be seen in the debugger (for the entire method, unfortunately) if (currentMethod.LocalList == null) { currentMethod.LocalList = new LocalList(); } currentMethod.LocalList.Add(l); currentMethod.Body.HasLocals = true; #endregion this.prestateValuesOfOldExpressions.Statements.Add( new AssignmentStatement(l, oldExpression.expression)); // Return an expression that will evaluate in the poststate to the value of the old // expression in the prestate. When we're not in a closure, this is just the local // itself. return l; #endregion } }
public override Field VisitField(Field field) { if (field == null) return null; WriteStart(GetFieldQualifiers(field)); this.VisitTypeReference(field.Type); Write(" {0}", field.Name.Name); if (field.Initializer != null) { Write(" = "); field.Initializer = this.VisitExpression(field.Initializer); } WriteFinish(";"); return field; }
/// <summary> /// If there is an anonymous delegate within a postcondition, then there /// will be a call to a delegate constructor. /// That call looks like "d..ctor(o,m)" where d is the type of the delegate. /// There are two cases depending on whether the anonymous delegate captured /// anything. In both cases, m is the method implementing the anonymous delegate. /// /// (1) It does capture something. Then o is the instance of the closure class /// implementing the delegate, and m is an instance method in the closure /// class. /// (2) It does *not* capture anything. Then o is the literal for null and /// m is a static method that was added directly to the class. /// /// This method will cause m to be visited to collect any old expressions /// that occur in it. But those old expressions are not turned into locals, /// but fields. The fields are created as either (1) members of the closure class, /// or (2) members of the class in which the method containing the contract /// containing the Old expression is defined. /// The fields are initialized when (1) the closure class instance is created, /// or (2) ... ??? (when!?) /// So set up enough state so that when those old expressions are visited, the /// correct ASTs can be built. /// </summary> /// <param name="cons">The AST representing the call to the constructor /// of the delegate type.</param> /// <returns>Whatever the base visitor returns</returns> public override Expression VisitConstruct(Construct cons) { if (cons.Type is DelegateNode) { UnaryExpression ue = cons.Operands[1] as UnaryExpression; if (ue == null) goto JustVisit; MemberBinding mb = ue.Operand as MemberBinding; if (mb == null) goto JustVisit; Method m = mb.BoundMember as Method; Contract.Assume(m != null); if (m.IsStatic) { // then there is no closure class, m is just a static method the compiler // added to the class itself goto JustVisit; } if (HelperMethods.IsCompilerGenerated(m)) { Local l = cons.Operands[0] as Local; if (l == null) goto JustVisit; // but then what is it?? TypeNode savedClosureClass = this.currentClosureClass; this.currentClosureClass = l.Type; if (savedClosureClass == null) { // then this is the top-level closure class // have to treat it special: it doesn't contain a field that points // to the top-level closure class. The field introduced to hold the value of the // old expression will be declared in this class. this.topLevelClosureClass = this.currentClosureClass; } else { // Find the field in this.closureClass that the C# compiler generated // to point to the top-level closure foreach (Member mem in this.currentClosureClass.Members) { Field f = mem as Field; if (f == null) continue; if (f.Type == this.topLevelClosureClass) { this.PointerToTopLevelClosureClass = f; break; } } } this.VisitBlock(m.Body); if (savedClosureClass == null) { this.topLevelClosureClass = null; } this.currentClosureClass = savedClosureClass; this.PointerToTopLevelClosureClass = null; } } JustVisit: return base.VisitConstruct(cons); }
private void CheckField(Field field) { Contract.Requires(field != null); string s = HelperMethods.GetStringFromAttribute(field, ContractNodes.SpecPublicAttributeName); if (s != null) { // okay if it is null, then it just doesn't have a named substitute to use in documentation, etc. // make sure it is the name of a (public) field or (public) property, but it might be inherited // Search class hierarchy for a field or a property TypeNode t = field.DeclaringType; bool error = true; while (t != null && error) { Contract.Assert(t != null); MemberList mems = t.GetMembersNamed(Identifier.For(s)); for (int i = 0, n = /*mems == null ? 0 : */ mems.Count; /*error && */i < n; i++) { Member mem = mems[i]; Field f = mem as Field; if (f != null) { if (!f.IsPublic) continue; //if (f.Type != field.Type) continue; // REVIEW: When it becomes possible, allow widening error = false; break; } Property p = mem as Property; if (p != null) { Method getter = p.Getter; if (getter == null) continue; // found by Clousot. if (!getter.IsPublic) continue; //if (getter.ReturnType != field.Type) continue; // REVIEW: When it becomes possible, allow widening error = false; break; } } t = t.BaseType; } if (error) { this.HandleError( new Error(1010, "Field '" + field.FullName + "' is marked [ContractPublicPropertyName(\"" + s + "\")], but no public field/property named '" + s + "' with type '" + field.Type + "' can be found", field.SourceContext)); } } }
public virtual Field VisitField(Field field) { if (field == null) return null; field.Attributes = this.VisitAttributeList(field.Attributes); field.Type = this.VisitTypeReference(field.Type); field.Initializer = this.VisitExpression(field.Initializer); field.ImplementedInterfaces = this.VisitInterfaceReferenceList(field.ImplementedInterfaces); return field; }