Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

View File

@@ -0,0 +1,96 @@
//
// AssemblyRef.cs
//
// Authors:
// Chris Bacon (chrisbacon76@gmail.com)
//
// Copyright (C) 2010 Chris Bacon
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace Mono.CodeContracts.Rewrite {
public struct AssemblyRef {
public struct TwoStreams {
public TwoStreams (Stream assembly, Stream symbols)
: this ()
{
this.Assembly = assembly;
this.Symbols = symbols;
}
public Stream Assembly { get; private set; }
public Stream Symbols { get; private set; }
}
public AssemblyRef (string filename)
: this ()
{
this.Filename = filename;
}
public AssemblyRef (TwoStreams streams)
: this ()
{
this.Streams = streams;
}
public string Filename { get; private set; }
public TwoStreams Streams { get; private set; }
public bool IsFilename {
get {
return this.Filename != null;
}
}
public bool IsStream {
get {
return this.Streams.Assembly != null;
}
}
public bool IsSet {
get {
return this.Filename != null || this.Streams.Assembly != null;
}
}
public static implicit operator AssemblyRef (string filename)
{
return new AssemblyRef (filename);
}
public static implicit operator AssemblyRef (Stream stream)
{
return new AssemblyRef (new TwoStreams (stream, null));
}
}
}

View File

@@ -0,0 +1,152 @@
//
// ConditionTextExtractor.cs
//
// Authors:
// Chris Bacon (chrisbacon76@gmail.com)
//
// Copyright (C) 2010 Chris Bacon
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mono.CodeContracts.Rewrite.AstVisitors;
using System.IO;
namespace Mono.CodeContracts.Rewrite {
class ConditionTextExtractor {
public ConditionTextExtractor (string filename, SourcePositionVisitor.CodePosition start, SourcePositionVisitor.CodePosition end)
{
this.filename = filename;
this.start = start;
this.end = end;
}
private string filename;
private SourcePositionVisitor.CodePosition start, end;
enum State {
FunctionName,
Parameters,
};
private State state;
public string GetConditionText ()
{
if (this.filename == null || this.start.IsEmpty || this.end.IsEmpty){
return "<unknown source code position>";
}
string[] lines;
try {
lines = File.ReadAllLines (this.filename);
} catch {
return "<cannot access source code>";
}
try {
StringBuilder sb = new StringBuilder ();
for (int i = this.start.Line; i <= this.end.Line; i++) {
string line = lines [i - 1];
if (i == this.end.Line && this.end.Column != 0) {
line = line.Substring (0, this.end.Column - 1);
}
if (i == this.start.Line && this.start.Column != 0) {
line = line.Substring (this.start.Column - 1);
}
sb.Append (line.Trim());
}
string cndStr = sb.ToString ();
this.state = State.FunctionName;
var cnd = this.RunStateMachine (cndStr);
return cnd.ToString ().Trim ();
} catch {
return "<source-code parse error>";
}
}
private StringBuilder RunStateMachine (string line)
{
StringBuilder cnd = new StringBuilder ();
int inBrackets = 0;
bool inDoubleQuotes = false;
bool inSingleQuotes = false;
bool inEscape = false;
foreach (char c in line) {
switch (this.state) {
case State.FunctionName:
if (c == '(') {
this.state = State.Parameters;
}
break;
case State.Parameters:
switch (c) {
case ',':
if (inBrackets == 0 && !inDoubleQuotes && !inSingleQuotes) {
return cnd;
}
break;
case '(':
if (!inDoubleQuotes && !inSingleQuotes) {
inBrackets++;
}
break;
case ')':
if (!inDoubleQuotes && !inSingleQuotes) {
if (inBrackets == 0) {
return cnd;
}
inBrackets--;
}
break;
case '"':
if (!inEscape) {
inDoubleQuotes = !inDoubleQuotes;
}
break;
case '\'':
if (!inEscape) {
inSingleQuotes = !inSingleQuotes;
}
break;
case '\\':
inEscape = true;
goto forceEscape;
}
inEscape = false;
forceEscape:
cnd.Append (c);
break;
default:
throw new NotSupportedException ("Cannot handle state: " + this.state);
}
}
return new StringBuilder ("<bad source code>");
}
}
}

View File

@@ -0,0 +1,48 @@
//
// ContractRequiresInfo.cs
//
// Authors:
// Chris Bacon (chrisbacon76@gmail.com)
//
// Copyright (C) 2010 Chris Bacon
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mono.CodeContracts.Rewrite.Ast;
namespace Mono.CodeContracts.Rewrite {
class ContractRequiresInfo {
public ContractRequiresInfo (Expr originalExpr, Expr rewrittenExpr)
{
this.OriginalExpr = originalExpr;
this.RewrittenExpr = rewrittenExpr;
}
public Expr OriginalExpr { get; private set; }
public Expr RewrittenExpr { get; private set; }
}
}

View File

