public static LNode ContractsOnLambda(LNode fn, IMacroContext context) { LNode oldFn = fn; if (fn.ArgCount == 2) { var rw = new CodeContractRewriter(LNode.Missing, Id_lambda_function, context); fn = ProcessArgContractAttributes(fn, 0, rw, isLambda: true); if (fn.HasAttrs) { fn = fn.WithAttrs(rw.Process(fn.Attrs, null)); } if (rw.PrependStmts.IsEmpty) { return(null); } else { var body = fn.Args[1]; if (!body.Calls(S.Braces)) { body = LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(body)))).SetStyle(NodeStyle.Statement); } body = body.WithArgs(body.Args.InsertRange(0, rw.PrependStmts)); fn = fn.WithArgChanged(1, body); return(fn); } } return(null); }
static LNode ProcessArgContractAttributes(LNode fn, int argsIndex, CodeContractRewriter rw, bool isLambda = false) { LNode fnArgs = fn.Args[argsIndex]; if (fnArgs.CallsMin(isLambda ? S.Tuple : S.AltList, 1)) { return(fn.WithArgChanged(argsIndex, fnArgs.WithArgs(arg => { if (arg.HasAttrs) { return arg.WithAttrs(rw.Process(arg.Attrs, GetVarName(arg))); } return arg; }))); } else if (isLambda) { var arg = fnArgs; // just one argument if (arg.HasAttrs) { fn = fn.WithArgChanged(argsIndex, arg.WithAttrs(rw.Process(arg.Attrs, GetVarName(arg)))); } } return(fn); }
public static LNode ContractsOnMethod(LNode fn, IMacroContext context) { LNode oldFn = fn; if (fn.ArgCount >= 4) { var rw = new CodeContractRewriter(fn.Args[0], fn.Args[1], context); fn = ProcessArgContractAttributes(fn, 2, rw); if (fn.Args[0].HasAttrs) { fn = fn.WithArgChanged(0, fn.Args[0].WithAttrs(rw.Process(fn.Args[0].Attrs, null))); } if (fn.HasAttrs) { fn = fn.WithAttrs(rw.Process(fn.Attrs, null)); } if (rw.PrependStmts.IsEmpty) { return(null); } else { var body = fn.Args[3]; if (!body.Calls(S.Braces)) { body = LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(body)))).SetStyle(NodeStyle.Statement); } body = body.WithArgs(body.Args.InsertRange(0, rw.PrependStmts)); fn = fn.WithArgChanged(3, body); return(fn); } } return(null); }
[LexicalMacro("([notnull] (x => ...)); ([notnull] x) => ...; ([requires(expr)] x) => ...; " + "([ensures(expr)] (x => ...)); ([ensuresOnThrow(expr)] (x => ...)); ", "Generates Contract checks in a lambda function. See the documentation of " + "ContractsOnMethod for more information about the contract attributes.", "=>", Mode = MacroMode.Passive | MacroMode.PriorityInternalFallback)] public static LNode ContractsOnLambda(LNode fn, IMacroContext context) { LNode oldFn = fn; if (fn.ArgCount == 2) { var rw = new CodeContractRewriter(LNode.Missing, Id_lambda_function, context); fn = ProcessArgContractAttributes(fn, 0, rw, isLambda: true); if (fn.HasAttrs) { fn = fn.WithAttrs(rw.Process(fn.Attrs, null)); } if (rw.PrependStmts.IsEmpty) { return(null); } else { var body = fn.Args[1]; if (!body.Calls(S.Braces)) { body = LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(body)))).SetStyle(NodeStyle.Statement); } body = body.WithArgs(body.Args.InsertRange(0, rw.PrependStmts)); fn = fn.WithArgChanged(1, body); return(fn); } } return(null); }
[LexicalMacro("notnull T method(notnull T arg) {...}; T method([requires(expr)] T arg) {...}; " + "[requires(expr)] T method(...) {...}; [ensures(expr)] T method(...) {...}; " + "[ensuresOnThrow(expr)] T method(...) {...}; [ensuresOnThrow<Exception>(expr)] T method(...) {...}", "Generates Contract checks in a method.\n\n" + "- [requires(expr)] and [assert(expr)] specify an expression that must be true at the beginning of the method; assert conditions are checked in debug builds only, while \"requires\" conditions are checked in all builds. The condition can include an underscore `_` that refers to the argument that the attribute is attached to, if any.\n" + "- [ensures(expr)] and [ensuresAssert(expr)] specify an expression that must be true if-and-when the method returns normally. assert conditions are checked in debug builds only. The condition can include an underscore `_` that refers to the return value of the method.\n" + "- [ensuresFinally(expr)] specifies an expression that must be true when the method exits, whether by exception or by a normal return. This is implemented by wrapping the method in a try-finally block.\n" + "- [ensuresOnThrow(expr)] and [ensuresOnThrow<ExceptionType>(expr)] specify a condition that must be true if the method throws an exception. When #haveContractRewriter is false, underscore `_` refers to the thrown exception object; this is not available in the MS Code Contracts Rewriter.\n" + "- notnull is equivalent to [requires(_ != null)] if applied to an argument, and [ensures(_ != null)] if applied to the method as a whole.\n" + "\nAll contract attributes (except notnull) can specify multiple expressions separated by commas, to produce multiple checks, each with its own error message.", "#fn", "#cons", Mode = MacroMode.Passive | MacroMode.PriorityInternalFallback)] public static LNode ContractsOnMethod(LNode fn, IMacroContext context) { LNode fnArgs, oldFn = fn; if (fn.ArgCount >= 4) { var rw = new CodeContractRewriter(fn.Args[0], fn.Args[1], context); fn = ProcessArgContractAttributes(fn, 2, rw); if (fn.Args[0].HasAttrs) { fn = fn.WithArgChanged(0, fn.Args[0].WithAttrs(rw.Process(fn.Args[0].Attrs, null))); } if (fn.HasAttrs) { fn = fn.WithAttrs(rw.Process(fn.Attrs, null)); } if (rw.PrependStmts.IsEmpty) { return(null); } else { var body = fn.Args[3]; if (!body.Calls(S.Braces)) { body = LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(body)))).SetStyle(NodeStyle.Statement); } body = body.WithArgs(body.Args.InsertRange(0, rw.PrependStmts)); fn = fn.WithArgChanged(3, body); return(fn); } } return(null); }
public static LNode ContractsOnMethod(LNode fn, IMacroContext context) { // Performance note: one should keep in mind that this macro usually // has no effect. It looks for contracts and usually finds none, so // we should try to search quickly. Luckily, LNode methods like // n.WithArgChanged(i,N) do not allocate a new node if the new value // equals the old value (if n[i] == N). LNode oldFn = fn; if (fn.ArgCount >= 4) { var rw = new CodeContractRewriter(fn.Args[0], fn.Args[1], context); // If this thing has an argument list, scan it fn = ProcessArgContractAttributes(fn, 2, rw); // Scan attributes on return type, then attributes on the whole method if (fn.Args[0].HasAttrs) { fn = fn.WithArgChanged(0, fn.Args[0].WithAttrs(rw.Process(fn.Args[0].Attrs, null))); } if (fn.HasAttrs) { fn = fn.WithAttrs(rw.Process(fn.Attrs, null)); } if (rw.PrependStmts.IsEmpty) { return(null); // this is the common case } else { var body = fn.Args[3]; if (!body.Calls(S.Braces) // Add braces in case of void LambdaMethod() => expr; ) { body = LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(body)))).SetStyle(NodeStyle.Statement); } body = body.WithArgs(body.Args.InsertRange(0, rw.PrependStmts)); fn = fn.WithArgChanged(3, body); return(fn); } } return(null); }
public static LNode ContractsOnLambda(LNode fn, IMacroContext context) { // Performance note: one should keep in mind that this macro usually // has no effect. It looks for contracts and usually finds none. LNode oldFn = fn; if (fn.ArgCount == 2) { var rw = new CodeContractRewriter(LNode.Missing, Id_lambda_function, context); // If this thing has an argument list, scan it fn = ProcessArgContractAttributes(fn, 0, rw, isLambda: true); // Scan attributes on the lambda as a whole if (fn.HasAttrs) { fn = fn.WithAttrs(rw.Process(fn.Attrs, null)); } if (rw.PrependStmts.IsEmpty) { return(null); // this is the common case } else { var body = fn.Args[1]; if (!body.Calls(S.Braces) // Add braces in case of void LambdaMethod() => expr; ) { body = LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(body)))).SetStyle(NodeStyle.Statement); } body = body.WithArgs(body.Args.InsertRange(0, rw.PrependStmts)); fn = fn.WithArgChanged(1, body); return(fn); } } return(null); }
public static LNode ContractsOnProperty(LNode prop, IMacroContext context) { // Performance note: one should keep in mind that this macro usually // has no effect. It looks for contracts and usually finds none. LNode oldProp = prop; if (prop.ArgCount == 4) { LNode braces = prop[3]; var oldBraces = braces; var rw = new CodeContractRewriter(prop.Args[0], prop.Args[1], context); // If this has an argument list (this[...]), process its contract attributes prop = ProcessArgContractAttributes(prop, 2, rw); // Remove contract attributes from the property and store in a list VList <LNode> cAttrs = LNode.List(); prop = prop.WithArgChanged(0, GrabContractAttrs(prop.Args[0], ref cAttrs, ContractAppliesTo.Getter)); prop = GrabContractAttrs(prop, ref cAttrs); // Find the getter and setter LNode getter = null, setter = null; int getterIndex = -1, setterIndex = -1; VList <LNode> getterAttrs = LNode.List(), setterAttrs = LNode.List(); bool isLambdaProperty = !braces.Calls(S.Braces); if (isLambdaProperty) { if (cAttrs.Count == 0) { return(null); // lambda property has no contract attributes } // Transform into a normal property getterAttrs = cAttrs; getter = LNode.Call(CodeSymbols.get, LNode.List(LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(braces)))).SetStyle(NodeStyle.Statement))).SetStyle(NodeStyle.Special); braces = LNode.Call(CodeSymbols.Braces, LNode.List(getter)).SetStyle(NodeStyle.Statement); getterIndex = 0; } else { for (int i = 0; i < braces.Args.Count; i++) { var part = braces.Args[i]; if (part.Calls(S.get)) { getter = part; getterIndex = i; } if (part.Calls(S.set)) { setter = part; setterIndex = i; } } // Now create separate lists of contract attributes for the getter and the setter if (cAttrs.Count != 0) { getterAttrs = cAttrs.SmartWhere(a => (PropertyContractInterpretation(a) & ContractAppliesTo.Getter) != 0); setterAttrs = cAttrs.SmartWhere(a => (PropertyContractInterpretation(a) & ContractAppliesTo.Setter) != 0); } } // Process the discovered attributes to produce prepended statements var sharedPrependStmts = rw.PrependStmts; if (getter != null) { getter = GrabContractAttrs(getter, ref getterAttrs); rw.Process(getterAttrs, null); rw.PrependStmtsToGetterOrSetter(ref braces, getterIndex, getter); } if (setter != null) { rw.PrependStmts = sharedPrependStmts; setter = GrabContractAttrs(setter, ref setterAttrs); rw.Process(setterAttrs, LNode.Id(CodeSymbols.value), true); rw.PrependStmtsToGetterOrSetter(ref braces, setterIndex, setter); } // Update the property if (braces == oldBraces) { return(null); // this is the common case } else { return(prop.WithArgChanged(3, braces)); } } return(null); }
public static LNode ContractsOnProperty(LNode prop, IMacroContext context) { LNode oldProp = prop; if (prop.ArgCount == 4) { LNode braces = prop[3]; var oldBraces = braces; var rw = new CodeContractRewriter(prop.Args[0], prop.Args[1], context); prop = ProcessArgContractAttributes(prop, 2, rw); VList <LNode> cAttrs = LNode.List(); prop = prop.WithArgChanged(0, GrabContractAttrs(prop.Args[0], ref cAttrs, ContractAppliesTo.Getter)); prop = GrabContractAttrs(prop, ref cAttrs); LNode getter = null, setter = null; int getterIndex = -1, setterIndex = -1; VList <LNode> getterAttrs = LNode.List(), setterAttrs = LNode.List(); bool isLambdaProperty = !braces.Calls(S.Braces); if (isLambdaProperty) { if (cAttrs.Count == 0) { return(null); } getterAttrs = cAttrs; getter = LNode.Call(CodeSymbols.get, LNode.List(LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(braces)))).SetStyle(NodeStyle.Statement))).SetStyle(NodeStyle.Special); braces = LNode.Call(CodeSymbols.Braces, LNode.List(getter)).SetStyle(NodeStyle.Statement); getterIndex = 0; } else { for (int i = 0; i < braces.Args.Count; i++) { var part = braces.Args[i]; if (part.Calls(S.get)) { getter = part; getterIndex = i; } if (part.Calls(S.set)) { setter = part; setterIndex = i; } } if (cAttrs.Count != 0) { getterAttrs = cAttrs.SmartWhere(a => (PropertyContractInterpretation(a) & ContractAppliesTo.Getter) != 0); setterAttrs = cAttrs.SmartWhere(a => (PropertyContractInterpretation(a) & ContractAppliesTo.Setter) != 0); } } var sharedPrependStmts = rw.PrependStmts; if (getter != null) { getter = GrabContractAttrs(getter, ref getterAttrs); rw.Process(getterAttrs, null); rw.PrependStmtsToGetterOrSetter(ref braces, getterIndex, getter); } if (setter != null) { rw.PrependStmts = sharedPrependStmts; setter = GrabContractAttrs(setter, ref setterAttrs); rw.Process(setterAttrs, LNode.Id(CodeSymbols.value), true); rw.PrependStmtsToGetterOrSetter(ref braces, setterIndex, setter); } if (braces == oldBraces) { return(null); } else { return(prop.WithArgChanged(3, braces)); } } return(null); }
[LexicalMacro("notnull T Prop {...}; T this[[requires(expr)] T arg] {...}; " + "T Prop { [requires(expr)] set; }; [ensures(expr)] T Prop {...}; " + "[ensuresOnThrow(expr)] T Prop {...}; [ensuresOnThrow<Exception>(expr)] T Prop {...}", "Generates contract checks in a property. You can apply contract attributes to " + "the property itself, to the getter, to the setter, or all three. When the [requires] " + "or [assert] attributes are applied to the property itself, they are treated as if " + "they were applied to the getter; but when the [ensures], [ensuresAssert], notnull, " + "and [ensuresOnThrow] attributes are applied to the property itself, they are treated " + "as if they were applied to both the getter and the setter separately.", "#property", Mode = MacroMode.Passive | MacroMode.PriorityInternalFallback)] public static LNode ContractsOnProperty(LNode prop, IMacroContext context) { LNode propArgs, oldProp = prop; if (prop.ArgCount == 4) { LNode braces = prop[3]; var oldBraces = braces; var rw = new CodeContractRewriter(prop.Args[0], prop.Args[1], context); prop = ProcessArgContractAttributes(prop, 2, rw); VList <LNode> cAttrs = LNode.List(); prop = prop.WithArgChanged(0, GrabContractAttrs(prop.Args[0], ref cAttrs, ContractAppliesTo.Getter)); prop = GrabContractAttrs(prop, ref cAttrs); LNode getter = null, setter = null; int getterIndex = -1, setterIndex = -1; VList <LNode> getterAttrs = LNode.List(), setterAttrs = LNode.List(); bool isLambdaProperty = !braces.Calls(S.Braces); if (isLambdaProperty) { if (cAttrs.Count == 0) { return(null); } getterAttrs = cAttrs; getter = LNode.Call(CodeSymbols.get, LNode.List(LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(braces)))).SetStyle(NodeStyle.Statement))).SetStyle(NodeStyle.Special); braces = LNode.Call(CodeSymbols.Braces, LNode.List(getter)).SetStyle(NodeStyle.Statement); getterIndex = 0; } else { for (int i = 0; i < braces.Args.Count; i++) { var part = braces.Args[i]; if (part.Calls(S.get)) { getter = part; getterIndex = i; } if (part.Calls(S.set)) { setter = part; setterIndex = i; } } if (cAttrs.Count != 0) { getterAttrs = cAttrs.Where(a => (PropertyContractInterpretation(a) & ContractAppliesTo.Getter) != 0); setterAttrs = cAttrs.Where(a => (PropertyContractInterpretation(a) & ContractAppliesTo.Setter) != 0); } } var sharedPrependStmts = rw.PrependStmts; if (getter != null) { getter = GrabContractAttrs(getter, ref getterAttrs); rw.Process(getterAttrs, null); rw.PrependStmtsToGetterOrSetter(ref braces, getterIndex, getter); } if (setter != null) { rw.PrependStmts = sharedPrependStmts; setter = GrabContractAttrs(setter, ref setterAttrs); rw.Process(setterAttrs, LNode.Id(CodeSymbols.value), true); rw.PrependStmtsToGetterOrSetter(ref braces, setterIndex, setter); } if (braces == oldBraces) { return(null); } else { return(prop.WithArgChanged(3, braces)); } } return(null); }