@@ -0,0 +1,294 @@
//
// ContractRuntime.cs
//
// Authors:
// Chris Bacon (chrisbacon76@gmail.com)
//
// Copyright (C) 2010 Chris Bacon
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mono.Cecil;
using System.Diagnostics.Contracts;
using Mono.Cecil.Cil;
using System.Diagnostics;
using System.Runtime.ConstrainedExecution;
using System.Runtime.CompilerServices;
namespace Mono.CodeContracts.Rewrite {
class ContractsRuntime {
private const string Namespace = "System.Diagnostics.Contracts";
public ContractsRuntime (ModuleDefinition module, RewriterOptions options)
{
this.module = module;
this.options = options;
}
private ModuleDefinition module;
private RewriterOptions options;
private TypeDefinition typeContractsRuntime = null;
private TypeDefinition typeContractException = null;
private MethodDefinition methodContractExceptionCons = null;
private MethodDefinition methodTriggerFailure = null;
private MethodDefinition methodReportFailure = null;
private MethodDefinition methodRequires = null;
private void EnsureTypeContractRuntime ()
{
if (this.typeContractsRuntime == null) {
// namespace System.Diagnostics.Contracts {
// [CompilerGenerated]
// private static class __ContractsRuntime {
// }
// }
// Create type
TypeReference typeObject = this.module.Import (typeof (object));
TypeDefinition type = new TypeDefinition ("__ContractsRuntime", Namespace,
TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.NotPublic | TypeAttributes.AnsiClass | TypeAttributes.AutoClass, // | TypeAttributes.BeforeFieldInit,
typeObject);
this.module.Types.Add (type);
// Attach custom attributes
var attrCompilerGeneratedCons = typeof (CompilerGeneratedAttribute).GetConstructor (Type.EmptyTypes);
CustomAttribute attrCompilerGenerated = new CustomAttribute (this.module.Import (attrCompilerGeneratedCons));
type.CustomAttributes.Add (attrCompilerGenerated);
// Store type
this.typeContractsRuntime = type;
}
}
private void EnsureTypeContractException ()
{
if (this.options.ThrowOnFailure && this.typeContractException == null) {
// [CompilerGenerated]
// private class ContractException : Exception {
// internal ContractException(ContractFailureKind kind, string usermsg, string condition, Exception inner)
// : base(failure, inner)
// {
// }
// }
// Prepare type references
TypeReference typeVoid = this.module.Import (typeof (void));
TypeReference typeContractFailureKind = this.module.Import (typeof (ContractFailureKind));
TypeReference typeString = this.module.Import (typeof (string));
TypeReference typeException = this.module.Import (typeof (Exception));
// Create type
TypeDefinition type = new TypeDefinition ("ContractException", Namespace,
TypeAttributes.NestedPrivate | TypeAttributes.AnsiClass | TypeAttributes.AutoClass, typeException);
//this.typeContractsRuntime.NestedTypes.Add (type);
this.module.Types.Add(type);
// Create constructor
MethodDefinition cons = new MethodDefinition (".ctor",
MethodAttributes.Assembly | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, typeVoid);
cons.Parameters.Add (new ParameterDefinition ("kind", ParameterAttributes.None, typeContractFailureKind));
cons.Parameters.Add (new ParameterDefinition ("failure", ParameterAttributes.None, typeString));
cons.Parameters.Add (new ParameterDefinition ("usermsg", ParameterAttributes.None, typeString));
cons.Parameters.Add (new ParameterDefinition ("condition", ParameterAttributes.None, typeString));
cons.Parameters.Add (new ParameterDefinition ("inner", ParameterAttributes.None, typeException));
var il = cons.Body.GetILProcessor ();
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldarg_2);
il.Emit (OpCodes.Ldarg_S, cons.Parameters [4]);
MethodReference mExceptionCons = this.module.Import (typeof (Exception).GetConstructor (new [] { typeof (string), typeof (Exception) }));
il.Emit (OpCodes.Call, mExceptionCons);
il.Emit (OpCodes.Ret);
type.Methods.Add (cons);
// Attach custom attributes
var attrCompilerGeneratedCons = typeof (CompilerGeneratedAttribute).GetConstructor (Type.EmptyTypes);
CustomAttribute attrCompilerGenerated = new CustomAttribute (this.module.Import (attrCompilerGeneratedCons));
type.CustomAttributes.Add (attrCompilerGenerated);
// Store constructor and type
this.methodContractExceptionCons = cons;
this.typeContractException = type;
}
}
private void EnsureMethodTriggerFailure ()
{
if (this.methodTriggerFailure == null) {
// if the ThrowOnFailure option is true, then:
// internal static void TriggerFailure(ContractFailureKind kind, string message, string userMessage, string conditionText, Exception inner)
// {
// throw new ContractException(kind, message, userMessage, conditionText, inner);
// }
// if the ThrowOnFailure option is false, then:
// internal static void TriggerFailure(ContractFailureKind kind, string message, string userMessage, string conditionText, Exception inner)
// {
// Debug.Fail(message, userMessage);
// }
// Prepare type references
TypeReference typeVoid = this.module.Import (typeof (void));
TypeReference typeContractFailureKind = this.module.Import (typeof (ContractFailureKind));
TypeReference typeString = this.module.Import (typeof (string));
TypeReference typeException = this.module.Import (typeof (Exception));
// Create method
MethodDefinition method = new MethodDefinition ("TriggerFailure",
MethodAttributes.Assembly | MethodAttributes.Static, typeVoid);
method.Parameters.Add (new ParameterDefinition ("kind", ParameterAttributes.None, typeContractFailureKind));
method.Parameters.Add (new ParameterDefinition ("message", ParameterAttributes.None, typeString));
method.Parameters.Add (new ParameterDefinition ("userMessage", ParameterAttributes.None, typeString));
method.Parameters.Add (new ParameterDefinition ("conditionText", ParameterAttributes.None, typeString));
method.Parameters.Add (new ParameterDefinition ("inner", ParameterAttributes.None, typeException));
var il = method.Body.GetILProcessor ();
if (this.options.ThrowOnFailure) {
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldarg_1);
il.Emit (OpCodes.Ldarg_2);
il.Emit (OpCodes.Ldarg_3);
il.Emit (OpCodes.Ldarg_S, method.Parameters [4]);
il.Emit (OpCodes.Newobj, this.methodContractExceptionCons);
il.Emit (OpCodes.Throw);
} else {
var mDebugFail = typeof (Debug).GetMethod ("Fail", new [] { typeof (string), typeof(string) });
MethodReference methodDebugFail = this.module.Import (mDebugFail);
il.Emit (OpCodes.Ldarg_1);
il.Emit (OpCodes.Ldarg_2);
il.Emit (OpCodes.Call, methodDebugFail);
il.Emit (OpCodes.Ret);
}
this.typeContractsRuntime.Methods.Add (method);
this.methodTriggerFailure = method;
}
}
private void EnsureMethodReportFailure ()
{
if (this.methodReportFailure == null) {
// internal static void ReportFailure(ContractFailureKind kind, string message, string conditionText, Exception inner)
// {
// string s = ContractHelper.RaiseContractFailedEvent(kind, message, conditionText, inner);
// if (s != null) {
// TriggerFailure(kind, s, message, conditionText, inner);
// }
// }
// Prepare type references
TypeReference typeVoid = this.module.Import (typeof (void));
TypeReference typeContractFailureKind = this.module.Import (typeof (ContractFailureKind));
TypeReference typeString = this.module.Import (typeof (string));
TypeReference typeException = this.module.Import (typeof (Exception));
#if NET_4_5
var helper = typeof (ContractHelper);
#else
var helper = typeof (System.Diagnostics.Contracts.Internal.ContractHelper);
#endif
MethodReference mRaiseContractFailedEvent = this.module.Import (helper.GetMethod ("RaiseContractFailedEvent"));
// Create method
MethodDefinition method = new MethodDefinition ("ReportFailure",
MethodAttributes.Assembly | MethodAttributes.Static, typeVoid);
method.Parameters.Add (new ParameterDefinition ("kind", ParameterAttributes.None, typeContractFailureKind));
method.Parameters.Add (new ParameterDefinition ("message", ParameterAttributes.None, typeString));
method.Parameters.Add (new ParameterDefinition ("conditionText", ParameterAttributes.None, typeString));
method.Parameters.Add (new ParameterDefinition ("inner", ParameterAttributes.None, typeException));
VariableDefinition vMsg = new VariableDefinition ("sMsg", typeString);
method.Body.Variables.Add (vMsg);
method.Body.InitLocals = true;
var il = method.Body.GetILProcessor ();
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldarg_1);
il.Emit (OpCodes.Ldarg_2);
il.Emit (OpCodes.Ldarg_3);
il.Emit (OpCodes.Call, mRaiseContractFailedEvent);
il.Emit (OpCodes.Stloc_0);
il.Emit (OpCodes.Ldloc_0);
var instRet = il.Create (OpCodes.Ret);
il.Emit (OpCodes.Brfalse_S, instRet);
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldloc_0);
il.Emit (OpCodes.Ldarg_1);
il.Emit (OpCodes.Ldarg_2);
il.Emit (OpCodes.Ldarg_3);
il.Emit (OpCodes.Call, this.methodTriggerFailure);
il.Append (instRet);
this.typeContractsRuntime.Methods.Add (method);
this.methodReportFailure = method;
}
}
private void EnsureGlobal ()
{
this.EnsureTypeContractRuntime ();
this.EnsureTypeContractException ();
this.EnsureMethodTriggerFailure ();
this.EnsureMethodReportFailure ();
}
public MethodDefinition GetRequires ()
{
this.EnsureGlobal ();
if (this.methodRequires == null) {
// [DebuggerNonUserCode]
// [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
// internal static void Requires(bool condition, string message, string conditionText)
// {
// if (!condition) {
// ReportFailure(ContractFailureKind.Precondition, message, conditionText, null);
// }
// }
// Prepare type references
TypeReference typeVoid = this.module.Import (typeof (void));
TypeReference typeBoolean = this.module.Import (typeof (bool));
TypeReference typeString = this.module.Import (typeof (string));
// Create method
MethodDefinition method = new MethodDefinition ("Requires",
MethodAttributes.Assembly | MethodAttributes.Static, typeVoid);
method.Parameters.Add (new ParameterDefinition ("condition", ParameterAttributes.None, typeBoolean));
method.Parameters.Add (new ParameterDefinition ("message", ParameterAttributes.None, typeString));
method.Parameters.Add (new ParameterDefinition ("conditionText", ParameterAttributes.None, typeString));
var il = method.Body.GetILProcessor ();
il.Emit (OpCodes.Ldarg_0);
var instRet = il.Create(OpCodes.Ret);
il.Emit (OpCodes.Brtrue_S, instRet);
il.Emit (OpCodes.Ldc_I4_0); // Assumes ContractFailureKind.Precondition == 0
il.Emit (OpCodes.Ldarg_1);
il.Emit (OpCodes.Ldarg_2);
il.Emit (OpCodes.Ldnull);
il.Emit (OpCodes.Call, this.methodReportFailure);
il.Append (instRet);
this.typeContractsRuntime.Methods.Add (method);
// Attach custom attributes
var attrDebugNonUserCodeCons = typeof (DebuggerNonUserCodeAttribute).GetConstructor (Type.EmptyTypes);
CustomAttribute attrDebugNonUserCode = new CustomAttribute (this.module.Import (attrDebugNonUserCodeCons));
method.CustomAttributes.Add (attrDebugNonUserCode);
var attrReliabilityContractCons = typeof (ReliabilityContractAttribute).GetConstructor (new [] { typeof (Consistency), typeof (Cer) });
// Blob for attribute: new ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)
byte [] blob = new byte [] { 1, 0, 3, 0, 0, 0, 1, 0, 0, 0 };
CustomAttribute attrReliabilityContract = new CustomAttribute (this.module.Import (attrReliabilityContractCons), blob);
method.CustomAttributes.Add (attrReliabilityContract);
// Store method
this.methodRequires = method;
}
return this.methodRequires;
}
}
}

View File

@@ -0,0 +1,188 @@
//
// Decompile.cs
//
// Authors:
// Chris Bacon (chrisbacon76@gmail.com)
//
// Copyright (C) 2010 Chris Bacon
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mono.CodeContracts.Rewrite.Ast;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Mono.CodeContracts.Rewrite {
class Decompile {
public Decompile (ModuleDefinition module, MethodDefinition method)
{
this.method = method;
this.exprs = new Stack<Expr> ();
this.Instructions = new Dictionary<Expr, Instruction> ();
this.methodInfo = new MethodInfo (module, method);
this.gen = new ExprGen (this.methodInfo);
}
private MethodInfo methodInfo;
private MethodDefinition method;
private Stack<Expr> exprs;
private ExprGen gen;
public Dictionary<Expr, Instruction> Instructions { get; private set; }
public Expr Go (bool failQuietly = true)
{
Instruction unknownInst = null;
var insts = this.method.Body.Instructions;
foreach (Instruction inst in insts) {
if (failQuietly) {
if (unknownInst == null) {
try {
Expr expr = this.ProcessInst (inst);
this.Instructions.Add (expr, inst);
this.exprs.Push (expr);
} catch (NotSupportedException) {
unknownInst = inst;
}
} else {
// Met unknown instruction, so check that there are no more contracts
if (inst.OpCode.OperandType == OperandType.InlineMethod) {
MethodReference method = (MethodReference) inst.Operand;
if (method.DeclaringType.FullName == "System.Diagnostics.Contracts.Contract") {
throw new NotSupportedException ("Unknown instruction in contract: " + unknownInst);
}
}
}
} else {
Expr expr = this.ProcessInst (inst);
this.Instructions.Add (expr, inst);
this.exprs.Push (expr);
}
}
Expr decompiled = new ExprBlock (this.methodInfo, this.exprs.Reverse ().ToArray ());
return decompiled;
}
private Expr ProcessInst (Instruction inst)
{
var opcode = inst.OpCode.Code;
switch (opcode) {
case Code.Nop:
return this.gen.Nop ();
case Code.Ldarg_0:
case Code.Ldarg_1:
case Code.Ldarg_2:
case Code.Ldarg_3:
return this.gen.LoadArg ((int) (opcode - Code.Ldarg_0));
case Code.Ldarg_S:
return this.gen.LoadArg ((ParameterDefinition) inst.Operand);
case Code.Ldnull:
return this.gen.LoadConstant (null);
case Code.Ldc_I4_M1:
case Code.Ldc_I4_0:
case Code.Ldc_I4_1:
case Code.Ldc_I4_2:
case Code.Ldc_I4_3:
case Code.Ldc_I4_4:
case Code.Ldc_I4_5:
case Code.Ldc_I4_6:
case Code.Ldc_I4_7:
case Code.Ldc_I4_8:
return this.gen.LoadConstant ((int) (opcode - Code.Ldc_I4_0));
case Code.Ldc_I4_S:
return this.gen.LoadConstant ((int) (sbyte) inst.Operand);
case Code.Ldc_I4:
return this.gen.LoadConstant ((int) inst.Operand);
case Code.Ldc_R4:
case Code.Ldc_R8:
case Code.Ldstr:
return this.gen.LoadConstant(inst.Operand);
case Code.Clt:
case Code.Clt_Un:
case Code.Cgt:
case Code.Cgt_Un:
case Code.Ceq:
case Code.Add:
case Code.Sub:
return this.ProcessBinaryOp (opcode);
case Code.Call:
return this.ProcessCall ((MethodReference) inst.Operand);
case Code.Ret:
return this.gen.Return ();
case Code.Conv_I4:
return this.ProcessConv (TypeCode.Int32);
case Code.Conv_I8:
return this.ProcessConv (TypeCode.Int64);
default:
throw new NotSupportedException ("Cannot handle opcode: " + inst.OpCode);
}
}
private Expr ProcessBinaryOp (Code opcode)
{
Expr right = this.exprs.Pop ();
Expr left = this.exprs.Pop ();
switch (opcode) {
case Code.Ceq:
return this.gen.CompareEqual (left, right);
case Code.Clt:
return this.gen.CompareLessThan (left, right, Sn.Signed);
case Code.Clt_Un:
return this.gen.CompareLessThan (left, right, Sn.Unsigned);
case Code.Cgt:
return this.gen.CompareGreaterThan (left, right, Sn.Signed);
case Code.Cgt_Un:
return this.gen.CompareGreaterThan (left, right, Sn.Unsigned);
case Code.Add:
return this.gen.Add (left, right, Sn.None, false);
case Code.Sub:
return this.gen.Sub (left, right, Sn.None, false);
default:
throw new NotSupportedException ("Unknown binary opcode: " + opcode);
}
}
private Expr ProcessCall (MethodReference method)
{
int paramCount = method.Parameters.Count;
Expr [] parameterExprs = new Expr [paramCount];
for (int i = 0; i < paramCount; i++) {
Expr parameter = this.exprs.Pop ();
parameterExprs [paramCount - i - 1] = parameter;
}
return this.gen.Call(method, parameterExprs);
}
private Expr ProcessConv (TypeCode convToType)
{
Expr exprToConvert = this.exprs.Pop ();
return this.gen.Conv(exprToConvert, convToType);
}
}
}

View File

@@ -0,0 +1,117 @@
//
// ExprGen.cs
//
// Authors:
// Chris Bacon (chrisbacon76@gmail.com)
//
// Copyright (C) 2010 Chris Bacon
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mono.CodeContracts.Rewrite.Ast;
using Mono.Cecil;
namespace Mono.CodeContracts.Rewrite {
class ExprGen {
public ExprGen (MethodInfo methodInfo)
{
this.methodInfo = methodInfo;
}
private MethodInfo methodInfo;
public ExprBlock Block (IEnumerable<Expr> exprs)
{
return new ExprBlock (this.methodInfo, exprs);
}
public ExprReturn Return ()
{
return new ExprReturn (this.methodInfo);
}
public ExprBox Box (Expr exprToBox)
{
return new ExprBox (this.methodInfo, exprToBox);
}
public ExprNop Nop ()
{
return new ExprNop (this.methodInfo);
}
public ExprLoadArg LoadArg (int index)
{
return new ExprLoadArg (this.methodInfo, index);
}
public ExprLoadArg LoadArg (ParameterDefinition parameterDefinition)
{
return this.LoadArg (parameterDefinition.Index + 1);
}
public ExprLoadConstant LoadConstant (object value)
{
return new ExprLoadConstant (this.methodInfo, value);
}
public ExprCall Call (MethodReference method, IEnumerable<Expr> parameters)
{
return new ExprCall (this.methodInfo, method, parameters);
}
public ExprCompareEqual CompareEqual (Expr left, Expr right)
{
return new ExprCompareEqual (this.methodInfo, left, right);
}
public ExprCompareLessThan CompareLessThan (Expr left, Expr right, Sn signage)
{
return new ExprCompareLessThan (this.methodInfo, left, right, signage);
}
public ExprCompareGreaterThan CompareGreaterThan (Expr left, Expr right, Sn signage)
{
return new ExprCompareGreaterThan (this.methodInfo, left, right, signage);
}
public ExprConv Conv (Expr exprToConvert, TypeCode convToType)
{
return new ExprConv (this.methodInfo, exprToConvert, convToType);
}
public ExprAdd Add (Expr left, Expr right, Sn signage, bool overflow)
{
return new ExprAdd (this.methodInfo, left, right, signage, overflow);
}
public ExprSub Sub (Expr left, Expr right, Sn signage, bool overflow)
{
return new ExprSub (this.methodInfo, left, right, signage, overflow);
}
}
}

View File

@@ -0,0 +1,92 @@
//
// MethodInfo.cs
//
// Authors:
// Chris Bacon (chrisbacon76@gmail.com)
//
// Copyright (C) 2010 Chris Bacon
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mono.Cecil;
namespace Mono.CodeContracts.Rewrite {
class MethodInfo {
public MethodInfo (ModuleDefinition module, MethodDefinition method)
{
this.Method = method;
this.Module = module;
this.typeVoid = new Lazy<TypeReference> (() => this.Module.Import (typeof (void)));
this.typeObject = new Lazy<TypeReference> (() => this.Module.Import (typeof (object)));
this.typeInt32 = new Lazy<TypeReference> (() => this.Module.Import (typeof (int)));
this.typeInt64 = new Lazy<TypeReference> (() => this.Module.Import (typeof (long)));
this.typeUInt32 = new Lazy<TypeReference> (() => this.Module.Import (typeof (uint)));
this.typeBoolean = new Lazy<TypeReference> (() => this.Module.Import (typeof (bool)));
this.typeString = new Lazy<TypeReference> (() => this.Module.Import (typeof (string)));
}
public MethodDefinition Method { get; private set; }
public ModuleDefinition Module { get; private set; }
private Lazy<TypeReference> typeVoid;
private Lazy<TypeReference> typeObject;
private Lazy<TypeReference> typeInt32;
private Lazy<TypeReference> typeInt64;
private Lazy<TypeReference> typeUInt32;
private Lazy<TypeReference> typeBoolean;
private Lazy<TypeReference> typeString;
public TypeReference TypeVoid {
get { return this.typeVoid.Value; }
}
public TypeReference TypeObject {
get { return this.typeObject.Value; }
}
public TypeReference TypeInt32 {
get { return this.typeInt32.Value; }
}
public TypeReference TypeInt64 {
get { return this.typeInt64.Value; }
}
public TypeReference TypeUInt32 {
get { return this.typeUInt32.Value; }
}
public TypeReference TypeBoolean {
get { return this.typeBoolean.Value; }
}
public TypeReference TypeString {
get { return this.typeString.Value; }
}
}
}

View File

@@ -0,0 +1,169 @@
//
// PerformRewrite.cs
//
// Authors:
// Chris Bacon (chrisbacon76@gmail.com)
//
// Copyright (C) 2010 Chris Bacon
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.CodeContracts.Rewrite.Ast;
using Mono.CodeContracts.Rewrite.AstVisitors;
namespace Mono.CodeContracts.Rewrite {
class PerformRewrite {
public PerformRewrite (RewriterOptions options)
{
this.options = options;
}
private RewriterOptions options;
private Dictionary<MethodDefinition, TransformContractsVisitor> rewrittenMethods = new Dictionary<MethodDefinition, TransformContractsVisitor> ();
public void Rewrite (AssemblyDefinition assembly)
{
foreach (ModuleDefinition module in assembly.Modules) {
ContractsRuntime contractsRuntime = new ContractsRuntime(module, this.options);
var allMethods =
from type in module.Types
from method in type.Methods
select method;
foreach (MethodDefinition method in allMethods.ToArray ()) {
this.RewriteMethod (module, method, contractsRuntime);
}
}
}
private void RewriteMethod (ModuleDefinition module, MethodDefinition method, ContractsRuntime contractsRuntime)
{
if (this.rewrittenMethods.ContainsKey (method)) {
return;
}
var overridden = this.GetOverriddenMethod (method);
if (overridden != null) {
this.RewriteMethod (module, overridden, contractsRuntime);
}
bool anyRewrites = false;
var baseMethod = this.GetBaseOverriddenMethod (method);
if (baseMethod != method) {
// Contract inheritance must be used
var vOverriddenTransform = this.rewrittenMethods [baseMethod];
// Can be null if overriding an abstract method
if (vOverriddenTransform != null) {
if (this.options.Level >= 2) {
// Only insert re-written contracts if level >= 2
foreach (var inheritedRequires in vOverriddenTransform.ContractRequiresInfo) {
this.RewriteIL (method.Body, null, null, inheritedRequires.RewrittenExpr);
anyRewrites = true;
}
}
}
}
TransformContractsVisitor vTransform = null;
if (method.HasBody) {
vTransform = this.TransformContracts (module, method, contractsRuntime);
if (vTransform.ContractRequiresInfo.Any ()) {
anyRewrites = true;
}
}
this.rewrittenMethods.Add (method, vTransform);
if (anyRewrites) {
Console.WriteLine (method);
}
}
private TransformContractsVisitor TransformContracts (ModuleDefinition module, MethodDefinition method, ContractsRuntime contractsRuntime)
{
var body = method.Body;
Decompile decompile = new Decompile (module, method);
var decomp = decompile.Go ();
TransformContractsVisitor vTransform = new TransformContractsVisitor (module, method, decompile.Instructions, contractsRuntime);
vTransform.Visit (decomp);
foreach (var replacement in vTransform.ContractRequiresInfo) {
// Only insert re-written contracts if level >= 2
Expr rewritten = this.options.Level >= 2 ? replacement.RewrittenExpr : null;
this.RewriteIL (body, decompile.Instructions, replacement.OriginalExpr, rewritten);
}
return vTransform;
}
private void RewriteIL (MethodBody body, Dictionary<Expr,Instruction> instructionLookup, Expr remove, Expr insert)
{
var il = body.GetILProcessor ();
Instruction instInsertBefore;
if (remove != null) {
var vInstExtent = new InstructionExtentVisitor (instructionLookup);
vInstExtent.Visit (remove);
instInsertBefore = vInstExtent.Instructions.Last ().Next;
foreach (var instRemove in vInstExtent.Instructions) {
il.Remove (instRemove);
}
} else {
instInsertBefore = body.Instructions [0];
}
if (insert != null) {
var compiler = new CompileVisitor (il, instructionLookup, inst => il.InsertBefore (instInsertBefore, inst));
compiler.Visit (insert);
}
}
private MethodDefinition GetOverriddenMethod (MethodDefinition method)
{
if (method.IsNewSlot || !method.IsVirtual) {
return null;
}
var baseType = method.DeclaringType.BaseType;
if (baseType == null) {
return null;
}
var overridden = baseType.Resolve ().Methods.FirstOrDefault (x => x.Name == method.Name);
return overridden;
}
private MethodDefinition GetBaseOverriddenMethod (MethodDefinition method)
{
var overridden = method;
while (true) {
var overriddenTemp = this.GetOverriddenMethod (overridden);
if (overriddenTemp == null) {
return overridden;
}
overridden = overriddenTemp;
}
}
}
}

View File

@@ -0,0 +1,103 @@
//
// Rewriter.cs
//
// Authors:
// Chris Bacon (chrisbacon76@gmail.com)
//
// Copyright (C) 2010 Chris Bacon
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mono.Cecil.Cil;
using Mono.Cecil;
using System.IO;
namespace Mono.CodeContracts.Rewrite {
public class Rewriter {
public static RewriterResults Rewrite (RewriterOptions options)
{
Rewriter rewriter = new Rewriter(options);
return rewriter.RewriteImpl();
}
private Rewriter(RewriterOptions options)
{
this.options = options;
}
private RewriterOptions options;
private List<string> warnings = new List<string> ();
private List<string> errors = new List<string> ();
private RewriterResults RewriteImpl ()
{
if (!this.options.Rewrite) {
return RewriterResults.Warning ("Not asked to rewrite");
}
if (!this.options.Assembly.IsSet) {
return RewriterResults.Error ("No assembly given to rewrite");
}
var readerParameters = new ReaderParameters ();
if (options.Debug)
readerParameters.ReadSymbols = true;
var assembly = this.options.Assembly.IsFilename ?
AssemblyDefinition.ReadAssembly (options.Assembly.Filename, readerParameters) :
AssemblyDefinition.ReadAssembly (options.Assembly.Streams.Assembly, readerParameters);
if (this.options.ForceAssemblyRename != null) {
assembly.Name.Name = this.options.ForceAssemblyRename;
} else if (this.options.OutputFile.IsSet && this.options.OutputFile.IsFilename) {
assembly.Name.Name = Path.GetFileNameWithoutExtension(this.options.OutputFile.Filename);
}
var output = this.options.OutputFile.IsSet ? this.options.OutputFile : this.options.Assembly;
var writerParameters = new WriterParameters ();
if (options.WritePdbFile) {
if (!options.Debug) {
return RewriterResults.Error ("Must specify -debug if using -writePDBFile.");
}
writerParameters.WriteSymbols = true;
}
PerformRewrite rewriter = new PerformRewrite (this.options);
rewriter.Rewrite (assembly);
if (output.IsFilename) {
assembly.Write (output.Filename, writerParameters);
} else {
assembly.Write (output.Streams.Assembly, writerParameters);
}
return new RewriterResults (warnings, errors);
}
}
}

View File

@@ -0,0 +1,62 @@
//
// RewriterOptions.cs
//
// Authors:
// Chris Bacon (chrisbacon76@gmail.com)
//
// Copyright (C) 2010 Chris Bacon
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Mono.CodeContracts.Rewrite {
public class RewriterOptions {
public RewriterOptions ()
{
// Initialise to defaults
this.Debug = true;
this.Level = 4;
this.WritePdbFile = true;
this.Rewrite = true;
this.BreakIntoDebugger = false;
this.ThrowOnFailure = false;
this.ForceAssemblyRename = null;
}
public AssemblyRef Assembly { get; set; }
public bool Debug { get; set; }
public int Level { get; set; }
public bool WritePdbFile { get; set; }
public bool Rewrite { get; set; }
public bool BreakIntoDebugger { get; set; }
public bool ThrowOnFailure { get; set; }
public AssemblyRef OutputFile { get; set; }
public string ForceAssemblyRename { get; set; }
}
}

View File

@@ -0,0 +1,82 @@
//
// RewriterResults.cs
//
// Authors:
// Chris Bacon (chrisbacon76@gmail.com)
//
// Copyright (C) 2010 Chris Bacon
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Mono.CodeContracts.Rewrite {
public class RewriterResults {
internal static RewriterResults Warning (string warning)
{
return new RewriterResults (new [] { warning }, null);
}
internal static RewriterResults Error (string error)
{
return new RewriterResults (null, new [] { error });
}
internal RewriterResults (ICollection<string> warnings, ICollection<string> errors)
{
this.warnings = warnings;
this.errors = errors;
}
private ICollection<string> warnings, errors;
public bool AnyWarnings {
get {
return this.warnings != null && this.warnings.Count > 0;
}
}
public bool AnyErrors {
get {
return this.errors != null && this.errors.Count > 0;
}
}
public IEnumerable<string> Warnings {
get {
return this.warnings ?? Enumerable.Empty<string> ();
}
}
public IEnumerable<string> Errors {
get {
return this.errors ?? Enumerable.Empty<string> ();
}
}
}
}

View File

@@ -0,0 +1,127 @@
//
// TransformContractsVisitor.cs
//
// Authors:
// Chris Bacon (chrisbacon76@gmail.com)
//
// Copyright (C) 2010 Chris Bacon
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mono.CodeContracts.Rewrite;
using Mono.CodeContracts.Rewrite.Ast;
using System.Diagnostics.Contracts;
using Mono.Cecil;
using Mono.CodeContracts.Rewrite.AstVisitors;
using Mono.Cecil.Cil;
namespace Mono.CodeContracts.Rewrite {
class TransformContractsVisitor : ExprVisitor {
public TransformContractsVisitor (ModuleDefinition module, MethodDefinition method, Dictionary<Expr, Instruction> instructionLookup, ContractsRuntime contractsRuntime)
{
//this.module = method.Module;
this.instructionLookup = instructionLookup;
this.contractsRuntime = contractsRuntime;
this.methodInfo = new MethodInfo (module, method);
}
//private ModuleDefinition module;
private Dictionary<Expr, Instruction> instructionLookup;
private ContractsRuntime contractsRuntime;
private MethodInfo methodInfo;
private List<ContractRequiresInfo> contractRequiresInfo = new List<ContractRequiresInfo> ();
public IEnumerable<ContractRequiresInfo> ContractRequiresInfo {
get { return this.contractRequiresInfo; }
}
protected override Expr VisitCall (ExprCall e)
{
var call = (ExprCall)base.VisitCall (e);
var method = e.Method;
if (method.DeclaringType.FullName == "System.Diagnostics.Contracts.Contract") {
switch (method.Name) {
case "Requires":
if (!method.HasGenericParameters) {
switch (method.Parameters.Count) {
case 1:
return this.ProcessRequires1 (call);
case 2:
return this.ProcessRequires2 (call);
default:
throw new NotSupportedException ("Invalid number of parameters to Contract.Requires()");
}
} else {
goto default;
}
default:
throw new NotSupportedException ("Cannot handle Contract." + e.Method.Name + "()");
}
}
return call;
}
private string GetConditionString (Expr e)
{
var vSource = new SourcePositionVisitor (this.instructionLookup);
vSource.Visit (e);
var extractor = new ConditionTextExtractor (vSource.SourceCodeFileName, vSource.StartPosition, vSource.EndPosition);
return extractor.GetConditionText ();
}
private Expr ProcessRequires1 (ExprCall e)
{
MethodDefinition mRequires = this.contractsRuntime.GetRequires ();
Expr conditionExpr = e.Parameters.First ();
Expr nullArgExpr = new ExprLoadConstant (this.methodInfo, null);
string conditionText = this.GetConditionString (e);
Expr conditionStringExpr = new ExprLoadConstant (this.methodInfo, conditionText);
var call = new ExprCall (this.methodInfo, mRequires, new Expr [] { conditionExpr, nullArgExpr, conditionStringExpr });
this.contractRequiresInfo.Add (new ContractRequiresInfo (e, call));
return call;
}
private Expr ProcessRequires2 (ExprCall e)
{
MethodDefinition mRequires = this.contractsRuntime.GetRequires ();
Expr conditionExpr = e.Parameters.First ();
Expr msgExpr = e.Parameters.ElementAt (1);
string conditionText = this.GetConditionString (e);
Expr conditionStringExpr = new ExprLoadConstant (this.methodInfo, conditionText);
var call = new ExprCall (this.methodInfo, mRequires, new Expr [] { conditionExpr, msgExpr, conditionStringExpr });
this.contractRequiresInfo.Add (new ContractRequiresInfo (e, call));
return call;
}
}
}