--- /dev/null
+.\"
+.\" cccheck manual page.
+.\" Copyright (C) 2011 Alexander Chebaturkin
+.\" Author:
+.\" Alexander Chebaturkin (chebaturkin@gmail.com)
+.\"
+.TH Mono "cccheck"
+.SH NAME
+cccheck \- Perform static code contracts verification for CLR assemblies.
+.SH SYNOPSIS
+.PP
+.B cccheck --assembly=<assembly> [options]
+.SH DESCRIPTION
+Perform static code contracts verification to find bugs and inconsistences
+between code and specification. This includes non-null, integer analyses.
+.PP
+The assembly must have been built with the symbol CONTRACTS_FULL defined,
+otherwise the calls to the contract methods will have been removed
+by the compiler.
+.PP
+Currently only Contract.Assume() and Contract.Assert() methods are
+supported. Only non-null analysis is supported, the consecutive analyses are
+in development. An error message will be shown if cccheck is unable to process
+all or some of the methods of specified assembly.
+.SH CONFIGURATION OPTIONS
+.TP
+.I "--assembly <assembly-name>"
+The assembly to perform static verification.
+.TP
+.I "--debug"
+Shows debug information about process of proving the assertions. It shows
+four layers of abstraction, raw layer, stack layer, heap layer,
+and substituted expression level.
+.TP
+.I "--method=<method-name-substring>"
+String for finding method. It filters all methods in assembly where method
+name has this parameter as a substring.
+.TP
+.I "--help"
+Show help for cccheck, listing configuration options.
+
+.SH EXAMPLES
+.TP
+Suppose you have a method:
+ void Method() {
+ object x = null;
+ int y = 1;
+ if (y % 2 == 1)
+ x = new object();
+ else
+ x = new string();
+
+ Contract.Assert(x != null);
+}
+
+After the verification the tool will have results in following format:
+"Assertion at : [Subroutine: <id> Block <blockId> PC <id>] :
+ is (true|false|unproven|unreachable)".
+(PC is a program counter)
+
+.SH AUTHOR
+Written by Alexander Chebaturkin
+.SH COPYRIGHT
+Copyright 2011 Alexander Chebaturkin.
+Released under MIT license.
+.SH WEB SITE
+Visit http://www.mono-project.com for details
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
<PropertyGroup>\r
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>\r
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>\r
<OutputPath>./../../class/lib/net_4_0</OutputPath>\r
<DefineConstants>NET_1_1;NET_2_0;NET_3_0;NET_3_5;NET_4_0</DefineConstants>\r
<NoStdLib>true</NoStdLib>\r
- \r
<AppDesignerFolder>Properties</AppDesignerFolder>\r
<RootNamespace>mscorlib</RootNamespace>\r
<AssemblyName>Mono.CodeContracts</AssemblyName>\r
- <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>\r
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>\r
<FileAlignment>512</FileAlignment>\r
<StartupObject>\r
</StartupObject>\r
</PropertyGroup>\r
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />\r
<ItemGroup>\r
- <Compile Include="..\..\build\common\Consts.cs" />
- <Compile Include="Assembly\AssemblyInfo.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite\AssemblyRef.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite\ConditionTextExtractor.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite\ContractRequiresInfo.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite\ContractsRuntime.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite\Decompile.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite\ExprGen.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite\MethodInfo.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite\PerformRewrite.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite\Rewriter.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite\RewriterOptions.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite\RewriterResults.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite\TransformContractsVisitor.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprAdd.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprBinaryOpArithmetic.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprBinaryOpComparison.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprBinaryOp.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprBlock.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprBox.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprCall.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprCompareEqual.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprCompareGreaterThan.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprCompareLessThan.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprConv.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.Ast\Expr.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprLoadArg.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprLoadConstant.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprNop.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprReturn.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprSub.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprType.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.Ast\Sn.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.AstVisitors\CompileVisitor.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.AstVisitors\ExprVisitor.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.AstVisitors\InstructionExtentVisitor.cs" />
- <Compile Include="Mono.CodeContracts.Rewrite.AstVisitors\SourcePositionVisitor.cs" />
-\r
+ <Compile Include="..\..\build\common\Consts.cs" />\r
+ <Compile Include="Assembly\AssemblyInfo.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite\AssemblyRef.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite\ConditionTextExtractor.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite\ContractRequiresInfo.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite\ContractsRuntime.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite\Decompile.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite\ExprGen.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite\MethodInfo.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite\PerformRewrite.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite\Rewriter.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite\RewriterOptions.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite\RewriterResults.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite\TransformContractsVisitor.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprAdd.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprBinaryOpArithmetic.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprBinaryOpComparison.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprBinaryOp.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprBlock.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprBox.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprCall.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprCompareEqual.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprCompareGreaterThan.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprCompareLessThan.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprConv.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.Ast\Expr.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprLoadArg.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprLoadConstant.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprNop.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprReturn.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprSub.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.Ast\ExprType.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.Ast\Sn.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.AstVisitors\CompileVisitor.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.AstVisitors\ExprVisitor.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.AstVisitors\InstructionExtentVisitor.cs" />\r
+ <Compile Include="Mono.CodeContracts.Rewrite.AstVisitors\SourcePositionVisitor.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.Drivers\AnalysisDriver.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.Drivers\BasicAnalysisDriver.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.Drivers\BasicMethodDriver.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.Drivers\CodeContractsAnalysisDriver.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.Drivers\IBasicAnalysisDriver.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.Drivers\IBasicMethodDriver.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.Drivers\IMethodAnalysis.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.Drivers\IMethodAnalysisFixPoint.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.Drivers\IMethodDriver.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.Drivers\IMethodResult.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding\FullExpressionDecoder.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding\IFullExpressionDecoder.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding\QueryVisitor.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding\VisitorForIsBinaryExpression.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding\VisitorForIsInst.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding\VisitorForIsNull.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding\VisitorForIsUnaryExpression.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding\VisitorForSizeOf.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding\VisitorForUnderlyingVariable.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding\VisitorForValueOf.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding\VisitorForVariable.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding\VisitorForVariablesIn.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions\BinaryExpr.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions\ConstExpr.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions\Expr.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions\IsInstExpr.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions\NullExpr.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions\SizeOfExpr.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions\UnaryExpr.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis\AnalysisDecoder.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis\AssumeDecoder.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis\ExprDomain.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis\ExpressionAnalysisFacade.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis\ExpressionDecoder.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis\ExpressionDecoderAdapter.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis\ExpressionPrinterFactory.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis\ILDecoderAdapter.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.ExpressionAnalysis\ValueAnalysis.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths\AccessPathFilter.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths\IVisibilityCheck.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths\MethodCallPathElement.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths\ParameterPathElement.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths\PathElement.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths\PathElementBase.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths\PathElement`1.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths\PathExtensions.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths\SpecialPathElement.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths\SpecialPathElementKind.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph\AbstractDomainUpdate.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph\EdgeUpdate.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph\EliminateEdgeUpdate.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph\EqualityPair.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph\EqualityUpdate.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph\IMergeInfo.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph\MergeInfo.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph\MultiEdge.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph\MultiEdgeUpdate.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph\SymGraph.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph\SymGraphTerm.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph\Update.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis\AbstractType.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis\AnalysisDecoder.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis\Domain.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis\FunctionsTable.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis\HeapAnalysis.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis\IAbstractDomainForEGraph.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis\IConstantInfo.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis\ISymGraph.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis\LabeledSymbol.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis\MethodWrapper.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis\ParameterWrapper.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis\StackToSymbolicAdapter.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis\SymbolicValue.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis\SymFunction.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis\SymValue.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis\TypeCache.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis\ValueContextProvider.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis\ValueDecoder.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.HeapAnalysis\Wrapper.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.NonNull\Analysis.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.NonNull\Domain.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.NonNull\ExpressionAssertDischarger.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.NonNull\ExpressionAssumeDecoder.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.NonNull\NonNullAnalysisFacade.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.StackAnalysis\APCMap.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.StackAnalysis\SequenceGenerator.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.StackAnalysis\StackDecoder.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.StackAnalysis\StackDepthFactory.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.StackAnalysis\StackDepthProvider.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.StackAnalysis\StackInfo.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis.StackAnalysis\StackInfo`1.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis\CodeLayer.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis\CodeLayerFactory.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis\ICodeLayer.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis\IExpressionContext.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis\IExpressionContextProvider.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis\ILPrinter.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis\IMethodContext.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis\IMethodContextProvider.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis\IStackContext.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis\IStackContextProvider.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis\IValueContext.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis\IValueContextProvider.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Analysis\PrinterFactory.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST.Visitors\CodeVisitor.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST.Visitors\DefaultNodeVisitor.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST.Visitors\IAggregateVisitor.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST.Visitors\ICodeConsumer.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST.Visitors\IExpressionILVisitor.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST.Visitors\IILVisitor.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST.Visitors\ILVisitorBase.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST.Visitors\IMethodCodeConsumer.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST.Visitors\ISymbolicExpressionVisitor.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST.Visitors\ISyntheticILVisitor.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST.Visitors\NodeInspector.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST.Visitors\NodeVisitor.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST.Visitors\ValueCodeVisitor.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\ArrayTypeNode.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\AssemblyNode.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\AssignmentStatement.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\BinaryExpression.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\BinaryOperator.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\Block.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\BlockExpression.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\BodyParser.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\Branch.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\CatchFilter.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\Class.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\Construct.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\CoreSystemTypes.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\EndFinally.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\Ensures.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\ExceptionHandler.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\Expression.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\ExpressionStatement.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\FaultHandler.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\Field.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\Literal.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\Local.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\Member.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\MemberBinding.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\Method.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\MethodCall.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\MethodContract.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\MethodContractElement.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\Module.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\NaryExpression.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\Node.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\NodeType.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\OperatorExtensions.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\Parameter.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\Property.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\Reference.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\Requires.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\Return.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\Statement.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\This.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\TypeNode.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\UnaryExpression.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\UnaryOperator.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.AST\Variable.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ContractExtraction\ContractExtractor.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ContractExtraction\ContractNodes.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ContractExtraction\GatherLocals.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ContractExtraction\HelperMethods.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ContractExtraction\RepresentationForAttribute.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Blocks\AssumeBlock.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Blocks\BlockBase.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Blocks\BlockWithLabels.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Blocks\CatchFilterEntryBlock.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Blocks\EnsuresBlock.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Blocks\EntryBlock.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Blocks\EntryExitBlock.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Blocks\LabelAdapter.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Blocks\MethodCallBlock.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Blocks\NewObjCallBlock.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders\BlockBuilder.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders\BlockStartGatherer.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders\EnsuresFactory.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders\RequiresFactory.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders\SimpleSubroutineBuilder.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders\SubroutineBuilder.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders\SubroutineFactory.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders\SubroutineWithHandlersBuilder.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Subroutines\EnsuresSubroutine.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Subroutines\FaultFinallySubroutineBase.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Subroutines\FaultSubroutine.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Subroutines\FinallySubroutine.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Subroutines\MethodContractSubroutine.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Subroutines\MethodSubroutine.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Subroutines\OldScanStateMachine.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Subroutines\OldValueSubroutine.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Subroutines\RequiresSubroutine.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Subroutines\SimpleSubroutine.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Subroutines\SubroutineBase.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Subroutines\SubroutineFacade.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow.Subroutines\SubroutineWithHandlers.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow\APC.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow\APCDecoder.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow\CFGBlock.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow\ContractFilteredCFG.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow\ControlFlowGraph.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow\Edge.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow\EdgeMap.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow\EdgeTag.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow\EdgeTagExtensions.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow\EdgeVisitor.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow\ICFG.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow\IConstantInfo.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow\IHandlerFilter.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow\IMethodInfo.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow\IStackInfo.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow\RemoveBranchDelegator.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow\Subroutine.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.ControlFlow\SubroutineKind.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataFlowAnalysis\DataFlowAnalysisBase.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataFlowAnalysis\EdgeBasedWidening.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataFlowAnalysis\EdgeConverter.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataFlowAnalysis\ForwardAnalysis.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataFlowAnalysis\ForwardDataFlowAnalysisBase.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataFlowAnalysis\IAnalysis.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataFlowAnalysis\IFixPointInfo.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataFlowAnalysis\IWidenStrategy.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataFlowAnalysis\Joiner.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataFlowAnalysis\StepWidening.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\AbstractWorkList.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\DecoratorHelper.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\DepthFirst.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\DoubleDictionary.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\DoubleImmutableMap.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\Dummy.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\EdgeVisitor.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\GraphWrapper.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\IGraph.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\IImmutableIntMap.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\IImmutableMap.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\IImmutableSet.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\IIndexable.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\ImmutableIntKeyMap.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\ImmutableIntMap.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\ImmutableMap.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\ImmutableSet.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\ImmutableSetExtensions.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\Indexable.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\ITypedProperties.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\IWorkList.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\LispList.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\LispListExtensions.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\Optional.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\Pair.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\PriorityQueue.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\TypedKey.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\TypedProperties.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\VisitStatus.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.DataStructures\WorkList.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Extensions\Extensions.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Lattices\EnvironmentDomain.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Lattices\FlatDomain.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Lattices\IAbstractDomain.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Lattices\SetDomain.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Providers\CodeContractDecoder.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Providers\CodeProviderImpl.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Providers\ICodeProvider.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Providers\IContractProvider.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Providers\IILDecoder.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Providers\IMetaDataProvider.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Providers\IMethodCodeProvider.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Providers\MetaDataProvider.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Proving\AssertionFinder.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Proving\BasicFacts.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Proving\BoxedExpression.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Proving\BoxedExpressionExtensions.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Proving\ComposedFactQuery.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Proving\ConstantPropagationFactQuery.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Proving\IFactBase.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Proving\IFactQuery.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static.Proving\SimpleLogicInference.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static\CheckResults.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static\CheckOptions.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static\Checker.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static\DebugOptions.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static\ProofOutcome.cs" />\r
+ <Compile Include="Mono.CodeContracts.Static\ProofOutcomeExtensions.cs" />\r
</ItemGroup>\r
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. \r
Other similar extension points exist, see Microsoft.Common.targets.\r
<PropertyGroup>\r
<PreBuildEvent></PreBuildEvent>\r
</PropertyGroup>\r
- <ItemGroup>
- <Reference Include="mscorlib.dll">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\\lib\build\mscorlib.dll</HintPath>
- </Reference>
- <Reference Include="System">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\\lib\build\System</HintPath>
- </Reference>
- <Reference Include="System.Core">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\\lib\build\System.Core</HintPath>
- </Reference>
- <Reference Include="Mono.Cecil.dll">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\\lib\build\Mono.Cecil.dll</HintPath>
- </Reference>
- <Reference Include="Mono.Cecil.Mdb.dll">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\\lib\build\Mono.Cecil.Mdb.dll</HintPath>
- </Reference>
- </ItemGroup>
-\r
+ <ItemGroup>\r
+ <Reference Include="mscorlib.dll">\r
+ <SpecificVersion>False</SpecificVersion>\r
+ <HintPath>..\\lib\build\mscorlib.dll</HintPath>\r
+ </Reference>\r
+ <Reference Include="System">\r
+ <SpecificVersion>False</SpecificVersion>\r
+ <HintPath>..\\lib\build\System</HintPath>\r
+ </Reference>\r
+ <Reference Include="System.Core">\r
+ <SpecificVersion>False</SpecificVersion>\r
+ <HintPath>..\\lib\build\System.Core</HintPath>\r
+ </Reference>\r
+ <Reference Include="Mono.Cecil.dll">\r
+ <SpecificVersion>False</SpecificVersion>\r
+ <HintPath>..\\lib\build\Mono.Cecil.dll</HintPath>\r
+ </Reference>\r
+ <Reference Include="Mono.Cecil.Mdb.dll">\r
+ <SpecificVersion>False</SpecificVersion>\r
+ <HintPath>..\\lib\build\Mono.Cecil.Mdb.dll</HintPath>\r
+ </Reference>\r
+ </ItemGroup>\r
<ItemGroup>\r
<Folder Include="Properties\" />\r
</ItemGroup>\r
- \r
-</Project>\r
-
+\r
+</Project>
\ No newline at end of file
--- /dev/null
+using System;
+using System.IO;
+using Mono.CodeContracts.Static.Analysis;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataFlowAnalysis;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.AST.Visitors {
+ class CodeVisitor<Variable, Expression, ContextData, EdgeData>
+ : ILVisitorBase<APC, Expression, Variable, bool, bool>,
+ IAnalysis<APC, bool, IILVisitor<APC, Expression, Variable, bool, bool>, EdgeData>
+ where ContextData : IMethodContextProvider {
+ private ICodeLayer<Expression, Variable, ContextData, EdgeData> codeLayer;
+
+ public ContextData Context
+ {
+ get { return this.codeLayer.ILDecoder.ContextProvider; }
+ }
+
+ protected IMetaDataProvider MetaDataProvider
+ {
+ get { return this.codeLayer.MetaDataProvider; }
+ }
+
+ public void Run (ICodeLayer<Expression, Variable, ContextData, EdgeData> codeLayer)
+ {
+ this.codeLayer = codeLayer;
+ codeLayer.CreateForward (this) (true);
+ }
+
+ #region Overrides of ILVisitorBase<APC,Expression,Variable,bool,bool>
+ public override bool DefaultVisit (APC pc, bool data)
+ {
+ return data;
+ }
+ #endregion
+
+ #region Implementation of IAnalysis<APC,bool,IILVisitor<APC,Expression,Variable,bool,bool>,EdgeData>
+ public IILVisitor<APC, Expression, Variable, bool, bool> GetVisitor ()
+ {
+ return this;
+ }
+
+ public virtual bool Join (Pair<APC, APC> edge, bool newstate, bool prevstate, out bool weaker, bool widen)
+ {
+ weaker = false;
+ return true;
+ }
+
+ public bool ImmutableVersion (bool arg)
+ {
+ return arg;
+ }
+
+ public bool MutableVersion (bool arg)
+ {
+ return arg;
+ }
+
+ public bool EdgeConversion (APC @from, APC to, bool isJoinPoint, EdgeData data, bool state)
+ {
+ return state;
+ }
+
+ public bool IsBottom (APC pc, bool state)
+ {
+ return !state;
+ }
+
+ public Predicate<APC> SaveFixPointInfo (IFixPointInfo<APC, bool> fixPointInfo)
+ {
+ return null;
+ }
+
+ public void Dump (Pair<bool, TextWriter> pair)
+ {
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// DefaultNodeVisitor.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+
+namespace Mono.CodeContracts.Static.AST.Visitors {
+ class DefaultNodeVisitor : NodeVisitor {
+ #region Overrides of NodeVisitor
+ public override Node Visit (Node node)
+ {
+ if (node == null)
+ return null;
+ switch (node.NodeType) {
+ case NodeType.Nop:
+ return node;
+
+ #region Binary
+ case NodeType.Add:
+ case NodeType.Sub:
+ case NodeType.Rem:
+ case NodeType.Clt:
+ case NodeType.Cgt:
+ case NodeType.Ceq:
+ case NodeType.Box:
+ case NodeType.Le:
+ case NodeType.Mul:
+ case NodeType.Div:
+ case NodeType.Div_Un:
+ case NodeType.Rem_Un:
+ case NodeType.And:
+ case NodeType.Or:
+ case NodeType.Shr:
+ case NodeType.Xor:
+ case NodeType.Shl:
+ case NodeType.Shr_Un:
+ case NodeType.Ne:
+ case NodeType.Ge:
+ case NodeType.Gt:
+ case NodeType.Lt:
+ case NodeType.Eq:
+ return VisitBinaryExpression ((BinaryExpression) node);
+ #endregion
+
+ case NodeType.Call:
+ case NodeType.Jmp:
+ case NodeType.MethodCall:
+ return VisitMethodCall ((MethodCall) node);
+
+ case NodeType.Conv:
+ case NodeType.Conv_I1:
+ case NodeType.Conv_I2:
+ case NodeType.Conv_I8:
+ case NodeType.Conv_I4:
+ case NodeType.Conv_R4:
+ case NodeType.Conv_R8:
+ case NodeType.Neg:
+ case NodeType.Not:
+ case NodeType.LogicalNot:
+ return VisitUnaryExpression ((UnaryExpression) node);
+
+ case NodeType.Literal:
+ return VisitLiteral ((Literal) node);
+ case NodeType.This:
+ return VisitThis ((This) node);
+
+ case NodeType.Block:
+ return VisitBlock ((Block) node);
+ case NodeType.Branch:
+ return VisitBranch ((Branch) node);
+ case NodeType.Return:
+ return VisitReturn ((Return) node);
+ case NodeType.AssignmentStatement:
+ return VisitAssignmentStatement ((AssignmentStatement) node);
+ case NodeType.Local:
+ return VisitLocal ((Local) node);
+ case NodeType.Parameter:
+ return VisitParameter ((Parameter) node);
+ case NodeType.ExpressionStatement:
+ return VisitExpressionStatement ((ExpressionStatement) node);
+ case NodeType.Method:
+ return VisitMethod ((Method) node);
+ case NodeType.MethodContract:
+ return VisitMethodContract ((MethodContract) node);
+ case NodeType.Requires:
+ return VisitRequires ((Requires) node);
+ case NodeType.Ensures:
+ return VisitEnsures ((Ensures) node);
+ case NodeType.TypeNode:
+ return VisitTypeNode ((TypeNode) node);
+ case NodeType.Assembly:
+ return VisitAssembly ((AssemblyNode) node);
+ case NodeType.Module:
+ return VisitModule ((Module) node);
+ case NodeType.MemberBinding:
+ return VisitMemberBinding ((MemberBinding) node);
+ case NodeType.Construct:
+ return VisitConstruct ((Construct) node);
+ }
+
+ return VisitUnknownNodeType (node);
+ }
+
+ public virtual AssemblyNode VisitAssembly (AssemblyNode node)
+ {
+ if (node == null)
+ return null;
+
+ VisitModuleList (node.Modules);
+
+
+ return node;
+ }
+
+ public virtual void VisitModuleList (IEnumerable<Module> node)
+ {
+ if (node == null)
+ return;
+
+ foreach (Module module in node)
+ VisitModule (module);
+ }
+
+ private Module VisitModule (Module node)
+ {
+ if (node == null)
+ return null;
+
+ VisitTypeNodeList (node.Types);
+
+ return node;
+ }
+
+ public virtual Statement VisitAssignmentStatement (AssignmentStatement node)
+ {
+ if (node == null)
+ return node;
+ node.Target = VisitTargetExpression (node.Target);
+ node.Source = VisitExpression (node.Source);
+
+ return node;
+ }
+
+ public virtual Expression VisitBinaryExpression (BinaryExpression node)
+ {
+ if (node == null)
+ return node;
+
+ node.Operand1 = VisitExpression (node.Operand1);
+ node.Operand2 = VisitExpression (node.Operand2);
+
+ return node;
+ }
+
+ public virtual Block VisitBlock (Block node)
+ {
+ if (node == null)
+ return null;
+
+ node.Statements = VisitStatementList (node.Statements);
+
+ return node;
+ }
+
+ public virtual List<Statement> VisitStatementList (List<Statement> node)
+ {
+ if (node == null)
+ return null;
+
+ for (int i = 0; i < node.Count; i++)
+ node [i] = (Statement) Visit (node [i]);
+
+ return node;
+ }
+
+ public virtual Statement VisitBranch (Branch node)
+ {
+ if (node == null)
+ return null;
+
+ node.Condition = VisitExpression (node.Condition);
+
+ return node;
+ }
+
+ public virtual Expression VisitConstruct (Construct node)
+ {
+ if (node == null)
+ return null;
+
+ node.Constructor = VisitExpression (node.Constructor);
+ node.Arguments = VisitExpressionList (node.Arguments);
+
+ return node;
+ }
+
+ public virtual Ensures VisitEnsures (Ensures node)
+ {
+ if (node == null)
+ return null;
+
+ node.Assertion = VisitExpression (node.Assertion);
+ node.UserMessage = VisitExpression (node.UserMessage);
+
+ return node;
+ }
+
+ public virtual Expression VisitExpression (Expression node)
+ {
+ if (node == null)
+ return null;
+
+ return node;
+ }
+
+ public virtual Statement VisitExpressionStatement (ExpressionStatement node)
+ {
+ if (node == null)
+ return null;
+
+ node.Expression = VisitExpression (node.Expression);
+
+ return node;
+ }
+
+ public virtual Expression VisitLiteral (Literal node)
+ {
+ return node;
+ }
+
+ public virtual Expression VisitLocal (Local node)
+ {
+ if (node == null)
+ return null;
+
+ node.Type = VisitTypeNode (node.Type);
+
+ //todo: maybe there should be something else
+
+ return node;
+ }
+
+ public virtual Expression VisitMemberBinding (MemberBinding node)
+ {
+ if (node == null)
+ return null;
+
+ node.TargetObject = VisitExpression (node.TargetObject);
+
+ return node;
+ }
+
+ public virtual Method VisitMethod (Method node)
+ {
+ if (node == null)
+ return null;
+
+ node.ReturnType = VisitTypeNode (node.ReturnType);
+ node.Parameters = VisitParameterList (node.Parameters);
+ node.MethodContract = VisitMethodContract (node.MethodContract);
+ node.Body = VisitBlock (node.Body);
+
+ return node;
+ }
+
+ public virtual List<Parameter> VisitParameterList (List<Parameter> node)
+ {
+ if (node == null)
+ return null;
+
+ for (int i = 0; i < node.Count; i++)
+ node [i] = VisitParameter (node [i]);
+
+ return node;
+ }
+
+ public virtual Expression VisitMethodCall (MethodCall node)
+ {
+ if (node == null)
+ return null;
+
+ node.Callee = VisitExpression (node.Callee);
+ node.Arguments = VisitExpressionList (node.Arguments);
+
+ return node;
+ }
+
+ public virtual MethodContract VisitMethodContract (MethodContract node)
+ {
+ if (node == null)
+ return null;
+
+ node.Requires = VisitRequiresList (node.Requires);
+ node.Ensures = VisitEnsuresList (node.Ensures);
+
+ return node;
+ }
+
+ public virtual List<Ensures> VisitEnsuresList (List<Ensures> node)
+ {
+ if (node == null)
+ return null;
+
+ for (int i = 0; i < node.Count; i++)
+ node [i] = (Ensures) Visit (node [i]);
+
+ return node;
+ }
+
+ public virtual List<Requires> VisitRequiresList (List<Requires> node)
+ {
+ if (node == null)
+ return null;
+
+ for (int i = 0; i < node.Count; i++)
+ node [i] = (Requires) Visit (node [i]);
+
+ return node;
+ }
+
+ public virtual Parameter VisitParameter (Parameter node)
+ {
+ if (node == null)
+ return null;
+
+ node.Type = VisitTypeNode (node.Type);
+
+ //todo: there may be something else
+
+ return node;
+ }
+
+ public virtual Requires VisitRequires (Requires node)
+ {
+ if (node == null)
+ return null;
+
+ node.Assertion = VisitExpression (node.Assertion);
+ node.UserMessage = VisitExpression (node.UserMessage);
+
+ return node;
+ }
+
+ public virtual Return VisitReturn (Return node)
+ {
+ if (node == null)
+ return null;
+
+ node.Expression = VisitExpression (node.Expression);
+
+ return node;
+ }
+
+ public virtual Expression VisitTargetExpression (Expression node)
+ {
+ return VisitExpression (node);
+ }
+
+ public virtual Expression VisitThis (This node)
+ {
+ if (node == null)
+ return null;
+
+ node.Type = VisitTypeNode (node.Type);
+
+ return node;
+ }
+
+ public virtual TypeNode VisitTypeNode (TypeNode node)
+ {
+ if (node == null)
+ return null;
+
+ var clazz = node as Class;
+ if (clazz != null)
+ clazz.BaseType = VisitTypeNode (clazz.BaseType);
+
+ VisitPropertiesList (node.Properties);
+ VisitMethodsList (node.Methods);
+ VisitTypeNodeList (node.NestedTypes);
+
+ return node;
+ }
+
+ public virtual List<Property> VisitPropertiesList (List<Property> node)
+ {
+ if (node == null)
+ return null;
+
+ for (int i = 0; i < node.Count; i++) {
+ Property property = node [i];
+ if (property != null)
+ node [i] = (Property) Visit (node [i]);
+ }
+
+ return node;
+ }
+
+ public virtual List<Method> VisitMethodsList (List<Method> node)
+ {
+ if (node == null)
+ return null;
+
+ for (int i = 0; i < node.Count; i++) {
+ Method method = node [i];
+ if (method != null)
+ node [i] = (Method) Visit (node [i]);
+ }
+
+ return node;
+ }
+
+ public virtual List<TypeNode> VisitTypeNodeList (List<TypeNode> node)
+ {
+ if (node == null)
+ return null;
+
+ for (int i = 0; i < node.Count; i++) {
+ TypeNode method = node [i];
+ if (method != null)
+ node [i] = (TypeNode) Visit (node [i]);
+ }
+
+ return node;
+ }
+
+ public virtual Expression VisitUnaryExpression (UnaryExpression node)
+ {
+ if (node == null)
+ return null;
+
+ node.Operand = VisitExpression (node.Operand);
+
+ return node;
+ }
+
+ public virtual Node VisitUnknownNodeType (Node node)
+ {
+ return node;
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// IAggregateVisitor.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.AST.Visitors {
+ interface IAggregateVisitor<Label, Data, Result> : IILVisitor<Label, Dummy, Dummy, Data, Result> {
+ Result Aggregate (Label pc, Label aggregateStart, bool canBeTargetOfBranch, Data data);
+ }
+}
--- /dev/null
+//
+// ICodeConsumer.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.AST.Visitors {
+ interface ICodeConsumer<Data, Result> {
+ Result Accept<Label> (ICodeProvider<Label> codeProvider, Label entryPoint, Data data);
+ }
+}
--- /dev/null
+//
+// IExpressionILVisitor.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST.Visitors {
+ interface IExpressionILVisitor<Label, Source, Dest, Data, Result> {
+ Result Binary (Label pc, BinaryOperator bop, Dest dest, Source src1, Source src2, Data data);
+ Result Unary (Label pc, UnaryOperator uop, bool unsigned, Dest dest, Source source, Data data);
+ Result LoadNull (Label pc, Dest dest, Data polarity);
+ Result LoadConst (Label pc, TypeNode type, object constant, Dest dest, Data data);
+ Result Sizeof (Label pc, TypeNode type, Dest dest, Data data);
+ Result Isinst (Label pc, TypeNode type, Dest dest, Source obj, Data data);
+ }
+}
--- /dev/null
+//
+// IILVisitor.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.AST.Visitors {
+ interface IILVisitor<Label, Source, Dest, Data, Result> :
+ IExpressionILVisitor<Label, Source, Dest, Data, Result>,
+ ISyntheticILVisitor<Label, Source, Dest, Data, Result> {
+ Result Arglist (Label pc, Dest dest, Data data);
+ Result Branch (Label pc, Label target, bool leavesExceptionBlock, Data data);
+ Result BranchCond (Label pc, Label target, BranchOperator bop, Source value1, Source value2, Data data);
+ Result BranchTrue (Label pc, Label target, Source cond, Data data);
+ Result BranchFalse (Label pc, Label target, Source cond, Data data);
+ Result Break (Label pc, Data data);
+
+ Result Call<TypeList, ArgList> (Label pc, Method method, bool virt, TypeList extraVarargs, Dest dest, ArgList args, Data data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<Source>;
+
+ Result Calli<TypeList, ArgList> (Label pc, TypeNode returnType, TypeList argTypes, bool instance, Dest dest, Source functionPointer, ArgList args, Data data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<Source>;
+
+ Result CheckFinite (Label pc, Dest dest, Source source, Data data);
+ Result CopyBlock (Label pc, Source destAddress, Source srcAddress, Source len, Data data);
+ Result EndFilter (Label pc, Source decision, Data data);
+ Result EndFinally (Label pc, Data data);
+ Result Jmp (Label pc, Method method, Data data);
+ Result LoadArg (Label pc, Parameter argument, bool isOld, Dest dest, Data data);
+ Result LoadArgAddress (Label pc, Parameter argument, bool isOld, Dest dest, Data data);
+ Result LoadLocal (Label pc, Local local, Dest dest, Data data);
+ Result LoadLocalAddress (Label pc, Local local, Dest dest, Data data);
+ Result Nop (Label pc, Data data);
+ Result Pop (Label pc, Source source, Data data);
+ Result Return (Label pc, Source source, Data data);
+ Result StoreArg (Label pc, Parameter argument, Source source, Data data);
+ Result StoreLocal (Label pc, Local local, Source source, Data data);
+ Result Switch (Label pc, TypeNode type, IEnumerable<Pair<object, Label>> cases, Source value, Data data);
+ Result Box (Label pc, TypeNode type, Dest dest, Source source, Data data);
+
+ Result ConstrainedCallvirt<TypeList, ArgList> (Label pc, Method method, TypeNode constraint, TypeList extraVarargs, Dest dest, ArgList args, Data data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<Source>;
+
+ Result CastClass (Label pc, TypeNode type, Dest dest, Source obj, Data data);
+ Result CopyObj (Label pc, TypeNode type, Source destPtr, Source sourcePtr, Data data);
+ Result Initobj (Label pc, TypeNode type, Source ptr, Data data);
+ Result LoadElement (Label pc, TypeNode type, Dest dest, Source array, Source index, Data data);
+ Result LoadField (Label pc, Field field, Dest dest, Source obj, Data data);
+ Result LoadFieldAddress (Label pc, Field field, Dest dest, Source obj, Data data);
+ Result LoadLength (Label pc, Dest dest, Source array, Data data);
+ Result LoadStaticField (Label pc, Field field, Dest dest, Data data);
+ Result LoadStaticFieldAddress (Label pc, Field field, Dest dest, Data data);
+ Result LoadTypeToken (Label pc, TypeNode type, Dest dest, Data data);
+ Result LoadFieldToken (Label pc, Field type, Dest dest, Data data);
+ Result LoadMethodToken (Label pc, Method type, Dest dest, Data data);
+
+ Result NewArray<ArgList> (Label pc, TypeNode type, Dest dest, ArgList lengths, Data data)
+ where ArgList : IIndexable<Source>;
+
+ Result NewObj<ArgList> (Label pc, Method ctor, Dest dest, ArgList args, Data data)
+ where ArgList : IIndexable<Source>;
+
+ Result MkRefAny (Label pc, TypeNode type, Dest dest, Source obj, Data data);
+ Result RefAnyType (Label pc, Dest dest, Source source, Data data);
+ Result RefAnyVal (Label pc, TypeNode type, Dest dest, Source source, Data data);
+ Result Rethrow (Label pc, Data data);
+ Result StoreElement (Label pc, TypeNode type, Source array, Source index, Source value, Data data);
+ Result StoreField (Label pc, Field field, Source obj, Source value, Data data);
+ Result StoreStaticField (Label pc, Field field, Source value, Data data);
+ Result Throw (Label pc, Source exception, Data data);
+ Result Unbox (Label pc, TypeNode type, Dest dest, Source obj, Data data);
+ Result UnboxAny (Label pc, TypeNode type, Dest dest, Source obj, Data data);
+ }
+}
--- /dev/null
+//
+// ILVisitorBase.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.AST.Visitors
+{
+ /// <summary>
+ /// Abstract base implementation of ILVisitor
+ /// </summary>
+ /// <remarks> Each (non-overriden) operation returns DefaultVisit(pc, data) </remarks>
+ abstract class ILVisitorBase<Label, Source, Dest, Data, Result>
+ : IILVisitor<Label, Source, Dest, Data, Result>
+ {
+ public abstract Result DefaultVisit(Label pc, Data data);
+
+ #region Implementation of IExpressionILVisitor<Label,Type,Source,Dest,Data,Result>
+ public virtual Result Binary(Label pc, BinaryOperator bop, Dest dest, Source operand1, Source operand2, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result Isinst(Label pc, TypeNode type, Dest dest, Source obj, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result LoadNull(Label pc, Dest dest, Data polarity)
+ {
+ return DefaultVisit (pc, polarity);
+ }
+
+ public virtual Result LoadConst(Label pc, TypeNode type, object constant, Dest dest, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result Sizeof(Label pc, TypeNode type, Dest dest, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result Unary(Label pc, UnaryOperator uop, bool unsigned, Dest dest, Source source, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+ #endregion
+
+ #region Implementation of IILVisitor<Label,Local,Parameter,Method,Field,Type,Source,Dest,Data,Result>
+ public virtual Result Arglist(Label pc, Dest dest, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result Branch(Label pc, Label target, bool leavesExceptionBlock, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result BranchCond(Label pc, Label target, BranchOperator bop, Source value1, Source value2, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result BranchTrue(Label pc, Label target, Source cond, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result BranchFalse(Label pc, Label target, Source cond, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result Break(Label pc, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result Call<TypeList, ArgList>(Label pc, Method method, bool virt, TypeList extraVarargs, Dest dest, ArgList args, Data data)
+ where TypeList : IIndexable<TypeNode> where ArgList : IIndexable<Source>
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result Calli<TypeList, ArgList>(Label pc, TypeNode returnType, TypeList argTypes, bool instance, Dest dest, Source functionPointer, ArgList args, Data data)
+ where TypeList : IIndexable<TypeNode> where ArgList : IIndexable<Source>
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result CheckFinite(Label pc, Dest dest, Source source, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result CopyBlock(Label pc, Source destAddress, Source srcAddress, Source len, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result EndFilter(Label pc, Source decision, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result EndFinally(Label pc, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result Jmp(Label pc, Method method, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result LoadArg(Label pc, Parameter param, bool isOld, Dest dest, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result LoadArgAddress(Label pc, Parameter param, bool isOld, Dest dest, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result LoadLocal(Label pc, Local local, Dest dest, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result LoadLocalAddress(Label pc, Local local, Dest dest, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result Nop(Label pc, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result Pop(Label pc, Source source, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result Return(Label pc, Source source, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result StoreArg(Label pc, Parameter param, Source source, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result StoreLocal(Label pc, Local local, Source source, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result Switch(Label pc, TypeNode type, IEnumerable<Pair<object, Label>> cases, Source value, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result Box(Label pc, TypeNode type, Dest dest, Source source, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result ConstrainedCallvirt<TypeList, ArgList>(Label pc, Method method, TypeNode constraint, TypeList extraVarargs, Dest dest, ArgList args, Data data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<Source>
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result CastClass(Label pc, TypeNode type, Dest dest, Source obj, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result CopyObj(Label pc, TypeNode type, Source destPtr, Source sourcePtr, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result Initobj(Label pc, TypeNode type, Source ptr, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result LoadElement(Label pc, TypeNode type, Dest dest, Source array, Source index, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result LoadField(Label pc, Field field, Dest dest, Source obj, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result LoadFieldAddress(Label pc, Field field, Dest dest, Source obj, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result LoadLength(Label pc, Dest dest, Source array, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result LoadStaticField(Label pc, Field field, Dest dest, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result LoadStaticFieldAddress(Label pc, Field field, Dest dest, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result LoadTypeToken(Label pc, TypeNode type, Dest dest, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result LoadFieldToken(Label pc, Field field, Dest dest, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result LoadMethodToken(Label pc, Method method, Dest dest, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result NewArray<ArgList>(Label pc, TypeNode type, Dest dest, ArgList lengths, Data data)
+ where ArgList : IIndexable<Source>
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result NewObj<ArgList>(Label pc, Method ctor, Dest dest, ArgList args, Data data)
+ where ArgList : IIndexable<Source>
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result MkRefAny(Label pc, TypeNode type, Dest dest, Source obj, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result RefAnyType(Label pc, Dest dest, Source source, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result RefAnyVal(Label pc, TypeNode type, Dest dest, Source source, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result Rethrow(Label pc, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result StoreElement(Label pc, TypeNode type, Source array, Source index, Source value, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result StoreField(Label pc, Field field, Source obj, Source value, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result StoreStaticField(Label pc, Field field, Source value, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result Throw(Label pc, Source exception, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result Unbox(Label pc, TypeNode type, Dest dest, Source obj, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result UnboxAny(Label pc, TypeNode type, Dest dest, Source obj, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+ #endregion
+
+ #region Implementation of ISyntheticILVisitor<Label,Method,Field,Type,Source,Dest,Data,Result>
+ public virtual Result Entry(Label pc, Method method, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result Assume(Label pc, EdgeTag tag, Source condition, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result Assert(Label pc, EdgeTag tag, Source condition, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result BeginOld(Label pc, Label matchingEnd, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result EndOld(Label pc, Label matchingBegin, TypeNode type, Dest dest, Source source, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result LoadStack(Label pc, int offset, Dest dest, Source source, bool isOld, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result LoadStackAddress(Label pc, int offset, Dest dest, Source source, TypeNode type, bool isOld, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+
+ public virtual Result LoadResult(Label pc, TypeNode type, Dest dest, Source source, Data data)
+ {
+ return DefaultVisit (pc, data);
+ }
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// IMethodCodeConsumer.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.AST.Visitors {
+ interface IMethodCodeConsumer<Data, Result> {
+ Result Accept<Label, Handler> (IMethodCodeProvider<Label, Handler> codeProvider, Label entry, Method method, Data data);
+ }
+}
--- /dev/null
+//
+// ISymbolicExpressionVisitor.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST.Visitors {
+ interface ISymbolicExpressionVisitor<Label, Source, Dest, Data, Result>
+ : IExpressionILVisitor<Label, Source, Dest, Data, Result> {
+ Result SymbolicConstant (Label pc, Dest variable, Data data);
+ }
+}
--- /dev/null
+//
+// ISyntheticILVisitor.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.ControlFlow;
+
+namespace Mono.CodeContracts.Static.AST.Visitors {
+ interface ISyntheticILVisitor<Label, Source, Dest, Data, Result> {
+ Result Entry (Label pc, Method method, Data data);
+ Result Assume (Label pc, EdgeTag tag, Source condition, Data data);
+ Result Assert (Label pc, EdgeTag tag, Source condition, Data data);
+ Result LoadStack (Label pc, int offset, Dest dest, Source source, bool isOld, Data data);
+ Result LoadStackAddress (Label pc, int offset, Dest dest, Source source, TypeNode type, bool isOld, Data data);
+ Result LoadResult (Label pc, TypeNode type, Dest dest, Source source, Data data);
+ Result BeginOld (Label pc, Label matchingEnd, Data data);
+ Result EndOld (Label pc, Label matchingBegin, TypeNode type, Dest dest, Source source, Data data);
+ }
+}
--- /dev/null
+//
+// NodeInspector.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+
+namespace Mono.CodeContracts.Static.AST.Visitors {
+ class NodeInspector {
+ public virtual void Visit (Node node)
+ {
+ if (node == null)
+ return;
+ switch (node.NodeType) {
+ case NodeType.Nop:
+ break;
+
+ #region Binary
+ case NodeType.Add:
+ case NodeType.Sub:
+ case NodeType.Rem:
+ case NodeType.Clt:
+ case NodeType.Cgt:
+ case NodeType.Ceq:
+ case NodeType.Box:
+ case NodeType.Le:
+ case NodeType.Mul:
+ case NodeType.Div:
+ case NodeType.Div_Un:
+ case NodeType.Rem_Un:
+ case NodeType.And:
+ case NodeType.Or:
+ case NodeType.Shr:
+ case NodeType.Xor:
+ case NodeType.Shl:
+ case NodeType.Shr_Un:
+ case NodeType.Ne:
+ case NodeType.Ge:
+ case NodeType.Gt:
+ case NodeType.Lt:
+ case NodeType.Eq:
+ VisitBinaryExpression ((BinaryExpression) node);
+ break;
+ #endregion
+
+ case NodeType.Call:
+ case NodeType.Jmp:
+ case NodeType.MethodCall:
+ VisitMethodCall ((MethodCall) node);
+ break;
+ case NodeType.Conv:
+ case NodeType.Conv_I1:
+ case NodeType.Conv_I2:
+ case NodeType.Conv_I8:
+ case NodeType.Conv_I4:
+ case NodeType.Conv_R4:
+ case NodeType.Conv_R8:
+ case NodeType.Neg:
+ case NodeType.Not:
+ case NodeType.LogicalNot:
+ VisitUnaryExpression ((UnaryExpression) node);
+ break;
+ case NodeType.Literal:
+ VisitLiteral ((Literal) node);
+ break;
+ case NodeType.This:
+ VisitThis ((This) node);
+ break;
+ case NodeType.Block:
+ VisitBlock ((Block) node);
+ break;
+ case NodeType.Branch:
+ VisitBranch ((Branch) node);
+ break;
+ case NodeType.Return:
+ VisitReturn ((Return) node);
+ break;
+ case NodeType.AssignmentStatement:
+ VisitAssignmentStatement ((AssignmentStatement) node);
+ break;
+ case NodeType.Local:
+ VisitLocal ((Local) node);
+ break;
+ case NodeType.Parameter:
+ VisitParameter ((Parameter) node);
+ break;
+ case NodeType.ExpressionStatement:
+ VisitExpressionStatement ((ExpressionStatement) node);
+ break;
+ case NodeType.Method:
+ VisitMethod ((Method) node);
+ break;
+ case NodeType.MethodContract:
+ VisitMethodContract ((MethodContract) node);
+ break;
+ case NodeType.Requires:
+ VisitRequires ((Requires) node);
+ break;
+ case NodeType.Ensures:
+ VisitEnsures ((Ensures) node);
+ break;
+ case NodeType.TypeNode:
+ VisitTypeNode ((TypeNode) node);
+ break;
+ case NodeType.Assembly:
+ VisitAssembly ((AssemblyNode) node);
+ break;
+ case NodeType.Module:
+ VisitModule ((Module) node);
+ break;
+ case NodeType.MemberBinding:
+ VisitMemberBinding ((MemberBinding) node);
+ break;
+ case NodeType.Construct:
+ VisitConstruct ((Construct) node);
+ break;
+ default:
+ VisitUnknownNodeType (node);
+ break;
+ }
+ }
+
+ public virtual void VisitAssembly (AssemblyNode node)
+ {
+ if (node == null)
+ return;
+
+ VisitModuleList (node.Modules);
+ }
+
+ public virtual void VisitModuleList (IEnumerable<Module> node)
+ {
+ if (node == null)
+ return;
+
+ foreach (Module module in node)
+ VisitModule (module);
+ }
+
+ public virtual void VisitModule (Module node)
+ {
+ if (node == null)
+ return;
+
+ VisitTypeNodeList (node.Types);
+ }
+
+ public virtual void VisitAssignmentStatement (AssignmentStatement node)
+ {
+ if (node == null)
+ return;
+ VisitTargetExpression (node.Target);
+ VisitExpression (node.Source);
+ }
+
+ public virtual void VisitBinaryExpression (BinaryExpression node)
+ {
+ if (node == null)
+ return;
+
+ VisitExpression (node.Operand1);
+ VisitExpression (node.Operand2);
+ }
+
+ public virtual void VisitBlock (Block node)
+ {
+ if (node == null)
+ return;
+
+ VisitStatementList (node.Statements);
+ }
+
+ public virtual void VisitStatementList (List<Statement> node)
+ {
+ if (node == null)
+ return;
+
+ for (int i = 0; i < node.Count; i++)
+ Visit (node [i]);
+ }
+
+ public virtual void VisitBranch (Branch node)
+ {
+ if (node == null)
+ return;
+
+ VisitExpression (node.Condition);
+ }
+
+ public virtual void VisitConstruct (Construct node)
+ {
+ if (node == null)
+ return;
+
+ VisitExpression (node.Constructor);
+ VisitExpressionList (node.Arguments);
+ }
+
+ public virtual void VisitExpressionList (List<Expression> list)
+ {
+ if (list == null)
+ return;
+
+ for (int i = 0; i < list.Count; ++i)
+ Visit (list [i]);
+ }
+
+ public virtual void VisitEnsures (Ensures node)
+ {
+ if (node == null)
+ return;
+
+ VisitExpression (node.Assertion);
+ VisitExpression (node.UserMessage);
+ }
+
+ public virtual void VisitExpression (Expression node)
+ {
+ if (node == null)
+ return;
+
+ //todo: maybe there will be something
+ }
+
+ public virtual void VisitExpressionStatement (ExpressionStatement node)
+ {
+ if (node == null)
+ return;
+
+ VisitExpression (node.Expression);
+ }
+
+ public virtual void VisitLiteral (Literal node)
+ {
+ }
+
+ public virtual void VisitLocal (Local node)
+ {
+ if (node == null)
+ return;
+
+ VisitTypeNode (node.Type);
+
+ //todo: maybe there should be something else
+ }
+
+ public virtual void VisitMemberBinding (MemberBinding node)
+ {
+ if (node == null)
+ return;
+
+ VisitExpression (node.TargetObject);
+ }
+
+ public virtual void VisitMethod (Method node)
+ {
+ if (node == null)
+ return;
+
+ VisitTypeNode (node.ReturnType);
+ VisitParameterList (node.Parameters);
+ VisitMethodContract (node.MethodContract);
+ VisitBlock (node.Body);
+ }
+
+ public virtual void VisitParameterList (List<Parameter> node)
+ {
+ if (node == null)
+ return;
+
+ for (int i = 0; i < node.Count; i++)
+ VisitParameter (node [i]);
+ }
+
+ public virtual void VisitMethodCall (MethodCall node)
+ {
+ if (node == null)
+ return;
+
+ VisitExpression (node.Callee);
+ VisitExpressionList (node.Arguments);
+ }
+
+ public virtual void VisitMethodContract (MethodContract node)
+ {
+ if (node == null)
+ return;
+
+ VisitRequiresList (node.Requires);
+ VisitEnsuresList (node.Ensures);
+ }
+
+ public virtual void VisitEnsuresList (List<Ensures> node)
+ {
+ if (node == null)
+ return;
+
+ for (int i = 0; i < node.Count; i++)
+ Visit (node [i]);
+ }
+
+ public virtual void VisitRequiresList (List<Requires> node)
+ {
+ if (node == null)
+ return;
+
+ for (int i = 0; i < node.Count; i++)
+ Visit (node [i]);
+ }
+
+ public virtual void VisitParameter (Parameter node)
+ {
+ if (node == null)
+ return;
+
+ VisitTypeNode (node.Type);
+
+ //todo: there may be something else
+ }
+
+ public virtual void VisitRequires (Requires node)
+ {
+ if (node == null)
+ return;
+
+ VisitExpression (node.Assertion);
+ VisitExpression (node.UserMessage);
+ }
+
+ public virtual void VisitReturn (Return node)
+ {
+ if (node == null)
+ return;
+
+ VisitExpression (node.Expression);
+ }
+
+ public virtual void VisitTargetExpression (Expression node)
+ {
+ VisitExpression (node);
+ }
+
+ public virtual void VisitThis (This node)
+ {
+ if (node == null)
+ return;
+
+ VisitTypeNode (node.Type);
+ }
+
+ public virtual void VisitTypeNode (TypeNode node)
+ {
+ if (node == null)
+ return;
+
+ var clazz = node as Class;
+ if (clazz != null)
+ VisitTypeNode (clazz.BaseType);
+
+ VisitPropertiesList (node.Properties);
+ VisitMethodsList (node.Methods);
+ VisitTypeNodeList (node.NestedTypes);
+ }
+
+ public virtual void VisitPropertiesList (List<Property> node)
+ {
+ if (node == null)
+ return;
+
+ for (int i = 0; i < node.Count; i++) {
+ Property property = node [i];
+ if (property != null)
+ Visit (node [i]);
+ }
+ }
+
+ public virtual void VisitMethodsList (List<Method> node)
+ {
+ if (node == null)
+ return;
+
+ for (int i = 0; i < node.Count; i++) {
+ Method method = node [i];
+ if (method != null)
+ Visit (node [i]);
+ }
+ }
+
+ public virtual void VisitTypeNodeList (List<TypeNode> node)
+ {
+ if (node == null)
+ return;
+
+ for (int i = 0; i < node.Count; i++) {
+ TypeNode typeNode = node [i];
+ if (typeNode != null)
+ Visit (typeNode);
+ }
+ }
+
+ public virtual void VisitUnaryExpression (UnaryExpression node)
+ {
+ if (node == null)
+ return;
+
+ VisitExpression (node.Operand);
+ }
+
+ public virtual void VisitUnknownNodeType (Node node)
+ {
+ }
+ }
+}
--- /dev/null
+//
+// NodeVisitor.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+
+namespace Mono.CodeContracts.Static.AST.Visitors {
+ abstract class NodeVisitor {
+ public abstract Node Visit (Node node);
+
+ public virtual List<Expression> VisitExpressionList (List<Expression> list)
+ {
+ if (list == null)
+ return null;
+
+ for (int i = 0; i < list.Count; ++i)
+ list [i] = (Expression) Visit (list [i]);
+
+ return list;
+ }
+ }
+}
--- /dev/null
+//
+// ValueCodeVisitor.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.Analysis;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.AST.Visitors {
+ class ValueCodeVisitor<Variable> :
+ CodeVisitor<Variable, Variable, IValueContextProvider<Variable>, IImmutableMap<Variable, LispList<Variable>>> {
+ }
+}
--- /dev/null
+//
+// ArrayTypeNode.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.Cecil;
+
+namespace Mono.CodeContracts.Static.AST {
+ class ArrayTypeNode : TypeNode {
+ public ArrayTypeNode (TypeNode type, int lowerBound, int rank) :
+ base (new ArrayType (type.TypeDefinition, rank))
+ {
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// AssemblyNode.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using System.Linq;
+using Mono.Cecil;
+
+namespace Mono.CodeContracts.Static.AST {
+ class AssemblyNode : Node {
+ private readonly AssemblyDefinition definition;
+ private IEnumerable<Module> modules;
+
+ public AssemblyNode (AssemblyDefinition definition) : base (NodeType.Assembly)
+ {
+ this.definition = definition;
+ }
+
+ public string FullName
+ {
+ get { return this.definition.FullName; }
+ }
+
+ public IEnumerable<Module> Modules
+ {
+ get
+ {
+ if (this.modules == null)
+ this.modules = this.definition.Modules.Select (it => new Module (it)).ToList ();
+ return this.modules;
+ }
+ }
+
+ public TypeNode GetType (string ns, string className)
+ {
+ foreach (Module module in Modules) {
+ TypeNode type = module.GetType (ns, className);
+ if (type != null)
+ return type;
+ }
+ IEnumerable<TypeDefinition> enumerable = this.definition.Modules.SelectMany (m => m.Types);
+ TypeDefinition firstOrDefault = enumerable.FirstOrDefault (t => t.Namespace == ns && t.Name == className);
+ if (firstOrDefault == null)
+ return null;
+
+ return TypeNode.Create (firstOrDefault);
+ }
+
+ public static AssemblyNode ReadAssembly (string filename)
+ {
+ var readerParameters = new ReaderParameters ();
+ AssemblyDefinition definition = AssemblyDefinition.ReadAssembly (filename, readerParameters);
+
+ return new AssemblyNode (definition);
+ }
+
+ public static AssemblyNode GetSystemAssembly ()
+ {
+ return ReadAssembly (typeof (object).Module.Assembly.Location);
+ }
+ }
+}
--- /dev/null
+//
+// AssignmentStatement.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ class AssignmentStatement : Statement {
+ public AssignmentStatement (Expression source, Expression target)
+ : base (NodeType.AssignmentStatement)
+ {
+ Source = source;
+ Target = target;
+ }
+
+ public Expression Source { get; set; }
+ public Expression Target { get; set; }
+
+ public override string ToString ()
+ {
+ return string.Format ("{0} := {1};", Target, Source);
+ }
+ }
+}
--- /dev/null
+//
+// BinaryExpression.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ class BinaryExpression : Expression {
+ public BinaryExpression (NodeType nodeType) : base (nodeType)
+ {
+ }
+
+ public BinaryExpression (NodeType nodeType, Expression operand1, Expression operand2) : base (nodeType)
+ {
+ Operand1 = operand1;
+ Operand2 = operand2;
+ }
+
+ public BinaryExpression (NodeType nodeType, Expression operand1, Expression operand2, TypeNode type)
+ : base (nodeType, type)
+ {
+ Operand1 = operand1;
+ Operand2 = operand2;
+ }
+
+ public Expression Operand1 { get; set; }
+ public Expression Operand2 { get; set; }
+
+ public override string ToString ()
+ {
+ return string.Format ("({1} :{0}: {2})", NodeType, Operand1, Operand2);
+ }
+ }
+}
--- /dev/null
+//
+// BinaryOperator.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ enum BinaryOperator {
+ Add,
+ Add_Ovf,
+ Add_Ovf_Un,
+ And,
+ Ceq,
+ Cobjeq,
+ Cne_Un,
+ Cge,
+ Cge_Un,
+ Cgt,
+ Cgt_Un,
+ Cle,
+ Cle_Un,
+ Clt,
+ Clt_Un,
+ Div,
+ Div_Un,
+ LogicalAnd,
+ LogicalOr,
+ Mul,
+ Mul_Ovf,
+ Mul_Ovf_Un,
+ Or,
+ Rem,
+ Rem_Un,
+ Shl,
+ Shr,
+ Shr_Un,
+ Sub,
+ Sub_Ovf,
+ Sub_Ovf_Un,
+ Xor
+ }
+}
--- /dev/null
+//
+// Block.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+
+namespace Mono.CodeContracts.Static.AST {
+ class Block : Statement {
+ public Block (List<Statement> statements) : base (NodeType.Block)
+ {
+ Statements = statements;
+ }
+
+ public Block () : base (NodeType.Block)
+ {
+ }
+
+ public int ILOffset { get; set; }
+ public List<Statement> Statements { get; set; }
+
+ public override string ToString ()
+ {
+ return string.Format ("Block(Off:{0}, Stmts:{1})", ILOffset, Statements.Count);
+ }
+ }
+}
--- /dev/null
+//
+// BlockExpression.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ class BlockExpression : Expression {
+ public Block Block;
+
+ public BlockExpression (Block block, TypeNode type)
+ : this ()
+ {
+ this.Block = block;
+ Type = type;
+ }
+
+ public BlockExpression (Block block) : this ()
+ {
+ this.Block = block;
+ }
+
+ public BlockExpression ()
+ : base (NodeType.BlockExpression)
+ {
+ }
+ }
+}
--- /dev/null
+//
+// BodyParser.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.Cecil;
+using Mono.Cecil.Cil;
+using Mono.Collections.Generic;
+
+namespace Mono.CodeContracts.Static.AST {
+ class BodyParser {
+ private readonly MethodDefinition method;
+ private readonly Dictionary<int, Block> block_map = new Dictionary<int, Block> ();
+ private readonly Stack<Expression> evaluation_stack;
+
+ public BodyParser (MethodDefinition method)
+ {
+ this.method = method;
+ this.evaluation_stack = new Stack<Expression> (2);
+
+ CoreSystemTypes.ModuleDefinition = this.method.Module;
+ }
+
+ public List<Statement> ParseBlocks ()
+ {
+ CreateBlockMap ();
+ var statements = new List<Statement> ();
+ Block block = null;
+
+ int counter = 0;
+ Collection<Instruction> instructions = this.method.Body.Instructions;
+ int size = instructions.Count;
+ while (counter < size) {
+ if (block == null) {
+ int offset = instructions [counter].Offset;
+ block = GetOrCreateBlock (offset);
+ statements.Add (block);
+ }
+
+ bool isNewBlock;
+ counter = ParseStatement (instructions, counter, block.Statements, out isNewBlock);
+ if (isNewBlock)
+ block = null;
+ }
+
+ statements.Add (GetOrCreateBlock (instructions [size - 1].Offset + 1));
+
+ return statements;
+ }
+
+ private int ParseStatement (Collection<Instruction> instructions, int index, List<Statement> result, out bool isNewBlock)
+ {
+ Expression expression = null;
+ Statement statement = null;
+ isNewBlock = false;
+
+ bool needToRepeat = true;
+ while (index < instructions.Count) {
+ Instruction inst = instructions [index++];
+ Code opcode = inst.OpCode.Code;
+ bool isStatement = false;
+ switch (opcode) {
+ case Code.Nop:
+ statement = new Statement (NodeType.Nop);
+ needToRepeat = false;
+ break;
+ case Code.Ldarg_0:
+ case Code.Ldarg_1:
+ case Code.Ldarg_2:
+ case Code.Ldarg_3:
+ expression = GetParameterExpression (opcode - Code.Ldarg_0);
+ break;
+ case Code.Ldarg_S:
+ expression = GetParameterExpression ((int) inst.Operand);
+ break;
+ case Code.Ldloc_0:
+ case Code.Ldloc_1:
+ case Code.Ldloc_2:
+ case Code.Ldloc_3:
+ expression = GetLocalExpression (opcode - Code.Ldloc_0);
+ break;
+ case Code.Ldloc_S:
+ expression = GetLocalExpression ((int) (inst.Operand));
+ break;
+ case Code.Stloc_0:
+ case Code.Stloc_1:
+ case Code.Stloc_2:
+ case Code.Stloc_3:
+ statement = new AssignmentStatement (PopOperand (), GetLocalExpression ((opcode - Code.Stloc_0)));
+ needToRepeat = false;
+ break;
+ case Code.Stloc_S:
+ statement = new AssignmentStatement (PopOperand (), GetLocalExpression ((VariableDefinition) (inst.Operand)));
+ needToRepeat = false;
+ break;
+ case Code.Starg_S:
+ statement = new AssignmentStatement (PopOperand (), GetParameterExpression ((int) (inst.Operand)));
+ needToRepeat = false;
+ break;
+ case Code.Ldarga_S:
+ throw new NotImplementedException ();
+ case Code.Ldloca_S:
+ throw new NotImplementedException ();
+ case Code.Ldnull:
+ expression = Literal.Null;
+ break;
+ 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:
+ expression = GetLiteral ((opcode - Code.Ldc_I4_0), CoreSystemTypes.Instance.TypeInt32);
+ break;
+ case Code.Ldc_I8:
+ expression = GetLiteral ((Int64) inst.Operand, CoreSystemTypes.Instance.TypeInt64);
+ break;
+ case Code.Ldc_I4_S:
+ expression = GetLiteral ((int) (sbyte) inst.Operand, CoreSystemTypes.Instance.TypeInt32);
+ break;
+ case Code.Ldc_I4:
+ expression = GetLiteral ((int) inst.Operand, CoreSystemTypes.Instance.TypeInt32);
+ break;
+ case Code.Ldc_R4:
+ expression = GetLiteral ((float) inst.Operand, CoreSystemTypes.Instance.TypeSingle);
+ break;
+ case Code.Ldc_R8:
+ expression = GetLiteral ((double) inst.Operand, CoreSystemTypes.Instance.TypeDouble);
+ break;
+ case Code.Ret:
+ statement = new Return (TypeIsVoid (this.method.ReturnType) ? null : PopOperand ());
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Br_S:
+ statement = ParseBranch (inst, NodeType.Nop, 0, true, false);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Brfalse_S:
+ statement = ParseBranch (inst, NodeType.LogicalNot, 1, true, false);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Brtrue_S:
+ statement = ParseBranch (inst, NodeType.Nop, 1, true, false);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Bne_Un_S:
+ statement = ParseBranch (inst, NodeType.Ne, 2, true, true);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Bge_Un_S:
+ statement = ParseBranch (inst, NodeType.Ge, 2, true, true);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Bgt_Un_S:
+ statement = ParseBranch (inst, NodeType.Gt, 2, true, true);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Ble_S:
+ statement = ParseBranch (inst, NodeType.Le, 2, true, false);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Blt_Un_S:
+ statement = ParseBranch (inst, NodeType.Lt, 2, true, true);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Br:
+ statement = ParseBranch (inst, NodeType.Nop, 0, false, false);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Brfalse:
+ statement = ParseBranch (inst, NodeType.LogicalNot, 0, false, false);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Brtrue:
+ statement = ParseBranch (inst, NodeType.Nop, 1, false, false);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Beq:
+ statement = ParseBranch (inst, NodeType.Eq, 2, false, false);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Bge:
+ statement = ParseBranch (inst, NodeType.Ge, 2, false, false);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Bgt:
+ statement = ParseBranch (inst, NodeType.Gt, 2, false, false);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Ble:
+ statement = ParseBranch (inst, NodeType.Le, 2, false, false);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Blt:
+ statement = ParseBranch (inst, NodeType.Lt, 2, false, false);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Bne_Un:
+ statement = ParseBranch (inst, NodeType.LogicalNot, 2, false, true);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Bge_Un:
+ statement = ParseBranch (inst, NodeType.Ge, 2, false, true);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Bgt_Un:
+ statement = ParseBranch (inst, NodeType.Gt, 2, false, true);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Ble_Un:
+ statement = ParseBranch (inst, NodeType.Le, 2, false, true);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Blt_Un:
+ statement = ParseBranch (inst, NodeType.Lt, 2, false, true);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Leave:
+ statement = ParseBranch (inst, NodeType.Nop, 0, false, false, true);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Leave_S:
+ statement = ParseBranch (inst, NodeType.Nop, 0, true, false, true);
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Endfinally:
+ statement = new EndFinally ();
+ isNewBlock = true;
+ needToRepeat = false;
+ break;
+ case Code.Switch:
+ break;
+ case Code.Ldind_I1:
+ break;
+ case Code.Ldind_U1:
+ break;
+ case Code.Ldind_I2:
+ break;
+ case Code.Ldind_U2:
+ break;
+ case Code.Ldind_I4:
+ break;
+ case Code.Ldind_U4:
+ break;
+ case Code.Ldind_I8:
+ break;
+ case Code.Ldind_I:
+ break;
+ case Code.Ldind_R4:
+ break;
+ case Code.Ldind_R8:
+ break;
+ case Code.Ldind_Ref:
+ break;
+ case Code.Stind_Ref:
+ break;
+ case Code.Stind_I1:
+ break;
+ case Code.Stind_I2:
+ break;
+ case Code.Stind_I4:
+ break;
+ case Code.Stind_I8:
+ break;
+ case Code.Stind_R4:
+ break;
+ case Code.Stind_R8:
+ break;
+ case Code.Add:
+ expression = ParseBinaryOperation (NodeType.Add);
+ break;
+ case Code.Sub:
+ expression = ParseBinaryOperation (NodeType.Sub);
+ break;
+ case Code.Mul:
+ expression = ParseBinaryOperation (NodeType.Mul);
+ break;
+ case Code.Div:
+ expression = ParseBinaryOperation (NodeType.Div);
+ break;
+ case Code.Div_Un:
+ expression = ParseBinaryOperation (NodeType.Div_Un);
+ break;
+ case Code.Rem:
+ expression = ParseBinaryOperation (NodeType.Rem);
+ break;
+ case Code.Rem_Un:
+ expression = ParseBinaryOperation (NodeType.Rem_Un);
+ break;
+ case Code.And:
+ expression = ParseBinaryOperation (NodeType.And);
+ break;
+ case Code.Or:
+ expression = ParseBinaryOperation (NodeType.Or);
+ break;
+ case Code.Xor:
+ expression = ParseBinaryOperation (NodeType.Xor);
+ break;
+ case Code.Shl:
+ expression = ParseBinaryOperation (NodeType.Shl);
+ break;
+ case Code.Shr:
+ expression = ParseBinaryOperation (NodeType.Shr);
+ break;
+ case Code.Shr_Un:
+ expression = ParseBinaryOperation (NodeType.Shr_Un);
+ break;
+ case Code.Neg:
+ expression = ParseUnaryOperation (NodeType.Neg);
+ break;
+ case Code.Not:
+ expression = ParseUnaryOperation (NodeType.Not);
+ break;
+ case Code.Conv_I1:
+ expression = new UnaryExpression (NodeType.Conv_I1, PopOperand (), CoreSystemTypes.Instance.TypeSByte);
+ break;
+ case Code.Conv_I2:
+ expression = new UnaryExpression (NodeType.Conv_I2, PopOperand (), CoreSystemTypes.Instance.TypeInt16);
+ break;
+ case Code.Conv_I4:
+ expression = new UnaryExpression (NodeType.Conv_I4, PopOperand (), CoreSystemTypes.Instance.TypeInt32);
+ break;
+ case Code.Conv_I8:
+ expression = new UnaryExpression (NodeType.Conv_I8, PopOperand (), CoreSystemTypes.Instance.TypeInt64);
+ break;
+ case Code.Conv_R4:
+ expression = new UnaryExpression (NodeType.Conv_R4, PopOperand (), CoreSystemTypes.Instance.TypeSingle);
+ break;
+ case Code.Conv_R8:
+ expression = new UnaryExpression (NodeType.Conv_R8, PopOperand (), CoreSystemTypes.Instance.TypeDouble);
+ break;
+ case Code.Conv_U4:
+ expression = new UnaryExpression (NodeType.Conv_R8, PopOperand (), CoreSystemTypes.Instance.TypeUInt32);
+ break;
+ case Code.Conv_U8:
+ expression = new UnaryExpression (NodeType.Conv_R8, PopOperand (), CoreSystemTypes.Instance.TypeUInt64);
+ break;
+ case Code.Call:
+ expression = ParseCall (inst, NodeType.Call, out isStatement);
+ if (isStatement)
+ needToRepeat = false;
+ break;
+ case Code.Callvirt:
+ expression = ParseCall (inst, NodeType.CallVirt, out isStatement);
+ if (isStatement)
+ needToRepeat = false;
+ break;
+ case Code.Cpobj:
+ break;
+ case Code.Ldobj:
+ break;
+ case Code.Ldstr:
+ expression = GetLiteral (inst.Operand, CoreSystemTypes.Instance.TypeString);
+ break;
+ case Code.Newobj:
+ expression = ParseNewObjectCreation (inst);
+ break;
+ case Code.Castclass:
+ break;
+ case Code.Isinst:
+ break;
+ case Code.Conv_R_Un:
+ break;
+ case Code.Unbox:
+ break;
+ case Code.Throw:
+ isNewBlock = true;
+ break;
+ case Code.Ldfld:
+ break;
+ case Code.Ldflda:
+ break;
+ case Code.Stfld:
+ break;
+ case Code.Ldsfld:
+ break;
+ case Code.Ldsflda:
+ break;
+ case Code.Stsfld:
+ break;
+ case Code.Stobj:
+ break;
+ case Code.Conv_Ovf_I1_Un:
+ break;
+ case Code.Conv_Ovf_I2_Un:
+ break;
+ case Code.Conv_Ovf_I4_Un:
+ break;
+ case Code.Conv_Ovf_I8_Un:
+ break;
+ case Code.Conv_Ovf_U1_Un:
+ break;
+ case Code.Conv_Ovf_U2_Un:
+ break;
+ case Code.Conv_Ovf_U4_Un:
+ break;
+ case Code.Conv_Ovf_U8_Un:
+ break;
+ case Code.Conv_Ovf_I_Un:
+ break;
+ case Code.Conv_Ovf_U_Un:
+ break;
+ case Code.Box:
+ break;
+ case Code.Newarr:
+ break;
+ case Code.Ldlen:
+ break;
+ case Code.Ldelema:
+ break;
+ case Code.Ldelem_I1:
+ break;
+ case Code.Ldelem_U1:
+ break;
+ case Code.Ldelem_I2:
+ break;
+ case Code.Ldelem_U2:
+ break;
+ case Code.Ldelem_I4:
+ break;
+ case Code.Ldelem_U4:
+ break;
+ case Code.Ldelem_I8:
+ break;
+ case Code.Ldelem_I:
+ break;
+ case Code.Ldelem_R4:
+ break;
+ case Code.Ldelem_R8:
+ break;
+ case Code.Ldelem_Ref:
+ break;
+ case Code.Stelem_I:
+ break;
+ case Code.Stelem_I1:
+ break;
+ case Code.Stelem_I2:
+ break;
+ case Code.Stelem_I4:
+ break;
+ case Code.Stelem_I8:
+ break;
+ case Code.Stelem_R4:
+ break;
+ case Code.Stelem_R8:
+ break;
+ case Code.Stelem_Ref:
+ break;
+ case Code.Ldelem_Any:
+ break;
+ case Code.Stelem_Any:
+ break;
+ case Code.Unbox_Any:
+ break;
+ case Code.Conv_Ovf_I1:
+ break;
+ case Code.Conv_Ovf_U1:
+ break;
+ case Code.Conv_Ovf_I2:
+ break;
+ case Code.Conv_Ovf_U2:
+ break;
+ case Code.Conv_Ovf_I4:
+ break;
+ case Code.Conv_Ovf_U4:
+ break;
+ case Code.Conv_Ovf_I8:
+ break;
+ case Code.Conv_Ovf_U8:
+ break;
+ case Code.Refanyval:
+ break;
+ case Code.Ckfinite:
+ break;
+ case Code.Mkrefany:
+ break;
+ case Code.Ldtoken:
+ break;
+ case Code.Conv_U2:
+ break;
+ case Code.Conv_U1:
+ break;
+ case Code.Conv_I:
+ break;
+ case Code.Conv_Ovf_I:
+ break;
+ case Code.Conv_Ovf_U:
+ break;
+ case Code.Add_Ovf:
+ break;
+ case Code.Add_Ovf_Un:
+ break;
+ case Code.Mul_Ovf:
+ break;
+ case Code.Mul_Ovf_Un:
+ break;
+ case Code.Sub_Ovf:
+ break;
+ case Code.Sub_Ovf_Un:
+ break;
+
+ case Code.Stind_I:
+ break;
+ case Code.Conv_U:
+ break;
+ case Code.Arglist:
+ break;
+ case Code.Ceq:
+ expression = ParseBinaryComparison (NodeType.Ceq);
+ break;
+ case Code.Cgt:
+ expression = ParseBinaryComparison (NodeType.Cgt);
+ break;
+ case Code.Cgt_Un:
+ break;
+ case Code.Clt:
+ expression = ParseBinaryComparison (NodeType.Clt);
+ break;
+ case Code.Clt_Un:
+ break;
+ case Code.Ldftn:
+ break;
+ case Code.Ldvirtftn:
+ break;
+ case Code.Ldarg:
+ break;
+ case Code.Ldarga:
+ break;
+ case Code.Starg:
+ break;
+ case Code.Ldloc:
+ break;
+ case Code.Ldloca:
+ break;
+ case Code.Stloc:
+ break;
+ case Code.Localloc:
+ break;
+ case Code.Endfilter:
+ isNewBlock = true;
+ break;
+ case Code.Unaligned:
+ break;
+ case Code.Volatile:
+ break;
+ case Code.Tail:
+ break;
+ case Code.Initobj:
+ break;
+ case Code.Constrained:
+ break;
+ case Code.Cpblk:
+ break;
+ case Code.Initblk:
+ break;
+ case Code.No:
+ break;
+ case Code.Rethrow:
+ isNewBlock = true;
+ break;
+ case Code.Sizeof:
+ break;
+ case Code.Refanytype:
+ break;
+ case Code.Readonly:
+ break;
+ default:
+ needToRepeat = false;
+ break;
+ }
+ if (!needToRepeat)
+ break;
+
+ int offset = inst.Next == null ? inst.Offset + 1 : inst.Next.Offset;
+ if (!this.block_map.ContainsKey (offset))
+ this.evaluation_stack.Push (expression);
+ else {
+ isNewBlock = true;
+ break;
+ }
+ }
+
+
+ while (this.evaluation_stack.Count > 0) {
+ Statement stmt = new ExpressionStatement (this.evaluation_stack.Pop ());
+ result.Add (stmt);
+ }
+
+ if (statement == null)
+ statement = new ExpressionStatement (expression);
+
+ result.Add (statement);
+ if (!isNewBlock)
+ isNewBlock = this.block_map.ContainsKey (instructions [index].Offset);
+
+ return index;
+ }
+
+
+ private Expression ParseNewObjectCreation (Instruction inst)
+ {
+ Method method = GetMethodFromMethodCallInstruction (inst);
+ int count = method.Parameters.Count;
+ List<Expression> arguments;
+ {
+ var expressions = new Expression[count];
+ for (int index = count - 1; index >= 0; index--)
+ expressions [index] = PopOperand ();
+
+ arguments = new List<Expression> (expressions);
+ }
+
+ var construct = new Construct (new MemberBinding (null, method), arguments) {Type = method.DeclaringType};
+
+ return construct;
+ }
+
+ private Expression ParseUnaryOperation (NodeType operatorType)
+ {
+ Expression operand = PopOperand ();
+ return new UnaryExpression (operatorType, operand, operand.Type);
+ }
+
+ private Expression ParseBinaryComparison (NodeType comparisonType)
+ {
+ Expression op1;
+ Expression op2;
+ Expression binaryExpression = ParseBinaryExpressionWithoutType (comparisonType, out op1, out op2);
+
+ binaryExpression.Type = CoreSystemTypes.Instance.TypeByte;
+
+ return binaryExpression;
+ }
+
+ private Expression ParseBinaryOperation (NodeType operatorType)
+ {
+ Expression op1;
+ Expression op2;
+ Expression binaryExpression = ParseBinaryExpressionWithoutType (operatorType, out op1, out op2);
+
+ binaryExpression.Type = op1.Type ?? op2.Type;
+
+ return binaryExpression;
+ }
+
+ private Expression ParseBinaryExpressionWithoutType (NodeType operatorType, out Expression op1, out Expression op2)
+ {
+ op2 = PopOperand ();
+ op1 = PopOperand ();
+
+ return new BinaryExpression (operatorType, op1, op2);
+ }
+
+ private Statement ParseBranch (Instruction inst, NodeType operatorType, int operandCount, bool isShortOffset, bool unsigned)
+ {
+ return ParseBranch (inst, operatorType, operandCount, isShortOffset, unsigned, false);
+ }
+
+ private Statement ParseBranch (Instruction inst, NodeType operatorType, int operandCount, bool isShortOffset, bool unsigned, bool leavesExceptionBlock)
+ {
+ Expression operand = operandCount > 1 ? PopOperand () : null;
+ Expression expression = operandCount > 0 ? PopOperand () : null;
+ Expression condition = operandCount > 1
+ ? new BinaryExpression (operatorType, expression, operand)
+ : (operandCount > 0
+ ? (operatorType == NodeType.Nop
+ ? expression
+ : new UnaryExpression (operatorType, expression)
+ )
+ : null);
+
+ int offset = ((Instruction) inst.Operand).Offset;
+ Block target = this.block_map [offset];
+
+ return new Branch (condition, target, isShortOffset, unsigned, leavesExceptionBlock);
+ }
+
+ private MethodCall ParseCall (Instruction instruction, NodeType typeOfCall, out bool isStatement)
+ {
+ Method method = GetMethodFromMethodCallInstruction (instruction);
+ isStatement = TypeIsVoid (method.ReturnType);
+ int parametersCount = method.Parameters == null ? 0 : method.Parameters.Count;
+ int n = typeOfCall != NodeType.Jmp ? parametersCount : 0;
+ List<Expression> arguments;
+ {
+ var expressions = new Expression[n];
+
+ for (int index = n - 1; index >= 0; --index)
+ expressions [index] = PopOperand ();
+ arguments = new List<Expression> (expressions);
+ }
+
+ var methodCall = new MethodCall (new MemberBinding (method.IsStatic ? null : PopOperand (), method), arguments, typeOfCall) {Type = method.ReturnType};
+ return methodCall;
+ }
+
+ private Method GetMethodFromMethodCallInstruction (Instruction instruction)
+ {
+ var methodReference = instruction.Operand as MethodReference;
+
+ var method = new Method (methodReference.Resolve ());
+ return method;
+ }
+
+ private Expression GetParameterExpression (int index)
+ {
+ if (this.method.IsStatic)
+ return new Parameter (this.method.Parameters [index]);
+ if (index == 0)
+ return new Parameter (this.method.Body.ThisParameter);
+
+ return new Parameter (this.method.Parameters [index - 1]);
+ }
+
+ private static bool TypeIsVoid (TypeNode type)
+ {
+ return type.FullName.Equals ("System.Void");
+ }
+
+ private static bool TypeIsVoid (TypeReference type)
+ {
+ return type.FullName.Equals ("System.Void");
+ }
+
+ private Expression GetLocalExpression (int index)
+ {
+ return new Local (this.method.Body.Variables [index]);
+ }
+
+ private Expression GetLocalExpression (VariableDefinition variable)
+ {
+ return new Local (variable);
+ }
+
+ private Expression PopOperand ()
+ {
+ return this.evaluation_stack.Pop ();
+ }
+
+ private Literal GetLiteral (object constant, TypeNode type)
+ {
+ return new Literal (constant, type);
+ }
+
+ #region Block map creation
+ private void CreateBlockMap ()
+ {
+ foreach (Instruction inst in this.method.Body.Instructions)
+ ProcessInstructionForBlockMap (inst);
+ }
+
+ private void ProcessInstructionForBlockMap (Instruction inst)
+ {
+ switch (inst.OpCode.Code) {
+ case Code.Leave:
+ case Code.Br:
+ case Code.Brfalse:
+ case Code.Brtrue:
+ case Code.Beq:
+ case Code.Bge:
+ case Code.Bgt:
+ case Code.Ble:
+ case Code.Blt:
+ case Code.Bne_Un:
+ case Code.Bge_Un:
+ case Code.Bgt_Un:
+ case Code.Ble_Un:
+ case Code.Blt_Un:
+ GetOrCreateBlock (((Instruction) inst.Operand).Offset);
+ break;
+ case Code.Leave_S:
+ case Code.Br_S:
+ case Code.Brfalse_S:
+ case Code.Brtrue_S:
+ case Code.Beq_S:
+ case Code.Bge_S:
+ case Code.Bgt_S:
+ case Code.Ble_S:
+ case Code.Blt_S:
+ case Code.Bne_Un_S:
+ case Code.Bge_Un_S:
+ case Code.Bgt_Un_S:
+ case Code.Ble_Un_S:
+ case Code.Blt_Un_S:
+ GetOrCreateBlock (((Instruction) inst.Operand).Offset);
+ break;
+ case Code.Switch:
+ break;
+ }
+ }
+
+ private Block GetOrCreateBlock (int address)
+ {
+ Block block;
+ if (!this.block_map.TryGetValue (address, out block)) {
+ this.block_map [address] = (block = new Block (new List<Statement> ()));
+ block.ILOffset = address;
+ }
+ return block;
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// Branch.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ class Branch : Statement {
+ public readonly bool LeavesExceptionBlock;
+ public Expression Condition;
+ public Block Target;
+ public bool IsShortOffset;
+ public bool Unsigned;
+
+ public Branch (Expression condition, Block target, bool isShortOffset, bool unsigned, bool leavesExceptionBlock) : base (NodeType.Branch)
+ {
+ this.Condition = condition;
+ this.Target = target;
+ this.IsShortOffset = isShortOffset;
+ this.Unsigned = unsigned;
+ this.LeavesExceptionBlock = leavesExceptionBlock;
+ }
+
+ public override string ToString ()
+ {
+ return string.Format ("Branch({0}, {1})", this.Condition == null ? "<no cond>" : this.Condition.ToString (), this.Target == null ? "<no target>" : this.Target.ToString ());
+ }
+ }
+
+ enum BranchOperator {
+ Beq,
+ Bge,
+ Bge_Un,
+ Bgt,
+ Bgt_Un,
+ Ble,
+ Ble_Un,
+ Blt,
+ Blt_Un,
+ Bne_un
+ }
+}
--- /dev/null
+//
+// CatchFilter.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ class CatchFilter : Statement {
+ public CatchFilter () : base (NodeType.Filter)
+ {
+ }
+
+ public CatchFilter (Block block, Expression expression)
+ : base (NodeType.Filter)
+ {
+ Block = block;
+ Expression = expression;
+ }
+
+ public Block Block { get; set; }
+ public Expression Expression { get; set; }
+ }
+}
--- /dev/null
+//
+// Class.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using System.Linq;
+using Mono.Cecil;
+
+namespace Mono.CodeContracts.Static.AST {
+ class Class : TypeNode {
+ public Class (TypeDefinition firstOrDefault) : base (firstOrDefault)
+ {
+ NodeType = NodeType.Class;
+ }
+
+ public IEnumerable<Method> GetMethods (string name, params TypeNode[] args)
+ {
+ IEnumerable<Method> enumerable = Methods.Where (m => m.Name == name);
+ foreach (Method method in enumerable) {
+ List<Parameter> parameters = method.Parameters;
+ bool ok = true;
+ if (args.Length != parameters.Count)
+ continue;
+
+ for (int i = 0; i < args.Length; i++) {
+ if (!parameters [i].Type.Equals (args [i])) {
+ ok = false;
+ break;
+ }
+ }
+
+ if (ok)
+ yield return method;
+ }
+ }
+
+ public Method GetMethod (string name, params TypeNode[] args)
+ {
+ return GetMethods (name, args).FirstOrDefault ();
+ }
+ }
+}
--- /dev/null
+//
+// Construct.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+
+namespace Mono.CodeContracts.Static.AST {
+ class Construct : NaryExpression {
+ public Construct ()
+ : base (null, NodeType.Construct)
+ {
+ }
+
+ public Construct (Expression constructor, List<Expression> arguments)
+ : base (arguments, NodeType.Construct)
+ {
+ Constructor = constructor;
+ }
+
+ public Expression Constructor { get; set; }
+ }
+}
--- /dev/null
+//
+// CoreSystemTypes.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.Cecil;
+
+namespace Mono.CodeContracts.Static.AST {
+ sealed class CoreSystemTypes {
+ private static CoreSystemTypes _instance;
+
+ private readonly ModuleDefinition Module;
+ private Lazy<AssemblyNode> systemAssembly;
+ private Lazy<TypeNode> typeArray;
+ private Lazy<TypeNode> typeBoolean;
+ private Lazy<TypeNode> typeByte;
+ private Lazy<TypeNode> typeChar;
+ private Lazy<TypeNode> typeDouble;
+ private Lazy<TypeNode> typeInt16;
+ private Lazy<TypeNode> typeInt32;
+ private Lazy<TypeNode> typeInt64;
+ private Lazy<TypeNode> typeIntPtr;
+ private Lazy<TypeNode> typeObject;
+ private Lazy<TypeNode> typeSByte;
+ private Lazy<TypeNode> typeSingle;
+ private Lazy<TypeNode> typeString;
+ private Lazy<TypeNode> typeSystemType;
+ private Lazy<TypeNode> typeUInt16;
+ private Lazy<TypeNode> typeUInt32;
+ private Lazy<TypeNode> typeUInt64;
+
+ private Lazy<TypeNode> typeUIntPtr;
+ private Lazy<TypeNode> typeVoid;
+
+ public CoreSystemTypes (ModuleDefinition module)
+ {
+ this.Module = module;
+
+ InitializeLazyTypes ();
+ }
+
+ public static ModuleDefinition ModuleDefinition { get; set; }
+
+ public static CoreSystemTypes Instance
+ {
+ get { return GetOrCreateInstance (ModuleDefinition); }
+ }
+
+ public TypeNode TypeObject
+ {
+ get { return this.typeObject.Value; }
+ }
+
+ public TypeNode TypeString
+ {
+ get { return this.typeString.Value; }
+ }
+
+ public TypeNode TypeBoolean
+ {
+ get { return this.typeBoolean.Value; }
+ }
+
+ public TypeNode TypeVoid
+ {
+ get { return this.typeVoid.Value; }
+ }
+
+ public TypeNode TypeSByte
+ {
+ get { return this.typeSByte.Value; }
+ }
+
+ public TypeNode TypeByte
+ {
+ get { return this.typeByte.Value; }
+ }
+
+ public TypeNode TypeInt16
+ {
+ get { return this.typeInt16.Value; }
+ }
+
+ public TypeNode TypeInt32
+ {
+ get { return this.typeInt32.Value; }
+ }
+
+ public TypeNode TypeInt64
+ {
+ get { return this.typeInt64.Value; }
+ }
+
+ public TypeNode TypeSingle
+ {
+ get { return this.typeSingle.Value; }
+ }
+
+ public TypeNode TypeDouble
+ {
+ get { return this.typeDouble.Value; }
+ }
+
+ public TypeNode TypeUInt16
+ {
+ get { return this.typeUInt16.Value; }
+ }
+
+ public TypeNode TypeUInt32
+ {
+ get { return this.typeUInt32.Value; }
+ }
+
+ public TypeNode TypeUInt64
+ {
+ get { return this.typeUInt64.Value; }
+ }
+
+ public AssemblyNode SystemAssembly
+ {
+ get { return this.systemAssembly.Value; }
+ }
+
+ public TypeNode TypeIntPtr
+ {
+ get { return this.typeIntPtr.Value; }
+ }
+
+ public TypeNode TypeArray
+ {
+ get { return this.typeArray.Value; }
+ }
+
+ public TypeNode TypeUIntPtr
+ {
+ get { return this.typeUIntPtr.Value; }
+ }
+
+ public TypeNode TypeChar
+ {
+ get { return this.typeChar.Value; }
+ }
+
+ public TypeNode TypeSystemType
+ {
+ get { return this.typeSystemType.Value; }
+ }
+
+ private static CoreSystemTypes GetOrCreateInstance (ModuleDefinition module)
+ {
+ if (_instance == null)
+ _instance = new CoreSystemTypes (module);
+
+ return _instance;
+ }
+
+ private void InitializeLazyTypes ()
+ {
+ this.typeVoid = new Lazy<TypeNode> (() => TypeNode.Create (this.Module.Import (typeof (void))));
+ this.typeSByte = new Lazy<TypeNode> (() => TypeNode.Create (this.Module.Import (typeof (SByte))));
+ this.typeByte = new Lazy<TypeNode> (() => TypeNode.Create (this.Module.Import (typeof (Byte))));
+ this.typeInt16 = new Lazy<TypeNode> (() => TypeNode.Create (this.Module.Import (typeof (Int16))));
+ this.typeInt32 = new Lazy<TypeNode> (() => TypeNode.Create (this.Module.Import (typeof (Int32))));
+ this.typeInt64 = new Lazy<TypeNode> (() => TypeNode.Create (this.Module.Import (typeof (Int64))));
+ this.typeUInt16 = new Lazy<TypeNode> (() => TypeNode.Create (this.Module.Import (typeof (UInt16))));
+ this.typeUInt32 = new Lazy<TypeNode> (() => TypeNode.Create (this.Module.Import (typeof (UInt32))));
+ this.typeUInt64 = new Lazy<TypeNode> (() => TypeNode.Create (this.Module.Import (typeof (UInt64))));
+ this.typeSingle = new Lazy<TypeNode> (() => TypeNode.Create (this.Module.Import (typeof (Single))));
+ this.typeDouble = new Lazy<TypeNode> (() => TypeNode.Create (this.Module.Import (typeof (Double))));
+ this.typeBoolean = new Lazy<TypeNode> (() => TypeNode.Create (this.Module.Import (typeof (Boolean))));
+ this.typeObject = new Lazy<TypeNode> (() => TypeNode.Create (this.Module.Import (typeof (object))));
+ this.typeString = new Lazy<TypeNode> (() => TypeNode.Create (this.Module.Import (typeof (string))));
+ this.typeArray = new Lazy<TypeNode> (() => TypeNode.Create (this.Module.Import (typeof (Array))));
+ this.typeIntPtr = new Lazy<TypeNode> (() => TypeNode.Create (this.Module.Import (typeof (IntPtr))));
+ this.typeUIntPtr = new Lazy<TypeNode> (() => TypeNode.Create (this.Module.Import (typeof (UIntPtr))));
+ this.typeChar = new Lazy<TypeNode> (() => TypeNode.Create (this.Module.Import (typeof (char))));
+ this.typeSystemType = new Lazy<TypeNode> (() => TypeNode.Create (this.Module.Import (typeof (Type))));
+
+ this.systemAssembly = new Lazy<AssemblyNode> (() => AssemblyNode.GetSystemAssembly ());
+ }
+ }
+}
--- /dev/null
+//
+// EndFinally.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ class EndFinally : Statement {
+ public EndFinally () : base (NodeType.EndFinally)
+ {
+ }
+ }
+}
--- /dev/null
+//
+// Ensures.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ class Ensures : MethodContractElement {
+ public Ensures ()
+ : base (NodeType.Ensures)
+ {
+ }
+
+ public Ensures (NodeType nodeType)
+ : base (nodeType)
+ {
+ }
+
+ public Ensures (Expression condition)
+ : this ()
+ {
+ Assertion = condition;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// ExceptionHandler.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ class ExceptionHandler : Node {
+ public ExceptionHandler () : base (NodeType.ExceptionHandler)
+ {
+ }
+
+ public NodeType HandlerType { get; set; }
+ public Block TryStartBlock { get; set; }
+ public Block BlockAfterTryEnd { get; set; }
+ public Block HandlerStartBlock { get; set; }
+ public Block BlockAfterHandlerEnd { get; set; }
+ public Block FilterExpression { get; set; }
+ public TypeNode FilterType { get; set; }
+ }
+}
--- /dev/null
+//
+// Expression.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ class Expression : Node {
+ protected TypeNode type;
+
+ public Expression (NodeType nodeType) : base (nodeType)
+ {
+ }
+
+ public Expression (NodeType nodeType, TypeNode type) : base (nodeType)
+ {
+ this.type = type;
+ }
+
+ public virtual TypeNode Type
+ {
+ get { return this.type; }
+ set { this.type = value; }
+ }
+ }
+}
--- /dev/null
+//
+// ExpressionStatement.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ class ExpressionStatement : Statement {
+ public ExpressionStatement () : base (NodeType.ExpressionStatement)
+ {
+ }
+
+ public ExpressionStatement (Expression expression)
+ : base (NodeType.ExpressionStatement)
+ {
+ Expression = expression;
+ }
+
+ public Expression Expression { get; set; }
+
+ public override string ToString ()
+ {
+ return string.Format ("ExpressionStatement({0})", Expression);
+ }
+ }
+}
--- /dev/null
+//
+// FaultHandler.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ class FaultHandler : Statement {
+ public FaultHandler () : base (NodeType.FaultHandler)
+ {
+ }
+
+ public FaultHandler (Block block) : this ()
+ {
+ Block = block;
+ }
+
+ public Block Block { get; set; }
+ }
+}
--- /dev/null
+//
+// Field.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.Cecil;
+
+namespace Mono.CodeContracts.Static.AST {
+ class Field : Member {
+ private readonly FieldDefinition definition;
+
+ public Field (FieldDefinition definition) : base (NodeType.Field)
+ {
+ this.definition = definition;
+ }
+
+ #region Overrides of Member
+ public override bool IsStatic
+ {
+ get { return this.definition.IsStatic; }
+ }
+
+ public TypeNode FieldType
+ {
+ get { return TypeNode.Create (this.definition.FieldType); }
+ }
+
+ public string Name
+ {
+ get { return this.definition.Name; }
+ }
+
+ public override TypeNode DeclaringType
+ {
+ get { return TypeNode.Create (this.definition.DeclaringType); }
+ }
+
+ public override Module Module
+ {
+ get { return new Module (this.definition.Module); }
+ }
+
+ public override bool IsPublic
+ {
+ get { return this.definition.IsPublic; }
+ }
+
+ public override bool IsPrivate
+ {
+ get { return this.definition.IsPrivate; }
+ }
+
+ public override bool IsAssembly
+ {
+ get { return this.definition.IsAssembly; }
+ }
+
+ public override bool IsFamily
+ {
+ get { return this.definition.IsFamily; }
+ }
+
+ public override bool IsFamilyOrAssembly
+ {
+ get { return this.definition.IsFamilyOrAssembly; }
+ }
+
+ public override bool IsFamilyAndAssembly
+ {
+ get { return this.definition.IsFamilyAndAssembly; }
+ }
+
+ public bool IsReadonly
+ {
+ get { return this.definition.IsInitOnly; }
+ }
+
+ public bool IsCompilerGenerated
+ {
+ get { return this.definition.IsCompilerControlled; }
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// Literal.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ sealed class Literal : Expression {
+ public static Literal Null = new Literal (null);
+ public object Value;
+
+ public Literal () : base (NodeType.Literal)
+ {
+ }
+
+ public Literal (object value)
+ : base (NodeType.Literal)
+ {
+ this.Value = value;
+ }
+
+ public Literal (object value, TypeNode type) : base (NodeType.Literal)
+ {
+ this.Value = value;
+ this.type = type;
+ }
+
+ public override string ToString ()
+ {
+ return string.Format ("Literal({0})", this.Value ?? "<null>");
+ }
+ }
+}
--- /dev/null
+//
+// Local.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.Cecil.Cil;
+
+namespace Mono.CodeContracts.Static.AST {
+ class Local : Variable {
+ public Local (VariableDefinition definition)
+ : base (NodeType.Local)
+ {
+ Definition = definition;
+ this.type = TypeNode.Create (definition.VariableType);
+ }
+
+ public VariableDefinition Definition { get; private set; }
+
+ public string Name
+ {
+ get { return ToString (); }
+ }
+
+ public override string ToString ()
+ {
+ return string.Format ("Local({0})", Definition);
+ }
+
+ public override bool Equals (object obj)
+ {
+ var other = obj as Local;
+ if (other != null)
+ return other.Definition == Definition;
+ return false;
+ }
+
+ public override int GetHashCode ()
+ {
+ return Definition.GetHashCode ();
+ }
+ }
+}
--- /dev/null
+//
+// Member.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ abstract class Member : Node {
+ public Member (NodeType nodeType) : base (nodeType)
+ {
+ }
+
+ public abstract TypeNode DeclaringType { get; }
+ public abstract Module Module { get; }
+
+ public abstract bool IsStatic { get; }
+ public abstract bool IsPublic { get; }
+ public abstract bool IsPrivate { get; }
+ public abstract bool IsAssembly { get; }
+ public abstract bool IsFamily { get; }
+ public abstract bool IsFamilyOrAssembly { get; }
+ public abstract bool IsFamilyAndAssembly { get; }
+ }
+}
--- /dev/null
+//
+// MemberBinding.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ class MemberBinding : Expression {
+ public MemberBinding ()
+ : base (NodeType.MemberBinding)
+ {
+ }
+
+ public MemberBinding (Expression targetObject, Member boundMember) : base (NodeType.MemberBinding)
+ {
+ BoundMember = boundMember;
+ TargetObject = targetObject;
+ switch (boundMember.NodeType) {
+ case NodeType.Method:
+ Type = ((Method) boundMember).ReturnType;
+ break;
+ default:
+ Type = boundMember as TypeNode;
+ break;
+ }
+ }
+
+ public Member BoundMember { get; set; }
+ public Expression TargetObject { get; set; }
+
+ public override string ToString ()
+ {
+ return string.Format ("MemberBinding({0}.{1})", TargetObject == null ? "<no target>" : TargetObject.ToString (), BoundMember);
+ }
+ }
+}
--- /dev/null
+//
+// Method.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.Cecil;
+using Mono.Cecil.Cil;
+using Mono.Collections.Generic;
+
+namespace Mono.CodeContracts.Static.AST {
+ class Method : Member, IEquatable<Method> {
+ #region Delegates
+ public delegate void MethodContractProvider (Method method);
+ #endregion
+
+ private readonly MethodDefinition definition;
+ private Block block;
+ private MethodContract contract;
+ private MethodContractProvider method_contract_provider;
+ private List<Parameter> parameters;
+ private TypeNode returnType;
+ private This thisParameter;
+
+ public Method (MethodDefinition definition)
+ : base (NodeType.Method)
+ {
+ this.definition = definition;
+ }
+
+ private Method (MethodDefinition definition, Block block) : base (NodeType.Method)
+ {
+ this.definition = definition;
+ this.block = block;
+ }
+
+ public bool HasGenericParameters
+ {
+ get { return this.definition.HasGenericParameters; }
+ }
+
+ public MethodDefinition Definition
+ {
+ get { return this.definition; }
+ }
+
+ public override TypeNode DeclaringType
+ {
+ get { return TypeNode.Create (this.definition.DeclaringType); }
+ }
+
+ public override Module Module
+ {
+ get { return new Module (this.definition.Module); }
+ }
+
+ public Method OverriddenMethod
+ {
+ get
+ {
+ if (!this.definition.HasOverrides)
+ return null;
+ return ParseMethodDefinition (this.definition.Overrides [0].Resolve ());
+ }
+ }
+
+ public Block Body
+ {
+ get
+ {
+ if (this.block == null)
+ this.block = ParseMethodBlock (this.definition);
+ return this.block;
+ }
+ set { this.block = value; }
+ }
+
+ public MethodContract MethodContract
+ {
+ get
+ {
+ if (this.contract == null && ContractProvider != null) {
+ MethodContractProvider provider = ContractProvider;
+ ContractProvider = null;
+ provider (this);
+ }
+ return this.contract;
+ }
+ set
+ {
+ this.contract = value;
+ if (value != null)
+ this.contract.DeclaringMethod = this;
+ ContractProvider = null;
+ }
+ }
+
+ public MethodContractProvider ContractProvider
+ {
+ get { return this.method_contract_provider; }
+ set
+ {
+ if (value == null) {
+ this.method_contract_provider = null;
+ return;
+ }
+
+ if (this.method_contract_provider != null)
+ this.method_contract_provider += value;
+ else
+ this.method_contract_provider = value;
+
+ this.contract = null;
+ }
+ }
+
+
+ public bool IsFinal
+ {
+ get { return this.definition.IsFinal; }
+ }
+
+ public bool HasBody
+ {
+ get { return this.definition.HasBody; }
+ }
+
+ public override bool IsPrivate
+ {
+ get { return this.definition.IsPrivate; }
+ }
+
+ public override bool IsAssembly
+ {
+ get { return this.definition.IsAssembly; }
+ }
+
+ public override bool IsFamily
+ {
+ get { return this.definition.IsFamily; }
+ }
+
+ public override bool IsFamilyOrAssembly
+ {
+ get { return this.definition.IsFamilyOrAssembly; }
+ }
+
+ public override bool IsFamilyAndAssembly
+ {
+ get { return this.definition.IsFamilyAndAssembly; }
+ }
+
+ public override bool IsPublic
+ {
+ get { return this.definition.IsPublic; }
+ }
+
+ public bool IsProtected
+ {
+ get { return this.definition.IsFamily; }
+ }
+
+ public bool IsProtectedOrInternal
+ {
+ get { return this.definition.IsFamilyOrAssembly; }
+ }
+
+ public bool IsProtectedAndInternal
+ {
+ get { return this.definition.IsFamilyAndAssembly; }
+ }
+
+ public string Name
+ {
+ get { return this.definition.Name; }
+ }
+
+ public string FullName
+ {
+ get { return this.definition.FullName; }
+ }
+
+ public bool HasOverrides
+ {
+ get { return this.definition.HasOverrides; }
+ }
+
+ public bool IsVirtual
+ {
+ get { return this.definition.IsVirtual; }
+ }
+
+ public override bool IsStatic
+ {
+ get { return this.definition.IsStatic; }
+ }
+
+ public bool IsNewSlot
+ {
+ get { return this.definition.IsNewSlot; }
+ }
+
+ public bool IsAbstract
+ {
+ get { return this.definition.IsAbstract; }
+ }
+
+ public bool IsConstructor
+ {
+ get { return this.definition.IsConstructor; }
+ }
+
+ public List<Parameter> Parameters
+ {
+ get
+ {
+ if (this.parameters == null)
+ this.parameters = this.definition.Parameters.Select (i => new Parameter (i)).ToList ();
+ return this.parameters;
+ }
+ set { this.parameters = value; }
+ }
+
+ public bool HasParameters
+ {
+ get { return Parameters != null && Parameters.Count > 0; }
+ }
+
+ public TypeNode ReturnType
+ {
+ get
+ {
+ if (this.returnType == null)
+ this.returnType = TypeNode.Create (this.definition.ReturnType);
+ return this.returnType;
+ }
+ set { this.returnType = value; }
+ }
+
+ public bool IsSetter
+ {
+ get { return this.definition.IsSetter; }
+ }
+
+ public bool IsGetter
+ {
+ get { return this.definition.IsGetter; }
+ }
+
+ public This ThisParameter
+ {
+ get
+ {
+ if (this.thisParameter == null && !IsStatic && DeclaringType != null)
+ ThisParameter = !DeclaringType.IsValueType ? new This (DeclaringType.SelfInstantiation ()) : new This (DeclaringType.SelfInstantiation ().GetReferenceType ());
+ return this.thisParameter;
+ }
+ private set
+ {
+ this.thisParameter = value;
+ if (value != null)
+ this.thisParameter.DeclaringMethod = this;
+ }
+ }
+
+ public Method DeclaringMethod { get; private set; }
+
+ public List<TypeNode> GenericParameters
+ {
+ get
+ {
+ Collection<GenericParameter> genericParameters = this.definition.GenericParameters;
+ if (genericParameters == null)
+ return null;
+ return genericParameters.Select (it => TypeNode.Create (it)).ToList ();
+ }
+ }
+
+ public IList<Local> Locals
+ {
+ get
+ {
+ Collection<VariableDefinition> variables = this.definition.Body.Variables;
+ if (variables == null)
+ return null;
+ return variables.Select (it => new Local (it)).ToList ();
+ }
+ }
+
+ public bool IsCompilerGenerated
+ {
+ get { return this.definition.IsCompilerControlled; }
+ }
+
+ #region IEquatable<Method> Members
+ public bool Equals (Method other)
+ {
+ return this.definition == other.definition;
+ }
+ #endregion
+
+ public static Method ParseMethodDefinition (MethodDefinition methodDefinition)
+ {
+ Block methodBlock = ParseMethodBlock (methodDefinition);
+
+ return new Method (methodDefinition, methodBlock);
+ }
+
+ private static Block ParseMethodBlock (MethodDefinition methodDefinition)
+ {
+ var bp = new BodyParser (methodDefinition);
+ return new Block (bp.ParseBlocks ());
+ }
+
+ public override string ToString ()
+ {
+ return string.Format ("Method(Name: {0})", FullName);
+ }
+ }
+}
--- /dev/null
+//
+// MethodCall.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using System.Linq;
+
+namespace Mono.CodeContracts.Static.AST {
+ class MethodCall : NaryExpression {
+ public MethodCall () : base (null, NodeType.MethodCall)
+ {
+ }
+
+ public MethodCall (Expression callee, List<Expression> arguments)
+ : base (arguments, NodeType.MethodCall)
+ {
+ Callee = callee;
+ }
+
+ public MethodCall (Expression callee, List<Expression> arguments, NodeType typeOfCall)
+ : base (arguments, typeOfCall)
+ {
+ Callee = callee;
+ }
+
+ public Expression Callee { get; set; }
+
+ public override string ToString ()
+ {
+ return string.Format ("MethodCall({0}, args:{{{1}}})", Callee, string.Join (", ", Arguments.Select (it => it.ToString ())));
+ }
+ }
+}
--- /dev/null
+//
+// MethodContract.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+
+namespace Mono.CodeContracts.Static.AST {
+ class MethodContract : Node {
+ public Method DeclaringMethod;
+
+ public MethodContract (Method method) : base (NodeType.MethodContract)
+ {
+ this.DeclaringMethod = method;
+ }
+
+ public List<Requires> Requires { get; set; }
+
+ public List<Ensures> Ensures { get; set; }
+
+ public int RequiresCount
+ {
+ get
+ {
+ List<Requires> list = Requires;
+ if (list == null)
+ return 0;
+ return list.Count;
+ }
+ }
+
+ public int EnsuresCount
+ {
+ get
+ {
+ List<Ensures> list = Ensures;
+ if (list == null)
+ return 0;
+ return list.Count;
+ }
+ }
+ }
+}
--- /dev/null
+//
+// MethodContractElement.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ abstract class MethodContractElement : Node {
+ public Expression UserMessage;
+
+ protected MethodContractElement (NodeType nodeType) : base (nodeType)
+ {
+ }
+
+ public Expression Assertion { get; set; }
+ }
+}
--- /dev/null
+//
+// Module.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using System.Linq;
+using Mono.Cecil;
+
+namespace Mono.CodeContracts.Static.AST {
+ class Module : Node {
+ private readonly ModuleDefinition definition;
+ private List<TypeNode> types;
+
+ public Module (ModuleDefinition module) : base (NodeType.Module)
+ {
+ this.definition = module;
+ }
+
+ public ModuleDefinition Definition
+ {
+ get { return this.definition; }
+ }
+
+
+ public List<TypeNode> Types
+ {
+ get
+ {
+ if (this.types == null)
+ this.types = this.definition.Types.Select (it => TypeNode.Create (it)).ToList ();
+
+ return this.types;
+ }
+ }
+
+ public TypeNode GetType (string ns, string className)
+ {
+ TypeReference firstOrDefault = this.definition.Types.FirstOrDefault (t => t.Namespace == ns && t.Name == className);
+ if (firstOrDefault == null)
+ return null;
+
+ return TypeNode.Create (firstOrDefault);
+ }
+ }
+}
--- /dev/null
+//
+// NaryExpression.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+
+namespace Mono.CodeContracts.Static.AST {
+ abstract class NaryExpression : Expression {
+ public NaryExpression () : base (NodeType.Nop)
+ {
+ }
+
+ public NaryExpression (List<Expression> arguments, NodeType nodeType)
+ : base (nodeType)
+ {
+ Arguments = arguments;
+ }
+
+ public List<Expression> Arguments { get; set; }
+ }
+}
--- /dev/null
+//
+// Node.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ abstract class Node {
+ protected Node (NodeType nodeType)
+ {
+ NodeType = nodeType;
+ }
+
+ public NodeType NodeType { get; set; }
+ }
+}
--- /dev/null
+//
+// NodeType.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ enum NodeType {
+ Unknown,
+ Block,
+ Nop,
+ LoadArg,
+ LoadConstant,
+ Clt,
+ Cgt,
+ Ceq,
+ Return,
+ Box,
+ Conv,
+ Add,
+ Sub,
+ Rem,
+ Expression,
+ Literal,
+ Instruction,
+ AssignmentStatement,
+ Local,
+ Parameter,
+ Branch,
+ ExpressionStatement,
+ Le,
+ Mul,
+ Div,
+ Div_Un,
+ Rem_Un,
+ And,
+ Or,
+ Shr,
+ Xor,
+ Shl,
+ Shr_Un,
+ Neg,
+ Not,
+ Conv_I1,
+ Conv_I2,
+ Conv_I8,
+ Conv_I4,
+ Conv_R4,
+ Conv_R8,
+ LogicalNot,
+ Ne,
+ Ge,
+ Gt,
+ Lt,
+ Eq,
+ This,
+ Method,
+ MethodContract,
+ Requires,
+ Ensures,
+ ExceptionHandler,
+ Filter,
+ Catch,
+ Finally,
+ FaultHandler,
+ TypeNode,
+ EndFinally,
+ Call,
+ Calli,
+ Jmp,
+ MethodCall,
+ MemberBinding,
+ Construct,
+ Class,
+ Property,
+ Assembly,
+ Module,
+ BlockExpression,
+ CallVirt,
+ Field,
+ Reference
+ }
+}
--- /dev/null
+//
+// OperatorExtensions.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ static class OperatorExtensions {
+ public static bool IsConversionOperator (this UnaryOperator op)
+ {
+ switch (op) {
+ case UnaryOperator.Conv_i:
+ case UnaryOperator.Conv_i1:
+ case UnaryOperator.Conv_i2:
+ case UnaryOperator.Conv_i4:
+ case UnaryOperator.Conv_i8:
+ case UnaryOperator.Conv_r4:
+ case UnaryOperator.Conv_r8:
+ case UnaryOperator.Conv_u:
+ case UnaryOperator.Conv_u1:
+ case UnaryOperator.Conv_u2:
+ case UnaryOperator.Conv_u4:
+ case UnaryOperator.Conv_u8:
+ case UnaryOperator.Conv_r_un:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public static bool IsEqualityOperator (this BinaryOperator bop)
+ {
+ return bop == BinaryOperator.Ceq || bop == BinaryOperator.Cobjeq;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// Parameter.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.Cecil;
+
+namespace Mono.CodeContracts.Static.AST {
+ class Parameter : Variable {
+ private readonly ParameterDefinition definition;
+ private Method declaringMethod;
+ private bool declaringMethodSpecified;
+
+ public Parameter () : base (NodeType.Parameter)
+ {
+ }
+
+ public Parameter (ParameterDefinition definition) : base (NodeType.Parameter)
+ {
+ this.definition = definition;
+ this.type = TypeNode.Create (definition.ParameterType);
+ }
+
+ public string Name { get; protected set; }
+
+ public Method DeclaringMethod
+ {
+ get
+ {
+ if (!this.declaringMethodSpecified && this.declaringMethod == null) {
+ var methodReference = this.definition.Method as MethodReference;
+ if (methodReference == null)
+ throw new NotImplementedException ("Function pointers are not implemented");
+
+ this.declaringMethod = new Method (methodReference.Resolve ());
+ }
+ return this.declaringMethod;
+ }
+ set
+ {
+ this.declaringMethod = value;
+ this.declaringMethodSpecified = true;
+ }
+ }
+
+ public virtual int Index
+ {
+ get { return this.definition.Index; }
+ }
+
+ public virtual bool IsOut
+ {
+ get { return this.definition.IsOut; }
+ }
+
+ public override string ToString ()
+ {
+ return string.Format ("Parameter({0})", this.definition);
+ }
+ }
+}
--- /dev/null
+//
+// Property.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.Cecil;
+
+namespace Mono.CodeContracts.Static.AST {
+ class Property : Member {
+ private readonly PropertyDefinition definition;
+
+ public Property (PropertyDefinition definition) : base (NodeType.Property)
+ {
+ this.definition = definition;
+ }
+
+ #region Overrides of Member
+ public override TypeNode DeclaringType
+ {
+ get { return TypeNode.Create (this.definition.DeclaringType); }
+ }
+
+ public override Module Module
+ {
+ get { return new Module (this.definition.Module); }
+ }
+
+ public override bool IsStatic
+ {
+ get { return (Getter == null || Getter.IsStatic) && (Setter == null || Setter.IsStatic); }
+ }
+
+ public override bool IsPublic
+ {
+ get
+ {
+ //todo: implement this
+ return true;
+ }
+ }
+
+ public override bool IsPrivate
+ {
+ get
+ {
+ //todo: implement this
+ return false;
+ }
+ }
+
+ public override bool IsAssembly
+ {
+ get
+ {
+ //todo: implement this
+ return false;
+ }
+ }
+
+ public override bool IsFamily
+ {
+ get
+ {
+ //todo: implement this
+ return false;
+ }
+ }
+
+ public override bool IsFamilyOrAssembly
+ {
+ get
+ {
+ //todo: implement this
+ return false;
+ }
+ }
+
+ public override bool IsFamilyAndAssembly
+ {
+ get
+ {
+ //todo: implement this
+ return false;
+ }
+ }
+
+ public Method Getter
+ {
+ get
+ {
+ MethodDefinition methodDefinition = this.definition.GetMethod;
+ if (methodDefinition == null)
+ return null;
+ return new Method (methodDefinition);
+ }
+ }
+
+ public Method Setter
+ {
+ get
+ {
+ MethodDefinition methodDefinition = this.definition.SetMethod;
+ if (methodDefinition == null)
+ return null;
+ return new Method (methodDefinition);
+ }
+ }
+
+ public bool HasGetter
+ {
+ get { return (Getter != null); }
+ }
+
+ public bool HasSetter
+ {
+ get { return (Setter != null); }
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// Reference.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ class Reference : TypeNode {
+ private readonly TypeNode element_type;
+ private readonly string name;
+
+ public Reference (TypeNode elementType) : base (NodeType.Reference)
+ {
+ TypeDefinition = null;
+ this.element_type = elementType;
+ this.name = elementType.Name + "^";
+ }
+
+ public override string Name
+ {
+ get { return this.name; }
+ }
+
+ public override string FullName
+ {
+ get { return this.element_type.FullName + "^"; }
+ }
+
+ public TypeNode ElementType
+ {
+ get { return this.element_type; }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// Requires.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ class Requires : MethodContractElement {
+ public Requires ()
+ : base (NodeType.Requires)
+ {
+ }
+
+ public Requires (NodeType nodeType)
+ : base (nodeType)
+ {
+ }
+
+ public Requires (Expression condition)
+ : this ()
+ {
+ Assertion = condition;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// Return.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ class Return : ExpressionStatement {
+ public Return ()
+ {
+ NodeType = NodeType.Return;
+ }
+
+ public Return (Expression expression)
+ : base (expression)
+ {
+ NodeType = NodeType.Return;
+ }
+
+ public override string ToString ()
+ {
+ return string.Format ("return {0};", Expression);
+ }
+ }
+}
--- /dev/null
+//
+// Statement.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ class Statement : Node {
+ public Statement (NodeType nodeType) : base (nodeType)
+ {
+ }
+
+ public override string ToString ()
+ {
+ return string.Format ("Statement({0})", NodeType);
+ }
+ }
+}
--- /dev/null
+//
+// This.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ class This : Parameter {
+ public This ()
+ {
+ base.NodeType = NodeType.This;
+ base.Name = "this";
+ }
+
+ public This (TypeNode type) : this ()
+ {
+ this.type = type;
+ DeclaringMethod = null;
+ }
+
+ public override int Index
+ {
+ get { return 0; }
+ }
+
+ public override bool IsOut
+ {
+ get { return false; }
+ }
+
+ public override string ToString ()
+ {
+ return "<this>";
+ }
+ }
+}
--- /dev/null
+//
+// TypeNode.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.Cecil;
+
+namespace Mono.CodeContracts.Static.AST {
+ class TypeNode : Member, IEquatable<TypeNode> {
+ private TypeNode base_type;
+ private List<Method> methods;
+ private List<TypeNode> nestedTypes;
+ private List<Property> properties;
+
+ protected TypeNode () : base (NodeType.TypeNode)
+ {
+ }
+
+ protected TypeNode (NodeType nodeType)
+ : base (nodeType)
+ {
+ }
+
+ protected TypeNode (TypeReference typeReference) : this ()
+ {
+ TypeDefinition = typeReference as TypeDefinition ?? typeReference.Resolve ();
+ }
+
+ public TypeDefinition TypeDefinition { get; set; }
+
+ public IEnumerable<TypeNode> Interfaces
+ {
+ get
+ {
+ if (TypeDefinition == null)
+ return null;
+ return TypeDefinition.Interfaces.Select (i => new TypeNode (i));
+ }
+ }
+
+ public TypeNode BaseType
+ {
+ get
+ {
+ if (this.base_type == null && TypeDefinition != null)
+ this.base_type = new TypeNode (TypeDefinition.BaseType);
+ return this.base_type;
+ }
+ set { this.base_type = value; }
+ }
+
+ public virtual string FullName
+ {
+ get { return TypeDefinition == null ? "<null>" : TypeDefinition.FullName; }
+ }
+
+ public List<Property> Properties
+ {
+ get
+ {
+ if (this.properties == null)
+ this.properties = TypeDefinition.Properties.Select (it => new Property (it)).ToList ();
+ return this.properties;
+ }
+ set { this.properties = value; }
+ }
+
+ public List<Method> Methods
+ {
+ get
+ {
+ if (this.methods == null)
+ this.methods = TypeDefinition.Methods.Select (it => new Method (it)).ToList ();
+ return this.methods;
+ }
+ set { this.methods = value; }
+ }
+
+ public List<TypeNode> NestedTypes
+ {
+ get
+ {
+ if (this.nestedTypes == null)
+ this.nestedTypes = TypeDefinition.NestedTypes.Select (it => new TypeNode (it)).ToList ();
+ return this.nestedTypes;
+ }
+ set { this.nestedTypes = value; }
+ }
+
+ public virtual string Name
+ {
+ get { return TypeDefinition.Name; }
+ }
+
+ public static TypeNode Create (TypeReference typeReference)
+ {
+ TypeDefinition typeDefinition = typeReference.Resolve ();
+ if (typeDefinition == null)
+ return null;
+ if (typeDefinition.IsClass)
+ return new Class (typeDefinition);
+
+ return new TypeNode (typeDefinition);
+ }
+
+ public bool IsAssignableTo (TypeNode targetType)
+ {
+ if (this == CoreSystemTypes.Instance.TypeVoid)
+ return false;
+ if (targetType == this)
+ return true;
+ if (this == CoreSystemTypes.Instance.TypeObject)
+ return false;
+ if (targetType == CoreSystemTypes.Instance.TypeObject || BaseType.IsAssignableTo (targetType))
+ return true;
+ IEnumerable<TypeNode> interfaces = Interfaces;
+ if (interfaces == null || !interfaces.Any ())
+ return false;
+ foreach (TypeNode iface in interfaces) {
+ if (iface != null && iface.IsAssignableTo (targetType))
+ return true;
+ }
+ return false;
+ }
+
+ public TypeNode GetReferenceType ()
+ {
+ return new Reference (this);
+ }
+
+ public override string ToString ()
+ {
+ return string.Format ("Type({0})", FullName);
+ }
+
+ public TypeNode SelfInstantiation ()
+ {
+ //todo: implement this for generic
+ return this;
+ }
+
+ public TypeNode GetArrayType (int rank)
+ {
+ return new ArrayTypeNode (this, 0, rank);
+ }
+
+ #region Implementation of IEquatable<TypeNode>
+ public bool Equals (TypeNode other)
+ {
+ return TypeDefinition == other.TypeDefinition;
+ }
+
+ public override int GetHashCode ()
+ {
+ return TypeDefinition.GetHashCode ();
+ }
+
+ public override bool Equals (object obj)
+ {
+ return Equals (obj as TypeNode);
+ }
+ #endregion
+
+ #region Overrides of Member
+ private int classSize;
+ private bool classSizeSpecified;
+
+ public override bool IsStatic
+ {
+ get { return false; }
+ }
+
+ public override TypeNode DeclaringType
+ {
+ get { return Create (TypeDefinition.DeclaringType); }
+ }
+
+ public override Module Module
+ {
+ get
+ {
+ if (TypeDefinition == null)
+ return null;
+ return new Module (TypeDefinition.Module);
+ }
+ }
+
+ public override bool IsPublic
+ {
+ get { return TypeDefinition != null && TypeDefinition.IsPublic; }
+ }
+
+ public override bool IsAssembly
+ {
+ get { return TypeDefinition != null && TypeDefinition.IsNotPublic; }
+ }
+
+ public override bool IsPrivate
+ {
+ get { return false; }
+ }
+
+ public override bool IsFamily
+ {
+ get { return false; }
+ }
+
+ public override bool IsFamilyOrAssembly
+ {
+ get { return IsFamily || IsAssembly; }
+ }
+
+ public override bool IsFamilyAndAssembly
+ {
+ get { return IsFamily && IsAssembly; }
+ }
+
+ public virtual bool IsValueType
+ {
+ get { return TypeDefinition != null && TypeDefinition.IsValueType; }
+ }
+
+ public virtual bool IsStruct
+ {
+ get { return TypeDefinition != null && TypeDefinition.IsValueType; }
+ }
+
+ public virtual bool IsArray
+ {
+ get { return TypeDefinition != null && TypeDefinition.IsArray; }
+ }
+
+ public virtual bool IsInterface
+ {
+ get { return TypeDefinition != null && TypeDefinition.IsInterface; }
+ }
+
+ public virtual bool HasGenericParameters
+ {
+ get { return TypeDefinition != null && TypeDefinition.HasGenericParameters; }
+ }
+
+ public virtual bool IsNestedFamily
+ {
+ get { return TypeDefinition != null && TypeDefinition.IsNestedFamily; }
+ }
+
+ public virtual bool IsNestedPublic
+ {
+ get { return TypeDefinition != null && TypeDefinition.IsNestedPublic; }
+ }
+
+ public virtual bool IsNestedInternal
+ {
+ get { return TypeDefinition != null && TypeDefinition.IsNestedAssembly; }
+ }
+
+ public virtual bool IsNestedFamilyAndAssembly
+ {
+ get { return TypeDefinition != null && TypeDefinition.IsNestedFamilyAndAssembly; }
+ }
+
+ public virtual bool IsNestedAssembly
+ {
+ get { return TypeDefinition != null && TypeDefinition.IsNestedAssembly; }
+ }
+
+ public virtual bool IsPrimitive
+ {
+ get { return TypeDefinition != null && TypeDefinition.IsPrimitive; }
+ }
+
+ public virtual bool IsEnum
+ {
+ get { return TypeDefinition != null && TypeDefinition.IsEnum; }
+ }
+
+ public virtual bool IsClass
+ {
+ get { return TypeDefinition != null && TypeDefinition.IsClass; }
+ }
+
+ public virtual IEnumerable<Field> Fields
+ {
+ get
+ {
+ if (TypeDefinition == null)
+ return null;
+ return TypeDefinition.Fields.Select (it => new Field (it));
+ }
+ }
+
+ public int ClassSize
+ {
+ get
+ {
+ if (!this.classSizeSpecified && TypeDefinition != null)
+ ClassSize = TypeDefinition.ClassSize;
+ return this.classSize;
+ }
+ set
+ {
+ this.classSize = value;
+ this.classSizeSpecified = true;
+ }
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// UnaryExpression.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ class UnaryExpression : Expression {
+ public UnaryExpression (NodeType nodeType)
+ : base (nodeType)
+ {
+ }
+
+ public UnaryExpression (NodeType nodeType, Expression operand)
+ : base (nodeType)
+ {
+ Operand = operand;
+ }
+
+ public UnaryExpression (NodeType nodeType, Expression operand, TypeNode type)
+ : base (nodeType, type)
+ {
+ Operand = operand;
+ }
+
+ public Expression Operand { get; set; }
+
+ public override string ToString ()
+ {
+ return string.Format ("Unary({0}: {1})", NodeType, Operand);
+ }
+ }
+}
--- /dev/null
+//
+// UnaryOperator.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ enum UnaryOperator {
+ Conv_i,
+ Conv_i1,
+ Conv_i2,
+ Conv_i4,
+ Conv_i8,
+ Conv_r4,
+ Conv_r8,
+ Conv_u,
+ Conv_u1,
+ Conv_u2,
+ Conv_u4,
+ Conv_u8,
+ Conv_r_un,
+ Neg,
+ Not,
+ }
+}
--- /dev/null
+//
+// Variable.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.AST {
+ abstract class Variable : Expression {
+ protected Variable (NodeType type)
+ : base (type)
+ {
+ }
+ }
+}
--- /dev/null
+//
+// AnalysisDriver.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.ControlFlow.Subroutines;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis.Drivers {
+ abstract class AnalysisDriver<Expression, Variable>
+ : IBasicAnalysisDriver {
+ private readonly IBasicAnalysisDriver basic_driver;
+
+ protected AnalysisDriver (IBasicAnalysisDriver basicDriver)
+ {
+ this.basic_driver = basicDriver;
+ }
+
+ #region IBasicAnalysisDriver Members
+ public SubroutineFacade SubroutineFacade
+ {
+ get { return this.basic_driver.SubroutineFacade; }
+ }
+
+ public IMetaDataProvider MetaDataProvider
+ {
+ get { return this.basic_driver.MetaDataProvider; }
+ }
+
+ public IContractProvider ContractProvider
+ {
+ get { return this.basic_driver.ContractProvider; }
+ }
+ #endregion
+
+ public abstract IMethodDriver<Expression, Variable> CreateMethodDriver (Method method);
+ }
+}
--- /dev/null
+//
+// BasicAnalysisDriver.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.ControlFlow.Subroutines;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis.Drivers {
+ class BasicAnalysisDriver : IBasicAnalysisDriver {
+ private readonly IContractProvider contract_provider;
+ private readonly IMetaDataProvider meta_data_provider;
+
+ #region Implementation of IBasicAnalysisDriver<Local,Parameter,Method,Field,Property,Event,Type,Attribute,Assembly>
+ public IMetaDataProvider MetaDataProvider
+ {
+ get { return this.meta_data_provider; }
+ }
+
+
+ public IContractProvider ContractProvider
+ {
+ get { return this.contract_provider; }
+ }
+
+ public SubroutineFacade SubroutineFacade { get; private set; }
+ #endregion
+
+ public BasicAnalysisDriver (IMetaDataProvider metaDataProvider,
+ IContractProvider contractProvider)
+ {
+ SubroutineFacade = new SubroutineFacade (metaDataProvider, contractProvider);
+ this.meta_data_provider = metaDataProvider;
+ this.contract_provider = contractProvider;
+ }
+
+ public BasicMethodDriver CreateMethodDriver (Method method)
+ {
+ return new BasicMethodDriver (method, this);
+ }
+ }
+}
--- /dev/null
+//
+// BasicMethodDriver.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.Analysis.StackAnalysis;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.Drivers {
+ class BasicMethodDriver {
+ private readonly Method method;
+ private readonly IBasicAnalysisDriver parent;
+ private ICFG contract_free_cfg;
+
+ private ICodeLayer<Dummy, Dummy, IMethodContextProvider, Dummy> contract_free_raw_layer;
+ private ICodeLayer<int, int, IStackContextProvider, Dummy> contract_free_stack_layer;
+
+ public BasicMethodDriver (Method method, IBasicAnalysisDriver parent)
+ {
+ this.method = method;
+ this.parent = parent;
+
+ RawLayer = CodeLayerFactory.Create (
+ this.parent.SubroutineFacade.GetControlFlowGraph (method).GetDecoder (parent.MetaDataProvider),
+ parent.MetaDataProvider,
+ parent.ContractProvider, dummy => "", dummy => "");
+
+ if (DebugOptions.Debug) {
+ Console.WriteLine ("-----APC based CFG-----");
+ RawLayer.ILDecoder.ContextProvider.MethodContext.CFG.Print (Console.Out, RawLayer.Printer, null, null);
+ }
+
+ StackLayer = CodeLayerFactory.Create (
+ StackDepthFactory.Create (RawLayer.ILDecoder, RawLayer.MetaDataProvider),
+ RawLayer.MetaDataProvider,
+ RawLayer.ContractProvider, (i => "s" + i.ToString ()), i => "s" + i.ToString ()
+ );
+
+ if (DebugOptions.Debug)
+ {
+ Console.WriteLine ("-----Stack based CFG-----");
+ StackLayer.ILDecoder.ContextProvider.MethodContext.CFG.Print (Console.Out, StackLayer.Printer, null, null);
+ }
+ }
+
+ public Method CurrentMethod
+ {
+ get { return this.method; }
+ }
+
+ public IBasicAnalysisDriver AnalysisDriver
+ {
+ get { return this.parent; }
+ }
+
+ public ICodeLayer<Dummy, Dummy, IMethodContextProvider, Dummy> RawLayer { get; private set; }
+ public ICodeLayer<int, int, IStackContextProvider, Dummy> StackLayer { get; private set; }
+
+ public ICodeLayer<Dummy, Dummy, IMethodContextProvider, Dummy> ContractFreeRawLayer
+ {
+ get
+ {
+ if (this.contract_free_raw_layer == null) {
+ this.contract_free_raw_layer =
+ CodeLayerFactory.Create (ContractFreeCFG.GetDecoder (this.parent.MetaDataProvider),
+ RawLayer.MetaDataProvider,
+ RawLayer.ContractProvider,
+ RawLayer.ExpressionToString, RawLayer.VariableToString, RawLayer.Printer);
+ }
+ return this.contract_free_raw_layer;
+ }
+ }
+
+ public ICodeLayer<int, int, IStackContextProvider, Dummy> ContractFreeStackLayer
+ {
+ get
+ {
+ if (this.contract_free_stack_layer == null) {
+ this.contract_free_stack_layer =
+ CodeLayerFactory.Create (StackDepthFactory.Create (ContractFreeRawLayer.ILDecoder, this.contract_free_raw_layer.MetaDataProvider),
+ ContractFreeRawLayer.MetaDataProvider,
+ ContractFreeRawLayer.ContractProvider,
+ StackLayer.ExpressionToString, StackLayer.VariableToString, StackLayer.Printer);
+ }
+ return this.contract_free_stack_layer;
+ }
+ }
+
+ public ICFG ContractFreeCFG
+ {
+ get
+ {
+ if (this.contract_free_cfg == null) {
+ this.contract_free_cfg = new ContractFilteredCFG (RawLayer.ILDecoder.ContextProvider.MethodContext.CFG);
+
+ if (DebugOptions.Debug)
+ {
+ Console.WriteLine ("------raw contract-free cfg -----------------");
+ this.contract_free_cfg.Print (Console.Out, RawLayer.Printer, null, null);
+ }
+ }
+ return this.contract_free_cfg;
+ }
+ }
+
+ public ICFG CFG
+ {
+ get { return StackLayer.ILDecoder.ContextProvider.MethodContext.CFG; }
+ }
+ }
+}
--- /dev/null
+using System;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.Analysis.ExpressionAnalysis;
+using Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding;
+using Mono.CodeContracts.Static.Analysis.HeapAnalysis;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+using Mono.CodeContracts.Static.Proving;
+
+namespace Mono.CodeContracts.Static.Analysis.Drivers {
+ class CodeContractsAnalysisDriver<MethodResult>
+ : AnalysisDriver<LabeledSymbol<APC, SymbolicValue>, SymbolicValue> {
+ public CodeContractsAnalysisDriver (IBasicAnalysisDriver basicDriver)
+ : base (basicDriver)
+ {
+ }
+
+ public override IMethodDriver<LabeledSymbol<APC, SymbolicValue>, SymbolicValue> CreateMethodDriver (Method method)
+ {
+ return new MethodDriver (method, this);
+ }
+
+ #region Nested type: MethodDriver
+ private class MethodDriver : BasicMethodDriver,
+ IMethodDriver<LabeledSymbol<APC, SymbolicValue>, SymbolicValue>,
+ IFactBase<SymbolicValue> {
+ private Func<LabeledSymbol<APC, SymbolicValue>, string> expr2String;
+ private IFullExpressionDecoder<SymbolicValue, LabeledSymbol<APC, SymbolicValue>> expression_decoder;
+ private HeapAnalysis.HeapAnalysis heap_analysis;
+
+ public MethodDriver (Method method,
+ CodeContractsAnalysisDriver<MethodResult> parent)
+ : base (method, parent)
+ {
+ }
+
+ private new AnalysisDriver<LabeledSymbol<APC, SymbolicValue>, SymbolicValue> AnalysisDriver
+ {
+ get { return (AnalysisDriver<LabeledSymbol<APC, SymbolicValue>, SymbolicValue>) base.AnalysisDriver; }
+ }
+
+ #region IFactBase<SymbolicValue> Members
+ public ProofOutcome IsNull (APC pc, SymbolicValue variable)
+ {
+ return ProofOutcome.Top;
+ }
+
+ public ProofOutcome IsNonNull (APC pc, SymbolicValue variable)
+ {
+ return ProofOutcome.Top;
+ }
+
+ public bool IsUnreachable (APC pc)
+ {
+ return this.heap_analysis.IsUnreachable (pc);
+ }
+ #endregion
+
+ #region IMethodDriver<LabeledSymbol<APC,SymbolicValue>,SymbolicValue> Members
+ public ICodeLayer<SymbolicValue, SymbolicValue,
+ IValueContextProvider<SymbolicValue>,
+ IImmutableMap<SymbolicValue, LispList<SymbolicValue>>> ValueLayer { get; private set; }
+
+ public ICodeLayer<LabeledSymbol<APC, SymbolicValue>, SymbolicValue,
+ IExpressionContextProvider<LabeledSymbol<APC, SymbolicValue>, SymbolicValue>,
+ IImmutableMap<SymbolicValue, LispList<SymbolicValue>>> ExpressionLayer { get; private set; }
+
+ public ICodeLayer<SymbolicValue, SymbolicValue,
+ IValueContextProvider<SymbolicValue>,
+ IImmutableMap<SymbolicValue, LispList<SymbolicValue>>> HybridLayer { get; private set; }
+
+ public IExpressionContextProvider<LabeledSymbol<APC, SymbolicValue>, SymbolicValue> ContextProvider
+ {
+ get { return ExpressionLayer.ILDecoder.ContextProvider; }
+ }
+
+ public IMetaDataProvider MetaDataProvider
+ {
+ get { return RawLayer.MetaDataProvider; }
+ }
+
+ public IFactBase<SymbolicValue> BasicFacts
+ {
+ get { return this; }
+ }
+
+ public IFullExpressionDecoder<SymbolicValue, LabeledSymbol<APC, SymbolicValue>> ExpressionDecoder
+ {
+ get
+ {
+ if (this.expression_decoder == null)
+ this.expression_decoder =
+ new FullExpressionDecoder<SymbolicValue, LabeledSymbol<APC, SymbolicValue>>(MetaDataProvider, ContextProvider);
+ return this.expression_decoder;
+ }
+ }
+
+ public void RunHeapAndExpressionAnalyses ()
+ {
+ if (this.heap_analysis != null)
+ return;
+
+ this.heap_analysis = new HeapAnalysis.HeapAnalysis (StackLayer);
+ StackLayer.CreateForward (this.heap_analysis) (this.heap_analysis.InitialValue ());
+
+ ValueLayer = CodeLayerFactory.Create (
+ this.heap_analysis.GetDecoder (StackLayer.ILDecoder), StackLayer.MetaDataProvider, StackLayer.ContractProvider,
+ source => source.ToString (), dest => dest.ToString ());
+ var expressionAnalysis = new ExpressionAnalysisFacade<SymbolicValue, IValueContextProvider<SymbolicValue>, IImmutableMap<SymbolicValue, LispList<SymbolicValue>>>
+ (ValueLayer, this.heap_analysis.IsUnreachable);
+ ValueLayer.CreateForward (expressionAnalysis.CreateExpressionAnalysis ()) (expressionAnalysis.InitialValue (SymbolicValue.GetUniqueKey));
+
+ if (DebugOptions.Debug)
+ {
+ Console.WriteLine ("------------Value based CFG-----------------");
+ ValueLayer.ILDecoder.ContextProvider.MethodContext.CFG.Print (Console.Out, ValueLayer.Printer, null, null);
+ }
+
+ IILDecoder
+ <APC, LabeledSymbol<APC, SymbolicValue>, SymbolicValue, IExpressionContextProvider<LabeledSymbol<APC, SymbolicValue>, SymbolicValue>, IImmutableMap<SymbolicValue, LispList<SymbolicValue>>>
+ decoder = expressionAnalysis.GetDecoder (ValueLayer.ILDecoder);
+ this.expr2String = ExpressionPrinterFactory.Printer (decoder.ContextProvider, this);
+ ExpressionLayer = CodeLayerFactory.Create (decoder, ValueLayer.MetaDataProvider, ValueLayer.ContractProvider,
+ this.expr2String, ValueLayer.VariableToString);
+
+ if (DebugOptions.Debug)
+ {
+ Console.WriteLine ("------------Expression based CFG-------------");
+ ExpressionLayer.ILDecoder.ContextProvider.MethodContext.CFG.Print (Console.Out, ExpressionLayer.Printer, null, null);
+ }
+
+ HybridLayer = CodeLayerFactory.Create (ValueLayer.ILDecoder, ValueLayer.MetaDataProvider, ValueLayer.ContractProvider,
+ ValueLayer.ExpressionToString,
+ ValueLayer.VariableToString, ExpressionLayer.Printer);
+ }
+
+ public int KeyConverter (SymbolicValue var)
+ {
+ return SymbolicValue.GetUniqueKey (var);
+ }
+ #endregion
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// IBasicAnalysisDriver.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.ControlFlow.Subroutines;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis.Drivers {
+ interface IBasicAnalysisDriver {
+ SubroutineFacade SubroutineFacade { get; }
+ IMetaDataProvider MetaDataProvider { get; }
+ IContractProvider ContractProvider { get; }
+ }
+}
--- /dev/null
+//
+// IBasicMethodDriver.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.Drivers {
+ interface IBasicMethodDriver {
+ ICodeLayer<Dummy, Dummy, IMethodContextProvider, Dummy> RawLayer { get; }
+ ICodeLayer<int, int, IStackContextProvider, Dummy> StackLayer { get; }
+ ICodeLayer<Dummy, Dummy, IMethodContextProvider, Dummy> ContractFreeRawLayer { get; }
+ ICodeLayer<int, int, IStackContextProvider, Dummy> ContractFreeStackLayer { get; }
+
+ ICFG ContractFreeCFG { get; }
+ IBasicAnalysisDriver AnalysisDriver { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// IMethodAnalysis.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.Analysis.Drivers {
+ interface IMethodAnalysis {
+ string Name { get; }
+
+ IMethodResult<Variable> Analyze<Expression, Variable> (
+ string fullMethodName, IMethodDriver<Expression, Variable> methodDriver)
+ where Variable : IEquatable<Variable>
+ where Expression : IEquatable<Expression>;
+ }
+}
--- /dev/null
+//
+// IMethodAnalysisFixPoint.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.Proving;
+
+namespace Mono.CodeContracts.Static.Analysis.Drivers {
+ interface IMethodAnalysisFixPoint<Variable> {
+ IFactQuery<BoxedExpression, Variable> FactQuery { get; }
+ ProofOutcome ValidateExplicitAssertion (APC pc, Variable value);
+ }
+}
--- /dev/null
+//
+// IMethodDriver.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+using Mono.CodeContracts.Static.Proving;
+
+namespace Mono.CodeContracts.Static.Analysis.Drivers {
+ interface IMethodDriver<Expression, Variable> : IBasicMethodDriver {
+ ICodeLayer<Variable, Variable, IValueContextProvider<Variable>, IImmutableMap<Variable, LispList<Variable>>> ValueLayer { get; }
+ ICodeLayer<Expression, Variable, IExpressionContextProvider<Expression, Variable>, IImmutableMap<Variable, LispList<Variable>>> ExpressionLayer { get; }
+ ICodeLayer<Variable, Variable, IValueContextProvider<Variable>, IImmutableMap<Variable, LispList<Variable>>> HybridLayer { get; }
+
+ IExpressionContextProvider<Expression, Variable> ContextProvider { get; }
+ IMetaDataProvider MetaDataProvider { get; }
+
+ ICFG CFG { get; }
+ Method CurrentMethod { get; }
+ IFactBase<Variable> BasicFacts { get; }
+ IFullExpressionDecoder<Variable, Expression> ExpressionDecoder { get; }
+
+ void RunHeapAndExpressionAnalyses ();
+ int KeyConverter (Variable var);
+ }
+}
--- /dev/null
+//
+// IMethodResult.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using Mono.CodeContracts.Static.Proving;
+
+namespace Mono.CodeContracts.Static.Analysis.Drivers {
+ interface IMethodResult<Variable> : IMethodAnalysisFixPoint<Variable> {
+ IMethodAnalysis MethodAnalysis { get; set; }
+ void ValidateImplicitAssertions (IFactQuery<BoxedExpression, Variable> facts, List<string> proofResults);
+ }
+}
--- /dev/null
+//
+// FullExpressionDecoder.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Lattices;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding {
+ class FullExpressionDecoder<V, E> : IFullExpressionDecoder<V, E>
+ where V : IEquatable<V>
+ where E : IEquatable<E> {
+ public readonly VisitorForIsBinaryExpression<V, E> BinaryExpressionVisitor;
+ public readonly VisitorForIsInst<V, E> IsInstVisitor;
+ public readonly VisitorForIsNull<V, E> IsNullVisitor;
+ public readonly VisitorForSizeOf<V, E> SizeOfVisitor;
+ public readonly VisitorForIsUnaryExpression<V, E> UnaryExpressionVisitor;
+ public readonly VisitorForUnderlyingVariable<V, E> UnderlyingVariableVisitor;
+ public readonly VisitorForValueOf<V, E> ValueOfVisitor;
+ public readonly VisitorForVariable<V, E> VariableVisitor;
+ public readonly VisitorForVariablesIn<V, E> VariablesInVisitor;
+ private readonly IMetaDataProvider meta_data_provider;
+
+ #region Implementation of IFullExpressionDecoder<V,E>
+ public bool IsVariable (E expr, out object variable)
+ {
+ V var;
+ bool res = VisitorForVariable<V, E>.IsVariable (expr, out var, this);
+
+ variable = var;
+ return res;
+ }
+
+ public V UnderlyingVariable (E expr)
+ {
+ return VisitorForUnderlyingVariable<V, E>.IsUnderlyingVariable (expr, this);
+ }
+
+ public bool IsNull (E expr)
+ {
+ return VisitorForIsNull<V, E>.IsNull (expr, this);
+ }
+
+ public bool IsConstant (E expr, out object value, out TypeNode type)
+ {
+ return VisitorForValueOf<V, E>.IsConstant (expr, out value, out type, this);
+ }
+
+ public bool IsSizeof (E expr, out TypeNode type)
+ {
+ return VisitorForSizeOf<V, E>.IsSizeOf (expr, out type, this);
+ }
+
+ public bool IsIsinst (E expr, out E arg, out TypeNode type)
+ {
+ return VisitorForIsInst<V, E>.IsIsInst (expr, out type, out arg, this);
+ }
+
+ public bool IsUnaryExpression (E expr, out UnaryOperator op, out E arg)
+ {
+ return VisitorForIsUnaryExpression<V, E>.IsUnary (expr, out op, out arg, this);
+ }
+
+ public bool IsBinaryExpression (E expr, out BinaryOperator op, out E left, out E right)
+ {
+ return VisitorForIsBinaryExpression<V, E>.IsBinary (expr, out op, out left, out right, this);
+ }
+
+ public void AddFreeVariables (E expr, ISet<E> set)
+ {
+ VisitorForVariablesIn<V, E>.AddFreeVariables (expr, set, this);
+ }
+
+ public LispList<PathElement> GetVariableAccessPath (E expr)
+ {
+ return ContextProvider.ValueContext.AccessPathList (ContextProvider.ExpressionContext.GetPC (expr), ContextProvider.ExpressionContext.Unrefine (expr), true, false);
+ }
+
+ public bool TryGetType (E expr, out TypeNode type)
+ {
+ FlatDomain<TypeNode> aType = ContextProvider.ExpressionContext.GetType (expr);
+ if (aType.IsNormal) {
+ type = aType.Concrete;
+ return true;
+ }
+
+ type = null;
+ return false;
+ }
+
+ public bool TrySizeOfAsConstant (E expr, out int sizeAsConstant)
+ {
+ return TrySizeOf (expr, out sizeAsConstant);
+ }
+
+ private bool TrySizeOf (E expr, out int sizeAsConstant)
+ {
+ TypeNode type;
+ if (VisitorForSizeOf<V, E>.IsSizeOf (expr, out type, this)) {
+ int size = this.meta_data_provider.TypeSize (type);
+ if (size != -1) {
+ sizeAsConstant = size;
+ return true;
+ }
+ }
+
+ sizeAsConstant = -1;
+ return false;
+ }
+ #endregion
+
+ public FullExpressionDecoder (IMetaDataProvider metaDataProvider, IExpressionContextProvider<E, V> contextProvider)
+ {
+ ContextProvider = contextProvider;
+ this.meta_data_provider = metaDataProvider;
+ this.VariableVisitor = new VisitorForVariable<V, E> ();
+ this.UnderlyingVariableVisitor = new VisitorForUnderlyingVariable<V, E> ();
+ this.UnaryExpressionVisitor = new VisitorForIsUnaryExpression<V, E> ();
+ this.BinaryExpressionVisitor = new VisitorForIsBinaryExpression<V, E> ();
+ this.VariablesInVisitor = new VisitorForVariablesIn<V, E> (contextProvider);
+ this.ValueOfVisitor = new VisitorForValueOf<V, E> ();
+ this.SizeOfVisitor = new VisitorForSizeOf<V, E> ();
+ this.IsInstVisitor = new VisitorForIsInst<V, E> ();
+ this.IsNullVisitor = new VisitorForIsNull<V, E> ();
+ }
+
+ public IExpressionContextProvider<E, V> ContextProvider { get; private set; }
+ }
+}
--- /dev/null
+//
+// IFullExpressionDecoder.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding {
+ interface IFullExpressionDecoder<Variable, Expression> {
+ bool IsVariable (Expression expr, out object variable);
+ Variable UnderlyingVariable (Expression expr);
+ bool IsNull (Expression expr);
+ bool IsConstant (Expression expr, out object value, out TypeNode type);
+ bool IsSizeof (Expression expr, out TypeNode type);
+ bool IsIsinst (Expression expr, out Expression arg, out TypeNode type);
+ bool IsUnaryExpression (Expression expr, out UnaryOperator op, out Expression arg);
+ bool IsBinaryExpression (Expression expr, out BinaryOperator op, out Expression left, out Expression right);
+ void AddFreeVariables (Expression expr, ISet<Expression> set);
+ LispList<PathElement> GetVariableAccessPath (Expression expr);
+ bool TryGetType (Expression expr, out TypeNode type);
+ bool TrySizeOfAsConstant (Expression expr, out int sizeAsConstant);
+ }
+}
--- /dev/null
+//
+// QueryVisitor.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding {
+ abstract class QueryVisitor<V, E> : ISymbolicExpressionVisitor<E, E, V, Dummy, bool> where V : IEquatable<V> where E : IEquatable<E> {
+ #region ISymbolicExpressionVisitor<E,E,V,Dummy,bool> Members
+ public virtual bool Binary (E pc, BinaryOperator op, V dest, E operand1, E operand2, Dummy data)
+ {
+ return false;
+ }
+
+ public virtual bool Isinst (E pc, TypeNode type, V dest, E obj, Dummy data)
+ {
+ return false;
+ }
+
+ public virtual bool LoadNull (E pc, V dest, Dummy polarity)
+ {
+ return false;
+ }
+
+ public virtual bool LoadConst (E pc, TypeNode type, object constant, V dest, Dummy data)
+ {
+ return false;
+ }
+
+ public virtual bool Sizeof (E pc, TypeNode type, V dest, Dummy data)
+ {
+ return false;
+ }
+
+ public virtual bool Unary (E pc, UnaryOperator op, bool unsigned, V dest, E source, Dummy data)
+ {
+ return false;
+ }
+
+ public virtual bool SymbolicConstant (E pc, V variable, Dummy data)
+ {
+ return false;
+ }
+ #endregion
+
+ protected static bool Decode<Visitor> (E expr, Visitor visitor, FullExpressionDecoder<V,E> decoder)
+ where Visitor : QueryVisitor<V, E>
+ {
+ return decoder.ContextProvider.ExpressionContext.Decode<Dummy, bool, Visitor> (expr, visitor, Dummy.Value);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// VisitorForIsBinaryExpression.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding {
+ class VisitorForIsBinaryExpression<V, E> : QueryVisitor<V, E>
+ where V : IEquatable<V> where E : IEquatable<E> {
+
+ private BinaryOperator op;
+ private E left;
+ private E right;
+
+ public static bool IsBinary (E expr, out BinaryOperator bop, out E left, out E right, FullExpressionDecoder<V,E> decoder)
+ {
+ VisitorForIsBinaryExpression<V, E> v = decoder.BinaryExpressionVisitor;
+ bool res = Decode (expr, v, decoder);
+
+ bop = v.op;
+ left = v.left;
+ right = v.right;
+ return res;
+ }
+
+ public override bool Binary (E pc, BinaryOperator op, V dest, E operand1, E operand2, Dummy data)
+ {
+ this.op = op;
+ this.left = operand1;
+ this.right = operand2;
+
+ return true;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// VisitorForIsInst.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding {
+ class VisitorForIsInst<V, E> : QueryVisitor<V, E>
+ where V : IEquatable<V>
+ where E : IEquatable<E> {
+
+ private E argument;
+ private TypeNode type;
+
+ public static bool IsIsInst (E expr, out TypeNode type, out E arg, FullExpressionDecoder<V,E> decoder)
+ {
+ VisitorForIsInst<V, E> v = decoder.IsInstVisitor;
+ bool res = Decode (expr, v, decoder);
+
+ arg = v.argument;
+ type = v.type;
+ return res;
+ }
+
+ public override bool Isinst (E pc, TypeNode type, V dest, E obj, Dummy data)
+ {
+ this.type = type;
+ this.argument = obj;
+ return true;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// VisitorForIsNull.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding {
+ class VisitorForIsNull<V, E> : QueryVisitor<V, E>
+ where V : IEquatable<V>
+ where E : IEquatable<E> {
+ public static bool IsNull (E expr, FullExpressionDecoder<V, E> decoder)
+ {
+ VisitorForIsNull<V, E> v = decoder.IsNullVisitor;
+ bool res = Decode (expr, v, decoder);
+
+ return res;
+ }
+
+ public override bool LoadNull (E pc, V dest, Dummy polarity)
+ {
+ return true;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// VisitorForIsUnaryExpression.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding {
+ class VisitorForIsUnaryExpression<V, E> : QueryVisitor<V, E>
+ where V : IEquatable<V>
+ where E : IEquatable<E> {
+ private E Argument;
+ private UnaryOperator Operator;
+
+ public static bool IsUnary (E expr, out UnaryOperator op, out E arg, FullExpressionDecoder<V, E> decoder)
+ {
+ VisitorForIsUnaryExpression<V, E> v = decoder.UnaryExpressionVisitor;
+ bool res = Decode (expr, v, decoder);
+ op = v.Operator;
+ arg = v.Argument;
+ return res;
+ }
+
+ public override bool Unary (E pc, UnaryOperator op, bool unsigned, V dest, E source, Dummy data)
+ {
+ this.Argument = source;
+ this.Operator = op;
+ return true;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// VisitorForSizeOf.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding {
+ class VisitorForSizeOf<V, E> : QueryVisitor<V, E>
+ where V : IEquatable<V>
+ where E : IEquatable<E> {
+ private TypeNode Type;
+
+ public static bool IsSizeOf (E expr, out TypeNode type, FullExpressionDecoder<V, E> decoder)
+ {
+ VisitorForSizeOf<V, E> v = decoder.SizeOfVisitor;
+ bool res = Decode (expr, v, decoder);
+
+ type = v.Type;
+ return res;
+ }
+
+ public override bool Sizeof (E pc, TypeNode type, V dest, Dummy data)
+ {
+ this.Type = type;
+ return true;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// VisitorForUnderlyingVariable.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding {
+ class VisitorForUnderlyingVariable<V,E> : QueryVisitor<V, E>
+ where V : IEquatable<V>
+ where E : IEquatable<E> {
+ private V Variable;
+
+ public static V IsUnderlyingVariable (E expr, FullExpressionDecoder<V, E> decoder)
+ {
+ VisitorForUnderlyingVariable<V, E> visitor = decoder.UnderlyingVariableVisitor;
+ Decode (expr, visitor, decoder);
+ return visitor.Variable;
+ }
+
+ public override bool Binary (E pc, BinaryOperator op, V dest, E operand1, E operand2, Dummy data)
+ {
+ this.Variable = dest;
+ return true;
+ }
+
+ public override bool Isinst (E pc, TypeNode type, V dest, E obj, Dummy data)
+ {
+ this.Variable = dest;
+ return true;
+ }
+
+ public override bool LoadConst (E pc, TypeNode type, object constant, V dest, Dummy data)
+ {
+ this.Variable = dest;
+ return true;
+ }
+
+ public override bool LoadNull (E pc, V dest, Dummy polarity)
+ {
+ this.Variable = dest;
+ return true;
+ }
+
+ public override bool Sizeof (E pc, TypeNode type, V dest, Dummy data)
+ {
+ this.Variable = dest;
+ return true;
+ }
+
+ public override bool SymbolicConstant (E pc, V variable, Dummy data)
+ {
+ this.Variable = variable;
+ return true;
+ }
+
+ public override bool Unary (E pc, UnaryOperator op, bool unsigned, V dest, E source, Dummy data)
+ {
+ this.Variable = dest;
+ return true;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// VisitorForValueOf.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding {
+ class VisitorForValueOf<V, E> : QueryVisitor<V, E>
+ where V : IEquatable<V>
+ where E : IEquatable<E> {
+ private TypeNode Type;
+ private object Value;
+
+ public static bool IsConstant (E expr, out object value, out TypeNode type, FullExpressionDecoder<V, E> decoder)
+ {
+ VisitorForValueOf<V, E> v = decoder.ValueOfVisitor;
+ bool res = Decode (expr, v, decoder);
+
+ value = v.Value;
+ type = v.Type;
+ return res;
+ }
+
+ public override bool LoadNull (E pc, V dest, Dummy polarity)
+ {
+ this.Type = null;
+ this.Value = null;
+ return true;
+ }
+
+ public override bool LoadConst (E pc, TypeNode type, object constant, V dest, Dummy data)
+ {
+ this.Type = type;
+ this.Value = constant;
+ return true;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// VisitorForVariable.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding {
+ class VisitorForVariable<V,E> : QueryVisitor<V, E>
+ where V : IEquatable<V>
+ where E : IEquatable<E> {
+ private V variable;
+
+ public static bool IsVariable (E expr, out V var, FullExpressionDecoder<V, E> decoder)
+ {
+ VisitorForVariable<V, E> visitor = decoder.VariableVisitor;
+ bool res = Decode (expr, visitor, decoder);
+ var = visitor.variable;
+ return res;
+ }
+
+ public override bool SymbolicConstant (E pc, V variable, Dummy data)
+ {
+ this.variable = variable;
+ return true;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// VisitorForVariablesIn.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding {
+ class VisitorForVariablesIn<V, E> : ISymbolicExpressionVisitor<E, E, V, ISet<E>, Dummy>
+ where V : IEquatable<V>
+ where E : IEquatable<E> {
+ private readonly IExpressionContextProvider<E, V> contextProvider;
+
+ public VisitorForVariablesIn (IExpressionContextProvider<E, V> contextProvider)
+ {
+ this.contextProvider = contextProvider;
+ }
+
+ public static void AddFreeVariables (E expr, ISet<E> set, FullExpressionDecoder<V, E> decoder)
+ {
+ decoder.VariablesInVisitor.Recurse (expr, set);
+ }
+
+ private void Recurse (E expr, ISet<E> set)
+ {
+ this.contextProvider.ExpressionContext.Decode<ISet<E>, Dummy, VisitorForVariablesIn<V, E>> (expr, this, set);
+ }
+
+ #region Implementation of IExpressionILVisitor<E,E,V,ISet<E>,Dummy>
+ public Dummy Binary (E pc, BinaryOperator op, V dest, E operand1, E operand2, ISet<E> data)
+ {
+ Recurse (operand1, data);
+ Recurse (operand2, data);
+ return Dummy.Value;
+ }
+
+ public Dummy Isinst (E pc, TypeNode type, V dest, E obj, ISet<E> data)
+ {
+ data.Add (pc);
+ return Dummy.Value;
+ }
+
+ public Dummy LoadNull (E pc, V dest, ISet<E> polarity)
+ {
+ return Dummy.Value;
+ }
+
+ public Dummy LoadConst (E pc, TypeNode type, object constant, V dest, ISet<E> data)
+ {
+ return Dummy.Value;
+ }
+
+ public Dummy Sizeof (E pc, TypeNode type, V dest, ISet<E> data)
+ {
+ data.Add (pc);
+ return Dummy.Value;
+ }
+
+ public Dummy Unary (E pc, UnaryOperator op, bool unsigned, V dest, E source, ISet<E> data)
+ {
+ Recurse (source, data);
+ return Dummy.Value;
+ }
+ #endregion
+
+ #region Implementation of ISymbolicExpressionVisitor<E,E,V,ISet<E>,Dummy>
+ public Dummy SymbolicConstant (E pc, V variable, ISet<E> data)
+ {
+ return Dummy.Value;
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// BinaryExpr.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions {
+ class BinaryExpr<TSymbolicValue> : Expr<TSymbolicValue>
+ where TSymbolicValue : IEquatable<TSymbolicValue> {
+
+ public readonly BinaryOperator Operator;
+ public readonly TSymbolicValue Left;
+ public readonly TSymbolicValue Right;
+
+ public BinaryExpr (TSymbolicValue left, TSymbolicValue right, BinaryOperator op)
+ {
+ this.Left = left;
+ this.Right = right;
+ this.Operator = op;
+ }
+
+ #region Overrides of Expression
+ public override IEnumerable<TSymbolicValue> Variables
+ {
+ get
+ {
+ yield return this.Left;
+ yield return this.Right;
+ }
+ }
+
+ public override Result Decode<Data, Result, Visitor> (APC pc, TSymbolicValue dest, Visitor visitor, Data data)
+ {
+ return visitor.Binary (pc, this.Operator, dest, this.Left, this.Right, data);
+ }
+
+ public override Expr<TSymbolicValue> Substitute (IImmutableMap<TSymbolicValue, LispList<TSymbolicValue>> substitutions)
+ {
+ if (substitutions.ContainsKey (this.Left) && substitutions.ContainsKey (this.Right))
+ return new BinaryExpr<TSymbolicValue> (substitutions [this.Left].Head, substitutions [this.Right].Head, this.Operator);
+
+ return null;
+ }
+
+ public override bool IsContained (IImmutableSet<TSymbolicValue> candidates)
+ {
+ return candidates.Contains (this.Left) || candidates.Contains (this.Right);
+ }
+
+ public override bool Contains (TSymbolicValue symbol)
+ {
+ return this.Left.Equals (symbol) || this.Right.Equals (symbol);
+ }
+
+ public override string ToString ()
+ {
+ return String.Format ("Binary({0} {1} {2})", this.Left, this.Operator, this.Right);
+ }
+
+ public override bool Equals (Expr<TSymbolicValue> other)
+ {
+ var binary = other as BinaryExpr<TSymbolicValue>;
+ if (binary == null || binary.Operator != this.Operator)
+ return false;
+
+ return binary.Left.Equals (this.Left) && binary.Right.Equals (this.Right);
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// ConstExpr.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions {
+ class ConstExpr<TSymbolicValue> : Expr<TSymbolicValue> where TSymbolicValue : IEquatable<TSymbolicValue> {
+ public readonly TypeNode Type;
+ public readonly object value;
+
+ public ConstExpr (TypeNode type, object value)
+ {
+ this.Type = type;
+ this.value = value;
+ }
+
+ #region Overrides of Expression
+ public override IEnumerable<TSymbolicValue> Variables
+ {
+ get { yield break; }
+ }
+
+ public override Result Decode<Data, Result, Visitor> (APC pc, TSymbolicValue dest, Visitor visitor, Data data)
+ {
+ return visitor.LoadConst (pc, this.Type, this.value, dest, data);
+ }
+
+ public override Expr<TSymbolicValue> Substitute (IImmutableMap<TSymbolicValue, LispList<TSymbolicValue>> substitutions)
+ {
+ return this;
+ }
+
+ public override bool IsContained (IImmutableSet<TSymbolicValue> candidates)
+ {
+ return false;
+ }
+
+ public override bool Contains (TSymbolicValue symbol)
+ {
+ return false;
+ }
+
+ public override string ToString ()
+ {
+ return String.Format ("Const({0} {1})", this.Type, this.value);
+ }
+
+ public override bool Equals (Expr<TSymbolicValue> other)
+ {
+ var constant = other as ConstExpr<TSymbolicValue>;
+
+ return constant != null && constant.Type.Equals (this.Type) && constant.value.Equals (this.value);
+ }
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// Expr.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions {
+ abstract class Expr<TSymbolicValue> : IEquatable<Expr<TSymbolicValue>>
+ where TSymbolicValue : IEquatable<TSymbolicValue> {
+
+ public abstract IEnumerable<TSymbolicValue> Variables { get; }
+
+ public abstract bool Equals (Expr<TSymbolicValue> other);
+
+ public abstract Result Decode<Data, Result, Visitor> (APC pc, TSymbolicValue dest, Visitor visitor, Data data)
+ where Visitor : IExpressionILVisitor<APC, TSymbolicValue, TSymbolicValue, Data, Result>;
+
+ public abstract Expr<TSymbolicValue> Substitute (IImmutableMap<TSymbolicValue, LispList<TSymbolicValue>> substitutions);
+
+ /// <summary>
+ /// Specifies that current expression is partially contained in candidates
+ /// </summary>
+ public abstract bool IsContained (IImmutableSet<TSymbolicValue> candidates);
+
+ public abstract bool Contains (TSymbolicValue symbol);
+
+ public abstract override string ToString ();
+ }
+}
--- /dev/null
+//
+// IsInstExpr.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions {
+ class IsInstExpr<TSymbolicValue> : Expr<TSymbolicValue> where TSymbolicValue : IEquatable<TSymbolicValue> {
+ public readonly TSymbolicValue Argument;
+ public readonly TypeNode Type;
+
+ public IsInstExpr (TSymbolicValue argument, TypeNode type)
+ {
+ this.Argument = argument;
+ this.Type = type;
+ }
+
+ #region Overrides of Expression
+ public override IEnumerable<TSymbolicValue> Variables
+ {
+ get { yield return this.Argument; }
+ }
+
+ public override Result Decode<Data, Result, Visitor> (APC pc, TSymbolicValue dest, Visitor visitor, Data data)
+ {
+ return visitor.Isinst (pc, this.Type, dest, this.Argument, data);
+ }
+
+ public override Expr<TSymbolicValue> Substitute (IImmutableMap<TSymbolicValue, LispList<TSymbolicValue>> substitutions)
+ {
+ if (substitutions.ContainsKey (this.Argument))
+ return new IsInstExpr<TSymbolicValue> (substitutions [this.Argument].Head, this.Type);
+ return null;
+ }
+
+ public override bool IsContained (IImmutableSet<TSymbolicValue> candidates)
+ {
+ return candidates.Contains (this.Argument);
+ }
+
+ public override bool Contains (TSymbolicValue symbol)
+ {
+ return this.Argument.Equals (symbol);
+ }
+
+ public override string ToString ()
+ {
+ return String.Format ((string) "IsInst({0} {1})", (object) this.Type, (object) this.Argument);
+ }
+
+ public override bool Equals (Expr<TSymbolicValue> other)
+ {
+ var inst = other as IsInstExpr<TSymbolicValue>;
+
+ return (inst != null && inst.Type.Equals (this.Type) && inst.Argument.Equals (this.Argument));
+ }
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// NullExpr.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions {
+ sealed class NullExpr<TSymbolicValue> : Expr<TSymbolicValue> where TSymbolicValue : IEquatable<TSymbolicValue> {
+ public static readonly Expr<TSymbolicValue> Instance = new NullExpr<TSymbolicValue> ();
+
+ private NullExpr ()
+ {
+ }
+
+ #region Overrides of Expression
+ public override IEnumerable<TSymbolicValue> Variables
+ {
+ get { yield break; }
+ }
+
+ public override Result Decode<Data, Result, Visitor> (APC pc, TSymbolicValue dest, Visitor visitor, Data data)
+ {
+ return visitor.LoadNull (pc, dest, data);
+ }
+
+ public override Expr<TSymbolicValue> Substitute (IImmutableMap<TSymbolicValue, LispList<TSymbolicValue>> substitutions)
+ {
+ return this;
+ }
+
+ public override bool IsContained (IImmutableSet<TSymbolicValue> candidates)
+ {
+ return false;
+ }
+
+ public override bool Contains (TSymbolicValue symbol)
+ {
+ return false;
+ }
+
+ public override string ToString ()
+ {
+ return "Null()";
+ }
+
+ public override bool Equals (Expr<TSymbolicValue> other)
+ {
+ return other == this;
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// SizeoOfExpr.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions {
+ sealed class SizeOfExpr<TSymbolicValue> : Expr<TSymbolicValue> where TSymbolicValue : IEquatable<TSymbolicValue> {
+
+ public readonly TypeNode Type;
+
+ public SizeOfExpr (TypeNode type)
+ {
+ this.Type = type;
+ }
+
+ #region Overrides of Expression
+ public override IEnumerable<TSymbolicValue> Variables
+ {
+ get { return Enumerable.Empty<TSymbolicValue> (); }
+ }
+
+ public override Result Decode<Data, Result, Visitor> (APC pc, TSymbolicValue dest, Visitor visitor, Data data)
+ {
+ return visitor.Sizeof (pc, this.Type, dest, data);
+ }
+
+ public override Expr<TSymbolicValue> Substitute (IImmutableMap<TSymbolicValue, LispList<TSymbolicValue>> substitutions)
+ {
+ return this;
+ }
+
+ public override bool IsContained (IImmutableSet<TSymbolicValue> candidates)
+ {
+ return false;
+ }
+
+ public override bool Contains (TSymbolicValue symbol)
+ {
+ return false;
+ }
+
+ public override string ToString ()
+ {
+ return String.Format ("Sizeof({0})", this.Type);
+ }
+
+ public override bool Equals (Expr<TSymbolicValue> other)
+ {
+ var @sizeof = other as SizeOfExpr<TSymbolicValue>;
+
+ return (@sizeof != null && @sizeof.Type.Equals (this.Type));
+ }
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// UnaryExpr.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions {
+ class UnaryExpr<TSymbolicValue> : Expr<TSymbolicValue> where TSymbolicValue : IEquatable<TSymbolicValue> {
+ public readonly UnaryOperator Operator;
+ public readonly TSymbolicValue Source;
+ public readonly bool Unsigned;
+
+ public UnaryExpr (TSymbolicValue source, UnaryOperator op, bool unsigned)
+ {
+ this.Source = source;
+ this.Operator = op;
+ this.Unsigned = unsigned;
+ }
+
+ #region Overrides of Expression
+ public override IEnumerable<TSymbolicValue> Variables
+ {
+ get { yield return this.Source; }
+ }
+
+ public override Result Decode<Data, Result, Visitor> (APC pc, TSymbolicValue dest, Visitor visitor, Data data)
+ {
+ return visitor.Unary (pc, this.Operator, this.Unsigned, dest, this.Source, data);
+ }
+
+ public override Expr<TSymbolicValue> Substitute (IImmutableMap<TSymbolicValue, LispList<TSymbolicValue>> substitutions)
+ {
+ if (substitutions.ContainsKey (this.Source))
+ return new UnaryExpr<TSymbolicValue> (substitutions [this.Source].Head, this.Operator, this.Unsigned);
+
+ return null;
+ }
+
+ public override bool IsContained (IImmutableSet<TSymbolicValue> candidates)
+ {
+ return candidates.Contains (this.Source);
+ }
+
+ public override bool Contains (TSymbolicValue symbol)
+ {
+ return symbol.Equals (this.Source);
+ }
+
+ public override string ToString ()
+ {
+ return String.Format ("Unary({0} {1})", this.Operator, this.Source);
+ }
+
+ public override bool Equals (Expr<TSymbolicValue> other)
+ {
+ var unary = other as UnaryExpr<TSymbolicValue>;
+ if (unary == null || unary.Operator != this.Operator || unary.Unsigned != this.Unsigned)
+ return false;
+
+ return unary.Source.Equals (this.Source);
+ }
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// AnalysisDecoder.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.Lattices;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis {
+ class AnalysisDecoder<TSymValue> : ILVisitorBase<APC, TSymValue, TSymValue, ExprDomain<TSymValue>, ExprDomain<TSymValue>>
+ where TSymValue : IEquatable<TSymValue> {
+ public override ExprDomain<TSymValue> DefaultVisit (APC pc, ExprDomain<TSymValue> data)
+ {
+ return data;
+ }
+
+ public override ExprDomain<TSymValue> Assume (APC pc, EdgeTag tag, TSymValue condition, ExprDomain<TSymValue> data)
+ {
+ FlatDomain<Expr<TSymValue>> aExpression = data [condition];
+
+ if (aExpression.IsNormal) {
+ bool truth = tag != EdgeTag.False;
+ data = aExpression.Concrete.Decode<ExprDomain<TSymValue>, ExprDomain<TSymValue>, AssumeDecoder<TSymValue>>
+ (pc, condition, new AssumeDecoder<TSymValue> (truth), data);
+ }
+
+ return data;
+ }
+
+ public override ExprDomain<TSymValue> Assert (APC pc, EdgeTag tag, TSymValue condition, ExprDomain<TSymValue> data)
+ {
+ FlatDomain<Expr<TSymValue>> expression = data [condition];
+ if (expression.IsNormal) {
+ data = expression.Concrete.Decode<ExprDomain<TSymValue>, ExprDomain<TSymValue>, AssumeDecoder<TSymValue>>
+ (pc, condition, new AssumeDecoder<TSymValue> (true), data);
+ }
+
+ return data;
+ }
+
+ public override ExprDomain<TSymValue> Binary (APC pc, BinaryOperator op, TSymValue dest, TSymValue operand1, TSymValue operand2, ExprDomain<TSymValue> data)
+ {
+ return data.Add (dest, new BinaryExpr<TSymValue> (operand1, operand2, op));
+ }
+
+ public override ExprDomain<TSymValue> Isinst (APC pc, TypeNode type, TSymValue dest, TSymValue obj, ExprDomain<TSymValue> data)
+ {
+ return data.Add (dest, new IsInstExpr<TSymValue> (obj, type));
+ }
+
+ public override ExprDomain<TSymValue> LoadConst (APC pc, TypeNode type, object constant, TSymValue dest, ExprDomain<TSymValue> data)
+ {
+ return data.Add (dest, new ConstExpr<TSymValue> (type, constant));
+ }
+
+ public override ExprDomain<TSymValue> LoadNull (APC pc, TSymValue dest, ExprDomain<TSymValue> polarity)
+ {
+ return polarity.Add (dest, NullExpr<TSymValue>.Instance);
+ }
+
+ public override ExprDomain<TSymValue> Sizeof (APC pc, TypeNode type, TSymValue dest, ExprDomain<TSymValue> data)
+ {
+ return data.Add (dest, new SizeOfExpr<TSymValue> (type));
+ }
+
+ public override ExprDomain<TSymValue> Unary (APC pc, UnaryOperator op, bool unsigned, TSymValue dest, TSymValue source, ExprDomain<TSymValue> data)
+ {
+ return data.Add (dest, new UnaryExpr<TSymValue> (source, op, unsigned));
+ }
+ }
+}
--- /dev/null
+//
+// AssumeDecoder.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.Lattices;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis {
+ struct AssumeDecoder<SymbolicValue> : IExpressionILVisitor<APC, SymbolicValue, SymbolicValue, ExprDomain<SymbolicValue>, ExprDomain<SymbolicValue>>
+ where SymbolicValue : IEquatable<SymbolicValue> {
+ private readonly bool truth;
+
+ public AssumeDecoder (bool truth)
+ {
+ this.truth = truth;
+ }
+
+ #region IExpressionILVisitor<APC,SymbolicValue,SymbolicValue,ExprDomain<SymbolicValue>,ExprDomain<SymbolicValue>> Members
+ public ExprDomain<SymbolicValue> Binary (APC pc, BinaryOperator op, SymbolicValue dest, SymbolicValue s1, SymbolicValue s2, ExprDomain<SymbolicValue> data)
+ {
+ if (this.truth && op.IsEqualityOperator ()) {
+ if (!data.HasRefinement (s1)) {
+ FlatDomain<Expr<SymbolicValue>> expression2 = data [s2];
+ if (expression2.IsNormal && !data.IsReachableFrom (s2, s1))
+ return data.Add (s1, expression2.Concrete);
+ } else if (!data.HasRefinement (s2)) {
+ FlatDomain<Expr<SymbolicValue>> expression1 = data [s1];
+ if (expression1.IsNormal && !data.IsReachableFrom (s1, s2))
+ return data.Add (s2, expression1.Concrete);
+ }
+ }
+ if (!this.truth && op == BinaryOperator.Cne_Un) {
+ if (!data.HasRefinement (s1)) {
+ FlatDomain<Expr<SymbolicValue>> expression2 = data [s2];
+ if (expression2.IsNormal && !data.IsReachableFrom (s2, s1))
+ return data.Add (s1, expression2.Concrete);
+ } else if (!data.HasRefinement (s2)) {
+ FlatDomain<Expr<SymbolicValue>> expression1 = data [s1];
+ if (expression1.IsNormal && !data.IsReachableFrom (s1, s2))
+ return data.Add (s2, expression1.Concrete);
+ }
+ }
+ return data;
+ }
+
+ public ExprDomain<SymbolicValue> Isinst (APC pc, TypeNode type, SymbolicValue dest, SymbolicValue obj, ExprDomain<SymbolicValue> data)
+ {
+ return data;
+ }
+
+ public ExprDomain<SymbolicValue> LoadNull (APC pc, SymbolicValue dest, ExprDomain<SymbolicValue> polarity)
+ {
+ return polarity;
+ }
+
+ public ExprDomain<SymbolicValue> LoadConst (APC pc, TypeNode type, object constant, SymbolicValue dest, ExprDomain<SymbolicValue> data)
+ {
+ return data;
+ }
+
+ public ExprDomain<SymbolicValue> Sizeof (APC pc, TypeNode type, SymbolicValue dest, ExprDomain<SymbolicValue> data)
+ {
+ return data;
+ }
+
+ public ExprDomain<SymbolicValue> Unary (APC pc, UnaryOperator op, bool unsigned, SymbolicValue dest, SymbolicValue source, ExprDomain<SymbolicValue> data)
+ {
+ return data;
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// ExprDomain.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+using Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Lattices;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis {
+ class ExprDomain<TSymValue> : IGraph<TSymValue, Dummy>
+ where TSymValue : IEquatable<TSymValue> {
+ private readonly EnvironmentDomain<TSymValue, FlatDomain<Expr<TSymValue>>> expressions;
+
+ private ExprDomain (EnvironmentDomain<TSymValue, FlatDomain<Expr<TSymValue>>> expressions)
+ {
+ this.expressions = expressions;
+ }
+
+ #region Implementation of IGraph<SymbolicValue,Dummy>
+ public IEnumerable<TSymValue> Keys
+ {
+ get { return this.expressions.Keys; }
+ }
+
+ public bool IsBottom
+ {
+ get { return this.expressions.IsBottom; }
+ }
+
+ IEnumerable<TSymValue> IGraph<TSymValue, Dummy>.Nodes
+ {
+ get { return this.expressions.Keys; }
+ }
+
+ public IEnumerable<Pair<Dummy, TSymValue>> Successors(TSymValue node)
+ {
+ FlatDomain<Expr<TSymValue>> expr = this.expressions[node];
+ if (expr.IsNormal) foreach (TSymValue sv in expr.Concrete.Variables) yield return new Pair<Dummy, TSymValue> (Dummy.Value, sv);
+ }
+ #endregion
+
+ public FlatDomain<Expr<TSymValue>> this[TSymValue sv]
+ {
+ get { return this.expressions[sv]; }
+ }
+
+ public ExprDomain<TSymValue> Join(ExprDomain<TSymValue> that, bool widening, out bool weaker)
+ {
+ return new ExprDomain<TSymValue> (this.expressions.Join (that.expressions, widening, out weaker));
+ }
+
+ public static ExprDomain<TSymValue> TopValue(Func<TSymValue, int> keyConverter )
+ {
+ return new ExprDomain<TSymValue> (EnvironmentDomain<TSymValue, FlatDomain<Expr<TSymValue>>>.TopValue (keyConverter));
+ }
+
+ public ExprDomain<TSymValue> Add (TSymValue sv, Expr<TSymValue> expr)
+ {
+ return new ExprDomain<TSymValue> (this.expressions.Add (sv, expr));
+ }
+
+ public ExprDomain<TSymValue> Remove(TSymValue sv)
+ {
+ return new ExprDomain<TSymValue> (this.expressions.Remove (sv));
+ }
+
+ public ExprDomain<TSymValue> Empty()
+ {
+ return new ExprDomain<TSymValue> (this.expressions.Empty ());
+ }
+
+ public bool HasRefinement(TSymValue sv)
+ {
+ return this.expressions.Contains (sv);
+ }
+
+ public bool IsReachableFrom(TSymValue source, TSymValue target)
+ {
+ bool reachable = false;
+ DepthFirst.Visit (this, source, sv => {
+ if (sv.Equals (target))
+ reachable = true;
+ return true;
+ }, null);
+ return reachable;
+ }
+
+ public void Dump(TextWriter tw)
+ {
+ this.expressions.Dump (tw);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// ExpressionAnalysisFacade.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.Analysis.HeapAnalysis;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataFlowAnalysis;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis {
+ class ExpressionAnalysisFacade<TSymValue, TContext, TEdgeData>
+ where TSymValue : IEquatable<TSymValue>
+ where TContext : IValueContextProvider<TSymValue>
+ where TEdgeData : IImmutableMap<TSymValue, LispList<TSymValue>> {
+
+ public readonly Predicate<APC> IsUnreachable;
+
+ public readonly ICodeLayer<TSymValue, TSymValue, TContext, TEdgeData> ValueLayer;
+ private IFixPointInfo<APC, ExprDomain<TSymValue>> fix_point_info;
+
+ public ExpressionAnalysisFacade (ICodeLayer<TSymValue, TSymValue, TContext, TEdgeData> valueLayer,
+ Predicate<APC> isUnreachable)
+ {
+ this.ValueLayer = valueLayer;
+ this.IsUnreachable = isUnreachable;
+ }
+
+ public bool PreStateLookup (APC label, out ExprDomain<TSymValue> ifFound)
+ {
+ return this.fix_point_info.PreStateLookup (label, out ifFound);
+ }
+
+ public bool PostStateLookup (APC label, out ExprDomain<TSymValue> ifFound)
+ {
+ return this.fix_point_info.PostStateLookup (label, out ifFound);
+ }
+
+ public void SaveFixPointInfo (IFixPointInfo<APC, ExprDomain<TSymValue>> fixPointInfo)
+ {
+ this.fix_point_info = fixPointInfo;
+ }
+
+ public ExprDomain<TSymValue> InitialValue (Func<TSymValue, int> keyConverter)
+ {
+ return ExprDomain<TSymValue>.TopValue (keyConverter);
+ }
+
+ public IAnalysis<APC, ExprDomain<TSymValue>, IILVisitor<APC, TSymValue, TSymValue, ExprDomain<TSymValue>, ExprDomain<TSymValue>>, TEdgeData>
+ CreateExpressionAnalysis ()
+ {
+ return new ValueAnalysis<TSymValue, TContext, TEdgeData> (this);
+ }
+
+ public IILDecoder<APC, LabeledSymbol<APC, TSymValue>, TSymValue, IExpressionContextProvider<LabeledSymbol<APC, TSymValue>, TSymValue>, TEdgeData>
+ GetDecoder (
+ IILDecoder<APC, TSymValue, TSymValue, IValueContextProvider<TSymValue>, TEdgeData> ilDecoder)
+ {
+ return new ExpressionDecoder<TSymValue, TContext, TEdgeData> (ilDecoder, this);
+ }
+ }
+}
--- /dev/null
+//
+// ExpressionDecoder.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions;
+using Mono.CodeContracts.Static.Analysis.HeapAnalysis;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Lattices;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis {
+ class ExpressionDecoder<TSymbolicValue, TContext, TEdgeData> :
+ IILDecoder<APC, LabeledSymbol<APC, TSymbolicValue>, TSymbolicValue, IExpressionContextProvider<LabeledSymbol<APC, TSymbolicValue>, TSymbolicValue>, TEdgeData>,
+ IExpressionContextProvider<LabeledSymbol<APC, TSymbolicValue>, TSymbolicValue>,
+ IExpressionContext<LabeledSymbol<APC, TSymbolicValue>, TSymbolicValue>
+ where TSymbolicValue : IEquatable<TSymbolicValue>
+ where TContext : IValueContextProvider<TSymbolicValue>
+ where TEdgeData : IImmutableMap<TSymbolicValue, LispList<TSymbolicValue>> {
+ private readonly IILDecoder<APC, TSymbolicValue, TSymbolicValue, IValueContextProvider<TSymbolicValue>, TEdgeData> value_decoder;
+ private readonly ExpressionAnalysisFacade<TSymbolicValue, TContext, TEdgeData> parent;
+ private readonly IValueContextProvider<TSymbolicValue> underlying;
+
+ public ExpressionDecoder (IILDecoder<APC, TSymbolicValue, TSymbolicValue, IValueContextProvider<TSymbolicValue>, TEdgeData> valueDecoder,
+ ExpressionAnalysisFacade<TSymbolicValue, TContext, TEdgeData> parent)
+ {
+ this.value_decoder = valueDecoder;
+ this.parent = parent;
+ this.underlying = valueDecoder.ContextProvider;
+ }
+
+ #region IExpressionContext<LabeledSymbol<APC,SymbolicValue>,SymbolicValue> Members
+ public LabeledSymbol<APC, TSymbolicValue> Refine (APC pc, TSymbolicValue variable)
+ {
+ return new LabeledSymbol<APC, TSymbolicValue> (pc, variable);
+ }
+
+ public TSymbolicValue Unrefine (LabeledSymbol<APC, TSymbolicValue> expression)
+ {
+ return expression.Symbol;
+ }
+
+ public Result Decode<Data, Result, Visitor> (LabeledSymbol<APC, TSymbolicValue> expr, Visitor visitor, Data data)
+ where Visitor : ISymbolicExpressionVisitor<LabeledSymbol<APC, TSymbolicValue>, LabeledSymbol<APC, TSymbolicValue>, TSymbolicValue, Data, Result>
+ {
+ ExprDomain<TSymbolicValue> ifFound;
+ if (!this.parent.PreStateLookup (expr.ReadAt, out ifFound) || ifFound.IsBottom)
+ return visitor.SymbolicConstant (expr, expr.Symbol, data);
+
+ FlatDomain<Expr<TSymbolicValue>> aExpr = ifFound [expr.Symbol];
+ if (aExpr.IsNormal) {
+ return aExpr.Concrete.Decode<Data, Result, ExpressionDecoderAdapter<TSymbolicValue, Data, Result, Visitor>>
+ (expr.ReadAt, expr.Symbol,
+ new ExpressionDecoderAdapter<TSymbolicValue, Data, Result, Visitor> (visitor), data);
+ }
+
+ TypeNode type;
+ object constant;
+ if (this.parent.ValueLayer.ILDecoder.ContextProvider.ValueContext.IsConstant (expr.ReadAt, expr.Symbol, out type, out constant))
+ return visitor.LoadConst (expr, type, constant, expr.Symbol, data);
+
+ return visitor.SymbolicConstant (expr, expr.Symbol, data);
+ }
+
+ public FlatDomain<TypeNode> GetType (LabeledSymbol<APC, TSymbolicValue> expr)
+ {
+ return this.underlying.ValueContext.GetType (expr.ReadAt, expr.Symbol);
+ }
+
+ public APC GetPC (LabeledSymbol<APC, TSymbolicValue> pc)
+ {
+ return pc.ReadAt;
+ }
+
+ public LabeledSymbol<APC, TSymbolicValue> For (TSymbolicValue variable)
+ {
+ return new LabeledSymbol<APC, TSymbolicValue> (MethodContext.CFG.Entry, variable);
+ }
+
+ public bool IsZero (LabeledSymbol<APC, TSymbolicValue> expression)
+ {
+ return ValueContext.IsZero (expression.ReadAt, expression.Symbol);
+ }
+ #endregion
+
+ #region IILDecoder<APC,LabeledSymbol<APC,SymbolicValue>,SymbolicValue,IExpressionContextProvider<LabeledSymbol<APC,SymbolicValue>,SymbolicValue>,EdgeData> Members
+ public IExpressionContextProvider<LabeledSymbol<APC, TSymbolicValue>, TSymbolicValue> ContextProvider
+ {
+ get { return this; }
+ }
+
+ public Result ForwardDecode<Data, Result, Visitor> (APC pc, Visitor visitor, Data state)
+ where Visitor : IILVisitor<APC, LabeledSymbol<APC, TSymbolicValue>, TSymbolicValue, Data, Result>
+ {
+ return this.value_decoder.ForwardDecode<Data, Result, ILDecoderAdapter<TSymbolicValue, Data, Result, Visitor>>
+ (pc, new ILDecoderAdapter<TSymbolicValue, Data, Result, Visitor> (visitor), state);
+ }
+
+ public bool IsUnreachable (APC pc)
+ {
+ return this.parent.IsUnreachable (pc);
+ }
+
+ public TEdgeData EdgeData (APC from, APC to)
+ {
+ return this.parent.ValueLayer.ILDecoder.EdgeData (from, to);
+ }
+ #endregion
+
+ #region Implementation of IMethodContextProvider<Field,Method>
+ public IMethodContext MethodContext
+ {
+ get { return this.underlying.MethodContext; }
+ }
+ #endregion
+
+ #region Implementation of IStackContextProvider<Field,Method>
+ public IStackContext StackContext
+ {
+ get { return this.underlying.StackContext; }
+ }
+ #endregion
+
+ #region Implementation of IValueContextProvider<Local,Parameter,Method,Field,Type,SymbolicValue>
+ public IValueContext<TSymbolicValue> ValueContext
+ {
+ get { return this.underlying.ValueContext; }
+ }
+ #endregion
+
+ #region Implementation of IExpressionContextProvider<Local,Parameter,Method,Field,Type,ExternalExpression<APC,SymbolicValue>,SymbolicValue>
+ public IExpressionContext<LabeledSymbol<APC, TSymbolicValue>, TSymbolicValue> ExpressionContext
+ {
+ get { return this; }
+ }
+ #endregion
+ }
+}
--- /dev/null
+using System;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.Analysis.HeapAnalysis;
+using Mono.CodeContracts.Static.ControlFlow;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis {
+ struct ExpressionDecoderAdapter<SymbolicValue, Data, Result, Visitor>
+ : IExpressionILVisitor<APC, SymbolicValue, SymbolicValue, Data, Result>
+ where SymbolicValue : IEquatable<SymbolicValue>
+ where Visitor : ISymbolicExpressionVisitor<LabeledSymbol<APC, SymbolicValue>, LabeledSymbol<APC, SymbolicValue>, SymbolicValue, Data, Result> {
+
+ private readonly Visitor visitor;
+
+ public ExpressionDecoderAdapter (Visitor visitor)
+ {
+ this.visitor = visitor;
+ }
+
+ #region Implementation of IExpressionILVisitor<APC,Type,SymbolicValue,SymbolicValue,Data,Result>
+ public Result Binary (APC pc, BinaryOperator op, SymbolicValue dest, SymbolicValue operand1, SymbolicValue operand2, Data data)
+ {
+ return this.visitor.Binary (Unrefine (pc, dest), op, dest, Unrefine (pc, operand1), Unrefine (pc, operand2), data);
+ }
+
+ public Result Isinst (APC pc, TypeNode type, SymbolicValue dest, SymbolicValue obj, Data data)
+ {
+ return this.visitor.Isinst (Unrefine (pc, dest), type, dest, Unrefine (pc, obj), data);
+ }
+
+ public Result LoadNull (APC pc, SymbolicValue dest, Data polarity)
+ {
+ return this.visitor.LoadNull (Unrefine (pc, dest), dest, polarity);
+ }
+
+ public Result LoadConst (APC pc, TypeNode type, object constant, SymbolicValue dest, Data data)
+ {
+ return this.visitor.LoadConst (Unrefine (pc, dest), type, constant, dest, data);
+ }
+
+ public Result Sizeof (APC pc, TypeNode type, SymbolicValue dest, Data data)
+ {
+ return this.visitor.Sizeof (Unrefine (pc, dest), type, dest, data);
+ }
+
+ public Result Unary (APC pc, UnaryOperator op, bool unsigned, SymbolicValue dest, SymbolicValue source, Data data)
+ {
+ return this.visitor.Unary (Unrefine (pc, dest), op, unsigned, dest, Unrefine (pc, source), data);
+ }
+
+ private LabeledSymbol<APC, SymbolicValue> Unrefine (APC pc, SymbolicValue dest)
+ {
+ return new LabeledSymbol<APC, SymbolicValue> (pc, dest);
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// ExpressionPrinterFactory.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Text;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.Analysis.Drivers;
+using Mono.CodeContracts.Static.Analysis.HeapAnalysis;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis {
+ static class ExpressionPrinterFactory {
+ public static Func<LabeledSymbol<APC, SymbolicValue>, string> Printer<SymbolicValue>
+ (IExpressionContextProvider<LabeledSymbol<APC, SymbolicValue>, SymbolicValue> contextProvider,
+ IMethodDriver<LabeledSymbol<APC, SymbolicValue>, SymbolicValue> methodDriver)
+ where SymbolicValue : IEquatable<SymbolicValue>
+ {
+ return new PrinterImpl<SymbolicValue> (contextProvider, methodDriver).PrintAt;
+ }
+
+ #region Nested type: PrinterImpl
+ private class PrinterImpl<SymbolicValue> :
+ ISymbolicExpressionVisitor<LabeledSymbol<APC, SymbolicValue>, LabeledSymbol<APC, SymbolicValue>, SymbolicValue, StringBuilder, Dummy>
+ where SymbolicValue : IEquatable<SymbolicValue> {
+ private readonly IExpressionContextProvider<LabeledSymbol<APC, SymbolicValue>, SymbolicValue> context_provider;
+ private readonly IMethodDriver<LabeledSymbol<APC, SymbolicValue>, SymbolicValue> method_driver;
+
+ public PrinterImpl (IExpressionContextProvider<LabeledSymbol<APC, SymbolicValue>, SymbolicValue> contextProvider,
+ IMethodDriver<LabeledSymbol<APC, SymbolicValue>, SymbolicValue> methodDriver)
+ {
+ this.context_provider = contextProvider;
+ this.method_driver = methodDriver;
+ }
+
+ public string PrintAt (LabeledSymbol<APC, SymbolicValue> expr)
+ {
+ var sb = new StringBuilder ();
+ Recurse (sb, expr);
+ return sb.ToString ();
+ }
+
+ private void Recurse (StringBuilder sb, LabeledSymbol<APC, SymbolicValue> expr)
+ {
+ if (expr.Symbol.Equals (default(SymbolicValue)))
+ sb.Append ("<!null!>");
+ else
+ this.context_provider.ExpressionContext.Decode<StringBuilder, Dummy, PrinterImpl<SymbolicValue>> (expr, this, sb);
+ }
+
+ #region Implementation of IExpressionILVisitor<ExternalExpression<APC,SymbolicValue>,ExternalExpression<APC,SymbolicValue>,SymbolicValue,StringBuilder,Dummy>
+ public Dummy Binary (LabeledSymbol<APC, SymbolicValue> pc, BinaryOperator op, SymbolicValue dest, LabeledSymbol<APC, SymbolicValue> operand1, LabeledSymbol<APC, SymbolicValue> operand2,
+ StringBuilder data)
+ {
+ data.Append ('(');
+ Recurse (data, operand1);
+ data.AppendFormat (" {0} ", op);
+ Recurse (data, operand2);
+ data.Append (')');
+ return Dummy.Value;
+ }
+
+ public Dummy Isinst (LabeledSymbol<APC, SymbolicValue> pc, TypeNode type, SymbolicValue dest, LabeledSymbol<APC, SymbolicValue> obj, StringBuilder data)
+ {
+ data.AppendFormat ("IsInst({0}) ", this.method_driver.MetaDataProvider.FullName (type));
+ Recurse (data, obj);
+ return Dummy.Value;
+ }
+
+ public Dummy LoadNull (LabeledSymbol<APC, SymbolicValue> pc, SymbolicValue dest, StringBuilder polarity)
+ {
+ polarity.Append ("NULL");
+ return Dummy.Value;
+ }
+
+ public Dummy LoadConst (LabeledSymbol<APC, SymbolicValue> pc, TypeNode type, object constant, SymbolicValue dest, StringBuilder data)
+ {
+ data.Append (constant.ToString ());
+ return Dummy.Value;
+ }
+
+ public Dummy Sizeof (LabeledSymbol<APC, SymbolicValue> pc, TypeNode type, SymbolicValue dest, StringBuilder data)
+ {
+ data.AppendFormat ("sizeof({0})", this.method_driver.MetaDataProvider.FullName (type));
+ return Dummy.Value;
+ }
+
+ public Dummy Unary (LabeledSymbol<APC, SymbolicValue> pc, UnaryOperator op, bool unsigned, SymbolicValue dest, LabeledSymbol<APC, SymbolicValue> source, StringBuilder data)
+ {
+ data.AppendFormat ("{0} ", op.ToString ());
+ Recurse (data, source);
+ return Dummy.Value;
+ }
+ #endregion
+
+ #region Implementation of ISymbolicExpressionVisitor<ExternalExpression<APC,SymbolicValue>,ExternalExpression<APC,SymbolicValue>,SymbolicValue,StringBuilder,Dummy>
+ public Dummy SymbolicConstant (LabeledSymbol<APC, SymbolicValue> pc, SymbolicValue variable, StringBuilder data)
+ {
+ data.Append (variable.ToString ());
+ return Dummy.Value;
+ }
+ #endregion
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// ILDecoderAdapter.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.Analysis.HeapAnalysis;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis {
+ /// <summary>
+ /// This class performs translation from (source) SymbolicValue to LabeledSymbol
+ /// </summary>
+ struct ILDecoderAdapter<SymbolicValue, Data, Result, Visitor>
+ : IILVisitor<APC, SymbolicValue, SymbolicValue, Data, Result>
+ where SymbolicValue : IEquatable<SymbolicValue>
+ where Visitor : IILVisitor<APC, LabeledSymbol<APC, SymbolicValue>, SymbolicValue, Data, Result> {
+ private readonly Visitor visitor;
+
+ public ILDecoderAdapter (Visitor visitor)
+ {
+ this.visitor = visitor;
+ }
+
+ #region IILVisitor<APC,SymbolicValue,SymbolicValue,Data,Result> Members
+ public Result Binary (APC pc, BinaryOperator op, SymbolicValue dest, SymbolicValue operand1, SymbolicValue operand2, Data data)
+ {
+ return this.visitor.Binary (pc, op, dest, Convert (pc, operand1), Convert (pc, operand2), data);
+ }
+
+ public Result Isinst (APC pc, TypeNode type, SymbolicValue dest, SymbolicValue obj, Data data)
+ {
+ return this.visitor.Isinst (pc, type, dest, Convert (pc, obj), data);
+ }
+
+ public Result LoadNull (APC pc, SymbolicValue dest, Data polarity)
+ {
+ return this.visitor.LoadNull (pc, dest, polarity);
+ }
+
+ public Result LoadConst (APC pc, TypeNode type, object constant, SymbolicValue dest, Data data)
+ {
+ return this.visitor.LoadConst (pc, type, constant, dest, data);
+ }
+
+ public Result Sizeof (APC pc, TypeNode type, SymbolicValue dest, Data data)
+ {
+ return this.visitor.Sizeof (pc, type, dest, data);
+ }
+
+ public Result Unary (APC pc, UnaryOperator op, bool unsigned, SymbolicValue dest, SymbolicValue source, Data data)
+ {
+ return this.visitor.Unary (pc, op, unsigned, dest, Convert (pc, source), data);
+ }
+
+ public Result Entry (APC pc, Method method, Data data)
+ {
+ return this.visitor.Entry (pc, method, data);
+ }
+
+ public Result Assume (APC pc, EdgeTag tag, SymbolicValue condition, Data data)
+ {
+ return this.visitor.Assume (pc, tag, Convert (pc, condition), data);
+ }
+
+ public Result Assert (APC pc, EdgeTag tag, SymbolicValue condition, Data data)
+ {
+ return this.visitor.Assert (pc, tag, Convert (pc, condition), data);
+ }
+
+ public Result BeginOld (APC pc, APC matchingEnd, Data data)
+ {
+ return this.visitor.BeginOld (pc, matchingEnd, data);
+ }
+
+ public Result EndOld (APC pc, APC matchingBegin, TypeNode type, SymbolicValue dest, SymbolicValue source, Data data)
+ {
+ return this.visitor.EndOld (pc, matchingBegin, type, dest, Convert (pc, source), data);
+ }
+
+ public Result LoadStack (APC pc, int offset, SymbolicValue dest, SymbolicValue source, bool isOld, Data data)
+ {
+ return this.visitor.LoadStack (pc, offset, dest, Convert (pc, source), isOld, data);
+ }
+
+ public Result LoadStackAddress (APC pc, int offset, SymbolicValue dest, SymbolicValue source, TypeNode type, bool isOld, Data data)
+ {
+ return this.visitor.LoadStackAddress (pc, offset, dest, Convert (pc, source), type, isOld, data);
+ }
+
+ public Result LoadResult (APC pc, TypeNode type, SymbolicValue dest, SymbolicValue source, Data data)
+ {
+ return this.visitor.LoadResult (pc, type, dest, Convert (pc, source), data);
+ }
+
+ public Result Arglist (APC pc, SymbolicValue dest, Data data)
+ {
+ return this.visitor.Arglist (pc, dest, data);
+ }
+
+ public Result Branch (APC pc, APC target, bool leavesExceptionBlock, Data data)
+ {
+ throw new Exception ("Should not get branches at this level of abstraction.");
+ }
+
+ public Result BranchCond (APC pc, APC target, BranchOperator bop, SymbolicValue value1, SymbolicValue value2, Data data)
+ {
+ throw new Exception ("Should not get branches at this level of abstraction.");
+ }
+
+ public Result BranchTrue (APC pc, APC target, SymbolicValue cond, Data data)
+ {
+ throw new Exception ("Should not get branches at this level of abstraction.");
+ }
+
+ public Result BranchFalse (APC pc, APC target, SymbolicValue cond, Data data)
+ {
+ throw new Exception ("Should not get branches at this level of abstraction.");
+ }
+
+ public Result Break (APC pc, Data data)
+ {
+ return this.visitor.Break (pc, data);
+ }
+
+ public Result Call<TypeList, ArgList> (APC pc, Method method, bool virt, TypeList extraVarargs, SymbolicValue dest, ArgList args, Data data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<SymbolicValue>
+ {
+ return this.visitor.Call (pc, method, virt, extraVarargs, dest, Convert (pc, args), data);
+ }
+
+ public Result Calli<TypeList, ArgList> (APC pc, TypeNode returnType, TypeList argTypes, bool instance, SymbolicValue dest, SymbolicValue functionPointer, ArgList args, Data data)
+ where TypeList : IIndexable<TypeNode> where ArgList : IIndexable<SymbolicValue>
+ {
+ return this.visitor.Calli (pc, returnType, argTypes, instance, dest, Convert (pc, functionPointer), Convert (pc, args), data);
+ }
+
+ public Result CheckFinite (APC pc, SymbolicValue dest, SymbolicValue source, Data data)
+ {
+ return this.visitor.CheckFinite (pc, dest, Convert (pc, source), data);
+ }
+
+ public Result CopyBlock (APC pc, SymbolicValue destAddress, SymbolicValue srcAddress, SymbolicValue len, Data data)
+ {
+ return this.visitor.CopyBlock (pc, Convert (pc, destAddress), Convert (pc, srcAddress), Convert (pc, len), data);
+ }
+
+ public Result EndFilter (APC pc, SymbolicValue decision, Data data)
+ {
+ return this.visitor.EndFilter (pc, Convert (pc, decision), data);
+ }
+
+ public Result EndFinally (APC pc, Data data)
+ {
+ return this.visitor.EndFinally (pc, data);
+ }
+
+ public Result Jmp (APC pc, Method method, Data data)
+ {
+ return this.visitor.Jmp (pc, method, data);
+ }
+
+ public Result LoadArg (APC pc, Parameter argument, bool isOld, SymbolicValue dest, Data data)
+ {
+ return this.visitor.LoadArg (pc, argument, isOld, dest, data);
+ }
+
+ public Result LoadArgAddress (APC pc, Parameter argument, bool isOld, SymbolicValue dest, Data data)
+ {
+ return this.visitor.LoadArgAddress (pc, argument, isOld, dest, data);
+ }
+
+ public Result LoadLocal (APC pc, Local local, SymbolicValue dest, Data data)
+ {
+ return this.visitor.LoadLocal (pc, local, dest, data);
+ }
+
+ public Result LoadLocalAddress (APC pc, Local local, SymbolicValue dest, Data data)
+ {
+ return this.visitor.LoadLocalAddress (pc, local, dest, data);
+ }
+
+ public Result Nop (APC pc, Data data)
+ {
+ return this.visitor.Nop (pc, data);
+ }
+
+ public Result Pop (APC pc, SymbolicValue source, Data data)
+ {
+ return this.visitor.Pop (pc, Convert (pc, source), data);
+ }
+
+ public Result Return (APC pc, SymbolicValue source, Data data)
+ {
+ return this.visitor.Return (pc, Convert (pc, source), data);
+ }
+
+ public Result StoreArg (APC pc, Parameter argument, SymbolicValue source, Data data)
+ {
+ return this.visitor.StoreArg (pc, argument, Convert (pc, source), data);
+ }
+
+ public Result StoreLocal (APC pc, Local local, SymbolicValue source, Data data)
+ {
+ return this.visitor.StoreLocal (pc, local, Convert (pc, source), data);
+ }
+
+ public Result Switch (APC pc, TypeNode type, IEnumerable<Pair<object, APC>> cases, SymbolicValue value, Data data)
+ {
+ throw new Exception ("Should not get branches at this level of abstraction.");
+ }
+
+ public Result Box (APC pc, TypeNode type, SymbolicValue dest, SymbolicValue source, Data data)
+ {
+ return this.visitor.Box (pc, type, dest, Convert (pc, source), data);
+ }
+
+ public Result ConstrainedCallvirt<TypeList, ArgList> (APC pc, Method method, TypeNode constraint, TypeList extraVarargs, SymbolicValue dest, ArgList args, Data data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<SymbolicValue>
+ {
+ return this.visitor.ConstrainedCallvirt (pc, method, constraint, extraVarargs, dest, Convert (pc, args), data);
+ }
+
+ public Result CastClass (APC pc, TypeNode type, SymbolicValue dest, SymbolicValue obj, Data data)
+ {
+ return this.visitor.CastClass (pc, type, dest, Convert (pc, obj), data);
+ }
+
+ public Result CopyObj (APC pc, TypeNode type, SymbolicValue destPtr, SymbolicValue sourcePtr, Data data)
+ {
+ return this.visitor.CopyObj (pc, type, Convert (pc, destPtr), Convert (pc, sourcePtr), data);
+ }
+
+ public Result Initobj (APC pc, TypeNode type, SymbolicValue ptr, Data data)
+ {
+ return this.visitor.Initobj (pc, type, Convert (pc, ptr), data);
+ }
+
+ public Result LoadElement (APC pc, TypeNode type, SymbolicValue dest, SymbolicValue array, SymbolicValue index, Data data)
+ {
+ return this.visitor.LoadElement (pc, type, dest, Convert (pc, array), Convert (pc, index), data);
+ }
+
+ public Result LoadField (APC pc, Field field, SymbolicValue dest, SymbolicValue obj, Data data)
+ {
+ return this.visitor.LoadField (pc, field, dest, Convert (pc, obj), data);
+ }
+
+ public Result LoadFieldAddress (APC pc, Field field, SymbolicValue dest, SymbolicValue obj, Data data)
+ {
+ return this.visitor.LoadFieldAddress (pc, field, dest, Convert (pc, obj), data);
+ }
+
+ public Result LoadLength (APC pc, SymbolicValue dest, SymbolicValue array, Data data)
+ {
+ return this.visitor.LoadLength (pc, dest, Convert (pc, array), data);
+ }
+
+ public Result LoadStaticField (APC pc, Field field, SymbolicValue dest, Data data)
+ {
+ return this.visitor.LoadStaticField (pc, field, dest, data);
+ }
+
+ public Result LoadStaticFieldAddress (APC pc, Field field, SymbolicValue dest, Data data)
+ {
+ return this.visitor.LoadStaticFieldAddress (pc, field, dest, data);
+ }
+
+ public Result LoadTypeToken (APC pc, TypeNode type, SymbolicValue dest, Data data)
+ {
+ return this.visitor.LoadTypeToken (pc, type, dest, data);
+ }
+
+ public Result LoadFieldToken (APC pc, Field type, SymbolicValue dest, Data data)
+ {
+ return this.visitor.LoadFieldToken (pc, type, dest, data);
+ }
+
+ public Result LoadMethodToken (APC pc, Method type, SymbolicValue dest, Data data)
+ {
+ return this.visitor.LoadMethodToken (pc, type, dest, data);
+ }
+
+ public Result NewArray<ArgList> (APC pc, TypeNode type, SymbolicValue dest, ArgList lengths, Data data) where ArgList : IIndexable<SymbolicValue>
+ {
+ return this.visitor.NewArray (pc, type, dest, Convert (pc, lengths), data);
+ }
+
+ public Result NewObj<ArgList> (APC pc, Method ctor, SymbolicValue dest, ArgList args, Data data) where ArgList : IIndexable<SymbolicValue>
+ {
+ return this.visitor.NewObj (pc, ctor, dest, Convert (pc, args), data);
+ }
+
+ public Result MkRefAny (APC pc, TypeNode type, SymbolicValue dest, SymbolicValue obj, Data data)
+ {
+ return this.visitor.MkRefAny (pc, type, dest, Convert (pc, obj), data);
+ }
+
+ public Result RefAnyType (APC pc, SymbolicValue dest, SymbolicValue source, Data data)
+ {
+ return this.visitor.RefAnyType (pc, dest, Convert (pc, source), data);
+ }
+
+ public Result RefAnyVal (APC pc, TypeNode type, SymbolicValue dest, SymbolicValue source, Data data)
+ {
+ return this.visitor.RefAnyVal (pc, type, dest, Convert (pc, source), data);
+ }
+
+ public Result Rethrow (APC pc, Data data)
+ {
+ return this.visitor.Rethrow (pc, data);
+ }
+
+ public Result StoreElement (APC pc, TypeNode type, SymbolicValue array, SymbolicValue index, SymbolicValue value, Data data)
+ {
+ return this.visitor.StoreElement (pc, type, Convert (pc, array), Convert (pc, index), Convert (pc, value), data);
+ }
+
+ public Result StoreField (APC pc, Field field, SymbolicValue obj, SymbolicValue value, Data data)
+ {
+ return this.visitor.StoreField (pc, field, Convert (pc, obj), Convert (pc, value), data);
+ }
+
+ public Result StoreStaticField (APC pc, Field field, SymbolicValue value, Data data)
+ {
+ return this.visitor.StoreStaticField (pc, field, Convert (pc, value), data);
+ }
+
+ public Result Throw (APC pc, SymbolicValue exception, Data data)
+ {
+ return this.visitor.Throw (pc, Convert (pc, exception), data);
+ }
+
+ public Result Unbox (APC pc, TypeNode type, SymbolicValue dest, SymbolicValue obj, Data data)
+ {
+ return this.visitor.Unbox (pc, type, dest, Convert (pc, obj), data);
+ }
+
+ public Result UnboxAny (APC pc, TypeNode type, SymbolicValue dest, SymbolicValue obj, Data data)
+ {
+ return this.visitor.UnboxAny (pc, type, dest, Convert (pc, obj), data);
+ }
+ #endregion
+
+ private static LabeledSymbol<APC, SymbolicValue> Convert (APC pc, SymbolicValue value)
+ {
+ return new LabeledSymbol<APC, SymbolicValue> (pc, value);
+ }
+
+ private static ArgumentWrapper<ArgList> Convert<ArgList> (APC pc, ArgList value)
+ where ArgList : IIndexable<SymbolicValue>
+ {
+ return new ArgumentWrapper<ArgList> (value, pc);
+ }
+
+ #region Nested type: ArgumentWrapper
+ private struct ArgumentWrapper<ArgList> : IIndexable<LabeledSymbol<APC, SymbolicValue>>
+ where ArgList : IIndexable<SymbolicValue> {
+ private readonly APC readAt;
+ private readonly ArgList underlying;
+
+ public ArgumentWrapper (ArgList underlying, APC readAt)
+ {
+ this.underlying = underlying;
+ this.readAt = readAt;
+ }
+
+ #region Implementation of IIndexable<ExternalExpression<APC,SymbolicValue>>
+ public int Count
+ {
+ get { return this.underlying.Count; }
+ }
+
+ public LabeledSymbol<APC, SymbolicValue> this [int index]
+ {
+ get { return new LabeledSymbol<APC, SymbolicValue> (this.readAt, this.underlying [index]); }
+ }
+ #endregion
+ }
+ #endregion
+ }
+}
--- /dev/null
+using System;
+using System.IO;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataFlowAnalysis;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Lattices;
+
+namespace Mono.CodeContracts.Static.Analysis.ExpressionAnalysis {
+ class ValueAnalysis<SymbolicValue, Context, EdgeData> : IAnalysis<APC, ExprDomain<SymbolicValue>,
+ IILVisitor<APC, SymbolicValue, SymbolicValue, ExprDomain<SymbolicValue>, ExprDomain<SymbolicValue>>, EdgeData>
+ where SymbolicValue : IEquatable<SymbolicValue>
+ where Context : IValueContextProvider<SymbolicValue>
+ where EdgeData : IImmutableMap<SymbolicValue, LispList<SymbolicValue>> {
+ private readonly ExpressionAnalysisFacade<SymbolicValue, Context, EdgeData> parent;
+
+ public ValueAnalysis (ExpressionAnalysisFacade<SymbolicValue, Context, EdgeData> parent)
+ {
+ this.parent = parent;
+ }
+
+ #region Implementation of IAnalysis<APC,ExpressionAnalysis<Local,Parameter,Method,Field,Property,Event,Type,Attribute,Assembly,SymbolicValue,contextProvider,EdgeData>.Domain,IILVisitor<APC,Local,Parameter,Method,Field,Type,SymbolicValue,SymbolicValue,ExpressionAnalysis<Local,Parameter,Method,Field,Property,Event,Type,Attribute,Assembly,SymbolicValue,contextProvider,EdgeData>.Domain,ExpressionAnalysis<Local,Parameter,Method,Field,Property,Event,Type,Attribute,Assembly,SymbolicValue,contextProvider,EdgeData>.Domain>,EdgeData>
+ public ExprDomain<SymbolicValue> EdgeConversion (APC @from, APC to, bool isJoinPoint, EdgeData sourceTargetMap, ExprDomain<SymbolicValue> originalState)
+ {
+ if (sourceTargetMap == null)
+ return originalState;
+
+ if (DebugOptions.Debug)
+ {
+ Console.WriteLine ("====Expression analysis Parallel assign====");
+ DumpMap (sourceTargetMap);
+ DumpExpressions ("original expressions", originalState);
+ }
+
+ ExprDomain<SymbolicValue> result = originalState.Empty ();
+ ExprDomain<SymbolicValue> domain = originalState.Empty ();
+
+ foreach (SymbolicValue sv in originalState.Keys) {
+ Expr<SymbolicValue> expression = originalState [sv].Concrete.Substitute (sourceTargetMap);
+ if (expression != null)
+ domain = domain.Add (sv, expression);
+ }
+
+ foreach (SymbolicValue sv in sourceTargetMap.Keys) {
+ FlatDomain<Expr<SymbolicValue>> expressionDomain = domain [sv];
+ if (expressionDomain.IsNormal) {
+ Expr<SymbolicValue> expression = expressionDomain.Concrete;
+ foreach (SymbolicValue sub in sourceTargetMap [sv].AsEnumerable ())
+ result = result.Add (sub, expression);
+ }
+ }
+
+ if (DebugOptions.Debug)
+ {
+ DumpExpressions ("new expressions", result);
+ }
+ return result;
+ }
+
+ public IILVisitor<APC, SymbolicValue, SymbolicValue, ExprDomain<SymbolicValue>, ExprDomain<SymbolicValue>> GetVisitor ()
+ {
+ return new AnalysisDecoder<SymbolicValue> ();
+ }
+
+ public ExprDomain<SymbolicValue> Join (Pair<APC, APC> edge, ExprDomain<SymbolicValue> newstate, ExprDomain<SymbolicValue> prevstate, out bool weaker, bool widen)
+ {
+ return prevstate.Join (newstate, widen, out weaker);
+ }
+
+ public ExprDomain<SymbolicValue> ImmutableVersion (ExprDomain<SymbolicValue> arg)
+ {
+ return arg;
+ }
+
+ public ExprDomain<SymbolicValue> MutableVersion (ExprDomain<SymbolicValue> arg)
+ {
+ return arg;
+ }
+
+ public bool IsBottom (APC pc, ExprDomain<SymbolicValue> state)
+ {
+ return state.IsBottom;
+ }
+
+ public Predicate<APC> SaveFixPointInfo (IFixPointInfo<APC, ExprDomain<SymbolicValue>> fixPointInfo)
+ {
+ this.parent.SaveFixPointInfo (fixPointInfo);
+ return pc => true;
+ }
+
+ public void Dump (Pair<ExprDomain<SymbolicValue>, TextWriter> pair)
+ {
+ pair.Key.Dump (pair.Value);
+ }
+
+ private void DumpMap (IImmutableMap<SymbolicValue, LispList<SymbolicValue>> sourceTargetMap)
+ {
+ Console.WriteLine ("Source-Target assignment");
+ foreach (SymbolicValue key in sourceTargetMap.Keys) {
+ foreach (SymbolicValue value in sourceTargetMap [key].AsEnumerable ())
+ Console.Write ("{0} ", value);
+ Console.WriteLine (" := {0}", key);
+ }
+ }
+
+ private void DumpExpressions (string header, ExprDomain<SymbolicValue> state)
+ {
+ Console.WriteLine ("--- {0} ---", header);
+ foreach (SymbolicValue index in state.Keys) {
+ FlatDomain<Expr<SymbolicValue>> domain = state [index];
+ if (domain.IsNormal)
+ Console.WriteLine ("{0} -> {1}", index, domain.Concrete);
+ else if (domain.IsTop)
+ Console.WriteLine ("{0} -> (Top)", index);
+ else if (domain.IsBottom)
+ Console.WriteLine ("{0} -> (Bot)", index);
+ }
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// AccessPathFilter.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths {
+ class AccessPathFilter<TMember> {
+ public static AccessPathFilter<TMember> NoFilter = new AccessPathFilter<TMember> ();
+ private readonly Flags flags;
+ private readonly TMember member;
+ private readonly MemberFilter member_filter;
+
+ private AccessPathFilter ()
+ {
+ this.flags = Flags.AllowLocals;
+ this.member_filter = MemberFilter.NoFilter;
+ }
+
+ private AccessPathFilter (TMember member, MemberFilter memberFilter)
+ {
+ this.member_filter = memberFilter;
+ this.member = member;
+ }
+
+ public bool AllowLocal
+ {
+ get { return (this.flags & Flags.AllowLocals) == Flags.AllowLocals; }
+ }
+
+ public bool HasVisibilityMember
+ {
+ get { return this.member_filter != MemberFilter.NoFilter; }
+ }
+
+ public TMember VisibilityMember
+ {
+ get { return this.member; }
+ }
+
+ public static AccessPathFilter<TMember> FromPrecondition (TMember member)
+ {
+ return new AccessPathFilter<TMember> (member, MemberFilter.FromPrecondition);
+ }
+
+ public static AccessPathFilter<TMember> FromPostcondition (TMember member)
+ {
+ return new AccessPathFilter<TMember> (member, MemberFilter.FromPostcondition);
+ }
+
+ public static AccessPathFilter<TMember> IsVisibleFrom (TMember member)
+ {
+ return new AccessPathFilter<TMember> (member, MemberFilter.FromMethodBody);
+ }
+
+ public bool FilterOutPathElement<P> (P element)
+ where P : IVisibilityCheck<TMember>
+ {
+ switch (this.member_filter) {
+ case MemberFilter.FromPrecondition:
+ return !element.IsAsVisibleAs (this.member);
+ case MemberFilter.FromPostcondition:
+ return !element.IfRootIsParameter || !element.IsVisibleFrom (this.member);
+ case MemberFilter.FromMethodBody:
+ return !element.IsVisibleFrom (this.member);
+ default:
+ return false;
+ }
+ }
+
+ #region Nested type: Flags
+ [Flags]
+ private enum Flags {
+ AllowLocals = 1,
+ RequireParameter = 2
+ }
+ #endregion
+
+ #region Nested type: MemberFilter
+ private enum MemberFilter {
+ NoFilter = 0,
+ FromPrecondition,
+ FromPostcondition,
+ FromMethodBody
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// IVisibilityCheck.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths {
+ interface IVisibilityCheck<TMember> {
+ bool IfRootIsParameter { get; }
+ bool IsAsVisibleAs (TMember member);
+ bool IsVisibleFrom (TMember member);
+ }
+}
--- /dev/null
+//
+// MethodCallPathElement.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths {
+ class MethodCallPathElement : PathElement<Method> {
+ private readonly bool is_boolean_typed;
+ private readonly bool is_compressed;
+ private readonly bool is_getter;
+
+ public MethodCallPathElement (Method method,
+ bool isGetter, bool isBooleanTyped,
+ bool isStatic, string description,
+ SymFunction func, bool isCompressed)
+ : base (method, description, func)
+ {
+ this.is_boolean_typed = isBooleanTyped;
+ this.is_getter = isGetter;
+ this.is_compressed = isCompressed;
+ this.isStatic = isStatic;
+ }
+
+ public override bool IsAddressOf
+ {
+ get { return !this.is_compressed; }
+ }
+
+ public override bool IsMethodCall
+ {
+ get { return true; }
+ }
+
+ public override bool IsGetter
+ {
+ get { return this.is_getter; }
+ }
+
+ public override bool IsBooleanTyped
+ {
+ get { return this.is_boolean_typed; }
+ }
+ }
+}
--- /dev/null
+//
+// ParameterPathElement.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths {
+ class ParameterPathElement : PathElement<Parameter> {
+ public ParameterPathElement (Parameter p, string description,
+ SymFunction c, IMetaDataProvider metaDataProvider)
+ : base (p, description, c)
+ {
+ TypeNode type = metaDataProvider.ParameterType (p);
+ ResultType = metaDataProvider.ManagedPointer (type);
+
+ if (metaDataProvider.IsManagedPointer (type))
+ this.isManagedPointer = true;
+ }
+
+ public override bool IsParameter
+ {
+ get { return true; }
+ }
+
+ public override bool IsAddressOf
+ {
+ get { return false; }
+ }
+
+ public override Result Decode<Data, Result, Visitor, Label> (Label label, Visitor visitor, Data data)
+ {
+ Parameter p = this.Element;
+ return visitor.LoadArg (label, p, false, Dummy.Value, data);
+ }
+
+ public override bool IsCallerVisible ()
+ {
+ return true;
+ }
+ }
+}
--- /dev/null
+//
+// PathElement.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths
+{
+ abstract class PathElement
+ {
+ public virtual bool IsBooleanTyped { get { return false; } }
+ public virtual bool IsDeref { get { return false; } }
+
+ public virtual bool IsMethodCall { get { return false; } }
+ public virtual bool IsGetter { get { return false; } }
+ public virtual bool IsStatic { get { return false; } }
+ public virtual bool IsUnmanagedPointer { get { return false; } }
+ public virtual bool IsManagedPointer { get { return false; } }
+ public virtual bool IsParameter { get { return false; } }
+ public virtual bool IsParameterRef { get { return false; } }
+ public virtual string CastTo { get { return ""; } }
+ public abstract bool IsAddressOf { get; }
+
+ public virtual bool TryField(out Field f)
+ {
+ f = default(Field);
+ return false;
+ }
+
+ public abstract bool TryGetResultType(out TypeNode type);
+
+ public abstract TResult Decode<TData, TResult, TVisitor, TLabel>(TLabel label, TVisitor visitor, TData data)
+ where TVisitor : IAggregateVisitor<TLabel, TData, TResult>;
+
+ public abstract override string ToString();
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// PathElementBase.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths {
+ abstract class PathElementBase : PathElement {
+ public readonly SymFunction Func;
+
+ protected PathElementBase (SymFunction c)
+ {
+ this.Func = c;
+ }
+
+ public abstract bool TrySetType (TypeNode expectedType, IMetaDataProvider metaDataProvider, out TypeNode type);
+ }
+}
--- /dev/null
+//
+// PathElement`1.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths {
+ class PathElement<T> : PathElementBase {
+ public readonly string Description;
+ public readonly T Element;
+ protected string castTo;
+ protected bool isManagedPointer;
+ protected bool isStatic;
+ protected bool isUnmanagedPointer;
+
+ #region Overrides of PathElement
+ public override bool IsStatic
+ {
+ get { return this.isStatic; }
+ }
+
+ public override bool IsUnmanagedPointer
+ {
+ get { return this.isUnmanagedPointer; }
+ }
+
+ public override bool IsManagedPointer
+ {
+ get { return this.isManagedPointer; }
+ }
+
+ public override bool IsParameterRef
+ {
+ get { return typeof (T) == typeof (Parameter); }
+ }
+
+ public override string CastTo
+ {
+ get { return this.castTo; }
+ }
+
+ public override bool IsAddressOf
+ {
+ get { return true; }
+ }
+
+ public override bool TryField (out Field f)
+ {
+ if (typeof (T) == typeof (Field)) {
+ f = (Field) (object) this.Element;
+ return true;
+ }
+
+ f = default(Field);
+ return false;
+ }
+
+ public override bool TryGetResultType (out TypeNode type)
+ {
+ type = ResultType;
+ return true;
+ }
+
+ public override TResult Decode<TData, TResult, TVisitor, TLabel> (TLabel label, TVisitor visitor, TData data)
+ {
+ if (typeof (T) == typeof (Field)) {
+ var field = (Field) (object) this.Element;
+ if (this.isStatic)
+ return visitor.LoadStaticFieldAddress (label, field, Dummy.Value, data);
+ return visitor.LoadFieldAddress (label, field, Dummy.Value, Dummy.Value, data);
+ }
+
+ if (typeof (T) == typeof (Local)) {
+ var local = (Local) (object) this.Element;
+ return visitor.LoadLocalAddress (label, local, Dummy.Value, data);
+ }
+
+ if (typeof (T) == typeof (Method)) {
+ var method = (Method) (object) this.Element;
+ bool isVirtualMethod = this.Func.IsVirtualMethod;
+ return visitor.Call (label, method, isVirtualMethod, Indexable<TypeNode>.Empty, Dummy.Value, Indexable<Dummy>.Empty, data);
+ }
+
+ if (typeof (T) == typeof (Parameter)) {
+ var parameter = (Parameter) (object) this.Element;
+ return visitor.LoadArgAddress (label, parameter, false, Dummy.Value, data);
+ }
+
+ throw new InvalidOperationException ("Field, Local, Method or Parameter expected");
+ }
+
+ public override string ToString ()
+ {
+ return this.Description;
+ }
+ #endregion
+
+ public PathElement (T element, string description, SymFunction c) : base (c)
+ {
+ this.Element = element;
+ this.Description = description;
+ this.isStatic = false;
+ this.isUnmanagedPointer = false;
+ this.isManagedPointer = false;
+ }
+
+ public TypeNode ResultType { get; protected set; }
+
+ public virtual bool IsCallerVisible ()
+ {
+ return (typeof (T) == typeof (Parameter));
+ }
+
+ #region Overrides of PathElementBase
+ public override bool TrySetType (TypeNode expectedType, IMetaDataProvider metaDataProvider, out TypeNode resultType)
+ {
+ if (typeof (T) == typeof (Parameter)) {
+ var p = (Parameter) (object) this.Element;
+ TypeNode type = metaDataProvider.ParameterType (p);
+ this.isManagedPointer = metaDataProvider.IsManagedPointer (type);
+ ResultType = resultType = metaDataProvider.ManagedPointer (type);
+ return true;
+ }
+
+ if (typeof (T) == typeof (Field)) {
+ var f = (Field) (object) this.Element;
+ TypeNode type = metaDataProvider.FieldType (f);
+ this.isStatic = metaDataProvider.IsStatic (f);
+ this.isManagedPointer = metaDataProvider.IsManagedPointer (type);
+ ResultType = resultType = metaDataProvider.ManagedPointer (type);
+
+ TypeNode declaringType = metaDataProvider.DeclaringType (f);
+ if (metaDataProvider.IsManagedPointer (expectedType))
+ expectedType = metaDataProvider.ElementType (expectedType);
+ expectedType = metaDataProvider.Unspecialized (expectedType);
+
+ if (!metaDataProvider.IsStatic (f) && declaringType.Equals (expectedType) &&
+ (!metaDataProvider.DerivesFrom (expectedType, declaringType) ||
+ !metaDataProvider.IsProtected (f) && !metaDataProvider.IsPublic (f)))
+ this.castTo = metaDataProvider.FullName (declaringType);
+
+ return true;
+ }
+
+ if (typeof (T) == typeof (Local)) {
+ var local = (Local) (object) this.Element;
+ TypeNode type = metaDataProvider.LocalType (local);
+ this.isManagedPointer = metaDataProvider.IsManagedPointer (type);
+ ResultType = resultType = metaDataProvider.ManagedPointer (type);
+
+ return true;
+ }
+
+ if (typeof (T) == typeof (Method)) {
+ var method = (Method) (object) this.Element;
+ ResultType = resultType = !IsAddressOf
+ ? metaDataProvider.ReturnType (method)
+ : metaDataProvider.ManagedPointer (metaDataProvider.ReturnType (method));
+
+ if (metaDataProvider.IsManagedPointer (expectedType))
+ expectedType = metaDataProvider.ElementType (expectedType);
+ expectedType = metaDataProvider.Unspecialized (expectedType);
+
+ TypeNode declaringType = metaDataProvider.DeclaringType (method);
+ if (!metaDataProvider.IsStatic (method) && declaringType.Equals (expectedType) &&
+ (!metaDataProvider.DerivesFrom (expectedType, declaringType)
+ || !metaDataProvider.IsProtected (method) && !metaDataProvider.IsPublic (method)))
+ this.castTo = metaDataProvider.FullName (declaringType);
+
+ return true;
+ }
+
+ ResultType = resultType = default(TypeNode);
+ return false;
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// PathExtensions.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths {
+ static class PathExtensions {
+ public static HashSet<Field> FieldsIn (this LispList<PathElement> path)
+ {
+ var result = new HashSet<Field> ();
+ if (path != null) {
+ foreach (PathElement element in path.AsEnumerable ()) {
+ Field f;
+ if (element.TryField (out f))
+ result.Add (f);
+ }
+ }
+ return result;
+ }
+
+ public static string ToCodeString (this PathElement[] path)
+ {
+ return PathToString (path);
+ }
+
+ public static string ToCodeString (this LispList<PathElement> path)
+ {
+ return PathToString (path.AsEnumerable ());
+ }
+
+ private static string PathToString (IEnumerable<PathElement> path)
+ {
+ bool first = true;
+ bool isReference = false;
+ bool isUnmanagedPointer = false;
+ var sb = new StringBuilder ();
+
+ List<PathElement> pathL = path.ToList ();
+
+ for (int i = 0; i < pathL.Count; i++) {
+ PathElement element = pathL [i];
+ if (element.IsMethodCall && !element.IsGetter && element.IsStatic) {
+ string oldString = sb.ToString ();
+ sb = new StringBuilder ();
+ sb.AppendFormat ("{0}({1})", element, oldString);
+ } else {
+ if (!string.IsNullOrEmpty (element.CastTo)) {
+ string oldString = sb.ToString ();
+ sb = new StringBuilder ();
+ sb.AppendFormat ("(({0}{1}){2})", element.CastTo, isUnmanagedPointer ? "*" : "", oldString);
+ }
+
+ sb.Append (isUnmanagedPointer ? "->" : ".");
+ sb.Append (element.ToString ());
+ if (element.IsMethodCall && !element.IsGetter)
+ sb.Append ("()");
+ }
+ if (first)
+ first = false;
+
+ int num = (element.IsAddressOf ? 1 : 0) + (element.IsUnmanagedPointer ? 1 : 0) + (element.IsManagedPointer ? 1 : 0);
+ isUnmanagedPointer = element.IsUnmanagedPointer;
+
+ for (int j = 0; j < num; j++) {
+ if (j + 1 < pathL.Count) {
+ if (pathL [j + 1].IsDeref)
+ ++j;
+ } else
+ isReference = true;
+ }
+ }
+
+ if (isReference)
+ return isUnmanagedPointer ? sb.ToString () : "&" + sb;
+ if (isUnmanagedPointer)
+ return "*" + sb;
+
+ return sb.ToString ();
+ }
+ }
+}
--- /dev/null
+//
+// SpecialPathElement.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths {
+ class SpecialPathElement : PathElement<SpecialPathElementKind> {
+ private object type;
+
+ public SpecialPathElement (SpecialPathElementKind element, SymFunction c) : base (element, element.ToString (), c)
+ {
+ this.castTo = "";
+ }
+
+ public override bool IsAddressOf
+ {
+ get { return false; }
+ }
+
+ public override bool IsDeref
+ {
+ get { return this.Element == SpecialPathElementKind.Deref; }
+ }
+
+
+ public override bool TryGetResultType (out TypeNode resultType)
+ {
+ if (this.type is TypeNode) {
+ resultType = (TypeNode) this.type;
+ return true;
+ }
+
+ resultType = default (TypeNode);
+ return false;
+ }
+
+ public override bool TrySetType (TypeNode expectedType, IMetaDataProvider metaDataProvider, out TypeNode resultType)
+ {
+ switch (this.Element) {
+ case SpecialPathElementKind.Length:
+ this.castTo = metaDataProvider.IsArray (expectedType)
+ || metaDataProvider.System_String.Equals (expectedType)
+ ? ""
+ : "System.Array";
+ resultType = metaDataProvider.System_Int32;
+ return true;
+ case SpecialPathElementKind.Deref:
+ if (metaDataProvider.IsManagedPointer (expectedType)) {
+ TypeNode type = metaDataProvider.ElementType (expectedType);
+ this.type = type;
+ resultType = type;
+ return true;
+ }
+ resultType = default(TypeNode);
+ return false;
+
+ default:
+ resultType = default(TypeNode);
+ return false;
+ }
+ }
+
+ public override Result Decode<Data, Result, Visitor, Label> (Label label, Visitor visitor, Data data)
+ {
+ switch (this.Element) {
+ case SpecialPathElementKind.Length:
+ return visitor.LoadLength (label, Dummy.Value, Dummy.Value, data);
+ case SpecialPathElementKind.Deref:
+ throw new NotImplementedException ();
+ default:
+ throw new InvalidOperationException ();
+ }
+ }
+ }
+}
--- /dev/null
+//
+// SpecialPathElementKind.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths {
+ enum SpecialPathElementKind {
+ Length,
+ Deref
+ }
+}
--- /dev/null
+//
+// AbstractDomainUpdate.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph {
+ class AbstractDomainUpdate<TFunc, TAbstractDomain> : Update<TFunc, TAbstractDomain>
+ where TFunc : IEquatable<TFunc>, IConstantInfo
+ where TAbstractDomain : IAbstractDomainForEGraph<TAbstractDomain>, IEquatable<TAbstractDomain> {
+ private readonly SymValue sv;
+
+ public AbstractDomainUpdate (SymValue sv)
+ {
+ this.sv = sv;
+ }
+
+ #region Overrides of Update
+ public override void Replay (MergeInfo<TFunc, TAbstractDomain> merge)
+ {
+ if (!merge.IsCommon (this.sv))
+ return;
+
+ TAbstractDomain val1 = merge.Graph1 [this.sv];
+ TAbstractDomain val2 = merge.Graph2 [this.sv];
+ bool weaker;
+ TAbstractDomain join = val1.Join (val2, merge.Widen, out weaker);
+
+ TAbstractDomain wasInResult = merge.Result [this.sv];
+ if (weaker) {
+ if (DebugOptions.Debug)
+ {
+ Console.WriteLine ("----SymGraph changed during AbstractDomainUpdate of {3} " +
+ "due to weaker abstractValue join (val1 = {0}, val2 = {1}, wasInResult = {2}",
+ val1, val2, wasInResult, this.sv);
+ }
+ merge.Changed = true;
+ }
+
+ if (join.Equals (wasInResult))
+ return;
+
+ merge.Result [this.sv] = join;
+ }
+
+ public override void ReplayElimination (MergeInfo<TFunc, TAbstractDomain> merge)
+ {
+ if (!merge.IsCommon (this.sv))
+ return;
+
+ TAbstractDomain val1 = merge.Graph1 [this.sv];
+
+ if (val1.IsTop)
+ merge.Result [this.sv] = val1;
+ else {
+ TAbstractDomain val2 = merge.Graph2 [this.sv];
+ if (val2.IsTop)
+ merge.Result [this.sv] = val2;
+ }
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// EdgeUpdate.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph {
+ class EdgeUpdate<TFunc, TAbstractDomain> : Update<TFunc, TAbstractDomain>
+ where TFunc : IEquatable<TFunc>, IConstantInfo
+ where TAbstractDomain : IAbstractDomainForEGraph<TAbstractDomain>, IEquatable<TAbstractDomain> {
+ private readonly SymValue from;
+ private readonly TFunc function;
+
+ public EdgeUpdate (SymValue from, TFunc function)
+ {
+ this.from = from;
+ this.function = function;
+ }
+
+ #region Overrides of Update
+ public override void Replay (MergeInfo<TFunc, TAbstractDomain> merge)
+ {
+ if (!merge.IsCommon (this.from))
+ return;
+
+ SymValue sv1 = merge.Graph1.LookupWithoutManifesting (this.from, this.function);
+ SymValue sv2 = merge.Graph2.LookupWithoutManifesting (this.from, this.function);
+ if (DebugOptions.Debug)
+ {
+ Console.WriteLine ("Replay edge update: {0} -{1} -> [ {2}, {3} ]",
+ this.from, this.function, sv1, sv2);
+ }
+ if (sv1 == null) {
+ if (this.function.KeepAsBottomField && merge.Graph1.HasAllBottomFields (this.from))
+ sv1 = merge.Graph1.BottomPlaceHolder;
+ else {
+ if (sv2 == null || merge.Widen || !this.function.ManifestField)
+ return;
+ if (DebugOptions.Debug)
+ {
+ Console.WriteLine ("---SymGraph changed due to manifestation of a top edge in Graph1");
+ }
+ merge.Changed = true;
+ }
+ }
+ if (sv2 == null) {
+ if (this.function.KeepAsBottomField && merge.Graph2.HasAllBottomFields (this.from))
+ sv2 = merge.Graph2.BottomPlaceHolder;
+ else {
+ if (merge.Widen || !this.function.ManifestField)
+ return;
+ if (DebugOptions.Debug)
+ {
+ Console.WriteLine ("---SymGraph changed due to manifestation of due to missing target in Graph2");
+ }
+ merge.Changed = true;
+ return;
+ }
+ }
+
+ SymValue r = merge.AddJointEdge (sv1, sv2, this.function, this.from);
+ if (r == null || r.UniqueId <= merge.LastCommonVariable)
+ return;
+
+ merge.JoinSymbolicValue (sv1, sv2, r);
+ }
+
+ public override void ReplayElimination (MergeInfo<TFunc, TAbstractDomain> merge)
+ {
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// EliminateEdgeUpdate.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph {
+ class EliminateEdgeUpdate<TFunc, TAbstractDomain> : Update<TFunc, TAbstractDomain>
+ where TFunc : IEquatable<TFunc>, IConstantInfo
+ where TAbstractDomain : IAbstractDomainForEGraph<TAbstractDomain>, IEquatable<TAbstractDomain> {
+ private readonly SymValue from;
+ private readonly TFunc function;
+
+ public EliminateEdgeUpdate (SymValue sv, TFunc function)
+ {
+ this.from = sv;
+ this.function = function;
+ }
+
+ #region Overrides of Update
+ public override void ReplayElimination (MergeInfo<TFunc, TAbstractDomain> merge)
+ {
+ if (!merge.IsCommon (this.from))
+ return;
+
+ merge.Result.Eliminate (this.function, this.from);
+ }
+
+ public override void Replay (MergeInfo<TFunc, TAbstractDomain> merge)
+ {
+ if (!merge.IsCommon (this.from))
+ return;
+
+ SymValue sv1 = merge.Graph1.LookupWithoutManifesting (this.from, this.function);
+ SymValue sv2 = merge.Graph2.LookupWithoutManifesting (this.from, this.function);
+ if (sv1 != null && sv2 != null)
+ return;
+ if (sv1 != null) {
+ if (DebugOptions.Debug)
+ {
+ Console.WriteLine ("---SymGraph changed due to EliminateEdgeUpdate {0}-{1} " +
+ "-> that is only in G1", this.from, this.function);
+ }
+ merge.Changed = true;
+ }
+
+ bool noEdgeInResult = merge.Result.LookupWithoutManifesting (this.from, this.function) == null;
+ if (noEdgeInResult)
+ return;
+
+ merge.Result.Eliminate (this.function, this.from);
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// EqualityPair.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph {
+ struct EqualityPair<TFunc, TAbstractDomain> : IEquatable<EqualityPair<TFunc, TAbstractDomain>>
+ where TFunc : IEquatable<TFunc>, IConstantInfo
+ where TAbstractDomain : IAbstractDomainForEGraph<TAbstractDomain>, IEquatable<TAbstractDomain> {
+
+ public readonly SymValue Sv1;
+ public readonly SymValue Sv2;
+
+ public EqualityPair (SymValue v1, SymValue v2)
+ {
+ this.Sv1 = v1;
+ this.Sv2 = v2;
+ }
+
+ #region Implementation of IEquatable<SymGraph<Constant,AbstractValue>.EqualityPair>
+ public bool Equals (EqualityPair<TFunc, TAbstractDomain> other)
+ {
+ return (this.Sv1 == other.Sv1 && this.Sv2 == other.Sv2);
+ }
+ #endregion
+
+ public override bool Equals (object obj)
+ {
+ if (obj is EqualityPair<TFunc, TAbstractDomain>)
+ return Equals ((EqualityPair<TFunc, TAbstractDomain>) obj);
+ return false;
+ }
+
+ public override int GetHashCode ()
+ {
+ return (this.Sv1 == null ? 1 : this.Sv1.GlobalId) + this.Sv2.GlobalId;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// EqualityUpdate.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph {
+ class EqualityUpdate<TFunc, TAbstractDomain> : Update<TFunc, TAbstractDomain>
+ where TFunc : IEquatable<TFunc>, IConstantInfo
+ where TAbstractDomain : IAbstractDomainForEGraph<TAbstractDomain>, IEquatable<TAbstractDomain> {
+ private readonly SymValue sv1;
+ private readonly SymValue sv2;
+
+ public EqualityUpdate (SymValue sv1, SymValue sv2)
+ {
+ this.sv1 = sv1;
+ this.sv2 = sv2;
+ }
+
+ #region Overrides of Update
+ public override void Replay (MergeInfo<TFunc, TAbstractDomain> merge)
+ {
+ if (!merge.IsCommon (this.sv1) || !merge.IsCommon (this.sv2) || (!merge.Graph1.IsEqual (this.sv1, this.sv2) || merge.Result.IsEqual (this.sv1, this.sv2)))
+ return;
+ if (merge.Graph2.IsEqual (this.sv1, this.sv2))
+ merge.Result.AssumeEqual (this.sv1, this.sv2);
+ else
+ merge.Changed = true;
+ }
+
+ public override void ReplayElimination (MergeInfo<TFunc, TAbstractDomain> merge)
+ {
+ }
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// IMergeInfo.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph {
+ interface IMergeInfo {
+ bool Changed { get; }
+ IEnumerable<Tuple<SymValue, SymValue, SymValue>> MergeTriples { get; }
+ IImmutableMap<SymValue, LispList<SymValue>> ForwardG1Map { get; }
+ IImmutableMap<SymValue, LispList<SymValue>> ForwardG2Map { get; }
+
+ bool IsResultGraph<TFunc, TAbstractDomain> (SymGraph<TFunc, TAbstractDomain> graph)
+ where TFunc : IEquatable<TFunc>, IConstantInfo
+ where TAbstractDomain : IAbstractDomainForEGraph<TAbstractDomain>, IEquatable<TAbstractDomain>;
+
+ bool IsGraph1<TFunc, TAbstractDomain> (SymGraph<TFunc, TAbstractDomain> graph)
+ where TFunc : IEquatable<TFunc>, IConstantInfo
+ where TAbstractDomain : IAbstractDomainForEGraph<TAbstractDomain>, IEquatable<TAbstractDomain>;
+
+ bool IsGraph2<TFunc, TAbstractDomain> (SymGraph<TFunc, TAbstractDomain> graph)
+ where TFunc : IEquatable<TFunc>, IConstantInfo
+ where TAbstractDomain : IAbstractDomainForEGraph<TAbstractDomain>, IEquatable<TAbstractDomain>;
+ }
+}
--- /dev/null
+//
+// MergeInfo.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Extensions;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph {
+ class MergeInfo<TFunc, TADomain> : IMergeInfo
+ where TFunc : IEquatable<TFunc>, IConstantInfo
+ where TADomain : IAbstractDomainForEGraph<TADomain>, IEquatable<TADomain> {
+
+ public readonly SymGraph<TFunc, TADomain> Result;
+ public readonly SymGraph<TFunc, TADomain> Graph1;
+ public readonly SymGraph<TFunc, TADomain> Graph2;
+
+ public readonly int LastCommonVariable;
+ public readonly bool Widen;
+
+ private readonly HashSet<SymValue> manifested;
+ private readonly DoubleDictionary<SymValue, SymValue, int> pending_counts;
+ private readonly HashSet<Tuple<SymValue, SymValue, MultiEdge<TFunc, TADomain>>> visited_multi_edges;
+
+ private DoubleImmutableMap<SymValue, SymValue, SymValue> mappings;
+ private IImmutableSet<SymValue> visited_key1;
+ private LispList<Tuple<SymValue, SymValue, SymValue>> merge_triples;
+
+ public MergeInfo (SymGraph<TFunc, TADomain> result,
+ SymGraph<TFunc, TADomain> g1,
+ SymGraph<TFunc, TADomain> g2, bool widen)
+ {
+ this.mappings = DoubleImmutableMap<SymValue, SymValue, SymValue>.Empty (SymValue.GetUniqueKey);
+ this.visited_key1 = ImmutableSet<SymValue>.Empty (SymValue.GetUniqueKey);
+ this.visited_multi_edges = new HashSet<Tuple<SymValue, SymValue, MultiEdge<TFunc, TADomain>>> ();
+ this.pending_counts = new DoubleDictionary<SymValue, SymValue, int> ();
+ this.manifested = new HashSet<SymValue> ();
+
+ this.LastCommonVariable = result.IdGenerator;
+ this.Widen = widen;
+ this.Result = result;
+ this.Graph1 = g1;
+ this.Graph2 = g2;
+
+ this.Changed = false;
+ }
+
+ #region IMergeInfo Members
+ public bool Changed { get; set; }
+
+ public IEnumerable<Tuple<SymValue, SymValue, SymValue>> MergeTriples
+ {
+ get { return this.merge_triples.AsEnumerable (); }
+ }
+
+ public IImmutableMap<SymValue, LispList<SymValue>> ForwardG1Map
+ {
+ get { return GetForwardGraphMap ((t) => t.Item1); }
+ }
+
+ public IImmutableMap<SymValue, LispList<SymValue>> ForwardG2Map
+ {
+ get { return GetForwardGraphMap ((t) => t.Item2); }
+ }
+
+ public bool IsResultGraph<TFunc1, TAbstractDomain> (SymGraph<TFunc1, TAbstractDomain> graph)
+ where TFunc1 : IEquatable<TFunc1>, IConstantInfo
+ where TAbstractDomain : IAbstractDomainForEGraph<TAbstractDomain>, IEquatable<TAbstractDomain>
+ {
+ return Equals (graph, this.Result);
+ }
+
+ public bool IsGraph1<TFunc1, TAbstractDomain> (SymGraph<TFunc1, TAbstractDomain> graph)
+ where TFunc1 : IEquatable<TFunc1>, IConstantInfo
+ where TAbstractDomain : IAbstractDomainForEGraph<TAbstractDomain>, IEquatable<TAbstractDomain>
+ {
+ return (Equals (this.Graph1, graph) || Equals (this.Graph1.Parent, graph) && Equals (this.Graph1.Updates, graph.Updates));
+ }
+
+ public bool IsGraph2<TFunc1, TAbstractDomain> (SymGraph<TFunc1, TAbstractDomain> graph)
+ where TFunc1 : IEquatable<TFunc1>, IConstantInfo
+ where TAbstractDomain : IAbstractDomainForEGraph<TAbstractDomain>, IEquatable<TAbstractDomain>
+ {
+ return (Equals (this.Graph2, graph) || Equals (this.Graph2.Parent, graph) && Equals (this.Graph2.Updates, graph.Updates));
+ }
+ #endregion
+
+ public void AddMapping (SymValue v1, SymValue v2, SymValue result)
+ {
+ if (v1 != null && v2 != null)
+ this.mappings = this.mappings.Add (v1, v2, result);
+ else if (v2 == null)
+ this.visited_key1 = this.visited_key1.Add (v1);
+ else
+ this.visited_key1 = this.visited_key1.Add (v2);
+
+ AddMergeTriple (v1, v2, result);
+ }
+
+ public SymValue AddJointEdge (SymValue v1Target, SymValue v2Target, TFunc function, SymValue resultArg)
+ {
+ SymValue result = LookupMapping (v1Target, v2Target);
+ bool newEdge = false;
+ if (result == null)
+ {
+ if (IsMappingAlreadyAdded (v1Target, v2Target))
+ {
+ if (DebugOptions.Debug)
+ Console.WriteLine ("---SymGraph changed due to pre-existing mapping in G1 of {0}", v1Target);
+ Changed = true;
+ if (v1Target == null)
+ {
+ if (this.manifested.Contains (v2Target))
+ return null;
+ this.manifested.Add (v2Target);
+ }
+ if (v2Target == null)
+ {
+ if (this.manifested.Contains (v1Target))
+ return null;
+ this.manifested.Add (v1Target);
+ }
+ }
+ newEdge = true;
+ result = v1Target == null || v1Target.UniqueId > this.LastCommonVariable || v1Target != v2Target ? this.Result.FreshSymbol () : v1Target;
+ AddMapping (v1Target, v2Target, result);
+ }
+ else if (this.Result.LookupWithoutManifesting (resultArg, function) == result)
+ return null;
+ this.Result[function, resultArg] = result;
+ TADomain val1 = Graph1ADomain (v1Target);
+ TADomain val2 = Graph2ADomain (v2Target);
+
+ bool weaker;
+ TADomain join = val1.Join (val2, this.Widen, out weaker);
+ this.Result[result] = join;
+
+ if (weaker)
+ {
+ if (DebugOptions.Debug)
+ {
+ Console.WriteLine ("----SymGraph changed due to join of abstract values of [{0}, {1}] " +
+ "(prev {2}, new {3}, join {4}", v1Target, v2Target, val1, val2, join);
+ }
+ Changed = true;
+ }
+
+ return newEdge ? result : null;
+ }
+
+ public SymValue AddJointEdge (SymValue v1Target, SymValue v2Target, TFunc function, SymValue[] resultArgs)
+ {
+ SymValue result = LookupMapping (v1Target, v2Target);
+ bool newEdge = false;
+ if (result == null)
+ {
+ if (IsMappingAlreadyAdded (v1Target, v2Target))
+ {
+ if (DebugOptions.Debug)
+ Console.WriteLine ("---SymGraph changed due to pre-existing mapping in G1 of {0}", v1Target);
+ Changed = true;
+ if (v1Target == null || v2Target == null)
+ return null;
+ }
+ newEdge = true;
+ result = v1Target == null || v1Target.UniqueId > this.LastCommonVariable || v1Target != v2Target ? this.Result.FreshSymbol () : v1Target;
+ AddMapping (v1Target, v2Target, result);
+ }
+ else if (this.Result.LookupWithoutManifesting (resultArgs, function) == result)
+ return null;
+ this.Result[resultArgs, function] = result;
+ TADomain val1 = Graph1ADomain (v1Target);
+ TADomain val2 = Graph2ADomain (v2Target);
+
+ bool weaker;
+ TADomain joinValue = val1.Join (val2, this.Widen, out weaker);
+
+ this.Result[result] = joinValue;
+ if (weaker)
+ {
+ if (DebugOptions.Debug)
+ Console.WriteLine ("----SymGraph changed due to join of abstract values of [{0}, {1}] (prev {2}, new {3}, join {4}",
+ v1Target, v2Target,
+ val1, val2, joinValue);
+ Changed = true;
+ }
+
+ if (DebugOptions.Debug)
+ {
+ Console.WriteLine ("AddJointEdge: ({0}) -{1} -> [{2},{3},{4}]",
+ resultArgs.ToString (", "), function,
+ v1Target, v2Target, result);
+ }
+ return newEdge ? result : null;
+ }
+
+ public bool IsCommon (SymValue sv)
+ {
+ return sv.UniqueId <= this.LastCommonVariable;
+ }
+
+ public bool AreCommon (SymValue[] svs)
+ {
+ return svs.All (sv => IsCommon (sv));
+ }
+
+ public void JoinSymbolicValue (SymValue sv1, SymValue sv2, SymValue r)
+ {
+ if (this.Graph2.HasAllBottomFields (sv2)) {
+ if (sv1 != null) {
+ foreach (TFunc function in this.Graph1.TermMap.Keys2 (sv1)) {
+ SymValue v1 = this.Graph1.LookupWithoutManifesting (sv1, function);
+ bool isPlaceHolder;
+ SymValue v2 = this.Graph2.LookupOrBottomPlaceHolder (sv2, function, out isPlaceHolder);
+ if (!isPlaceHolder || function.KeepAsBottomField) {
+ SymValue r1 = AddJointEdge (v1, v2, function, r);
+ if (r1 != null)
+ JoinSymbolicValue (v1, v2, r1);
+ }
+ }
+ }
+ } else if (!this.Widen && this.Graph1.HasAllBottomFields (sv1)) {
+ if (DebugOptions.Debug)
+ Console.WriteLine ("---SymGraph changed due to an all bottom field value in G1 changing to non-bottom");
+ Changed = true;
+ if (sv2 != null) {
+ foreach (TFunc function in this.Graph2.TermMap.Keys2 (sv2)) {
+ bool isPlaceHolder;
+ SymValue v1 = this.Graph1.LookupOrBottomPlaceHolder (sv1, function, out isPlaceHolder);
+ SymValue v2 = this.Graph2.LookupWithoutManifesting (sv2, function);
+ if (!isPlaceHolder || function.KeepAsBottomField) {
+ SymValue r1 = AddJointEdge (v1, v2, function, r);
+ if (r1 != null)
+ JoinSymbolicValue (v1, v2, r1);
+ }
+ }
+ }
+ } else {
+ IEnumerable<TFunc> functions;
+ if (this.Widen) {
+ if (this.Graph1.TermMap.Keys2Count (sv1) <= this.Graph2.TermMap.Keys2Count (sv2))
+ functions = this.Graph1.TermMap.Keys2 (sv1);
+ else {
+ functions = this.Graph2.TermMap.Keys2 (sv2);
+ if (DebugOptions.Debug)
+ Console.WriteLine ("---SymGraph changed because G2 has fewer keys for {0} than {1} in G1", sv2, sv1);
+ Changed = true;
+ }
+ } else {
+ if (this.Graph1.TermMap.Keys2Count (sv1) < this.Graph2.TermMap.Keys2Count (sv2)) {
+ functions = this.Graph2.TermMap.Keys2 (sv2);
+ if (DebugOptions.Debug)
+ Console.WriteLine ("---SymGraph changed because G1 has fewer keys for {0} than {1} in G2", sv1, sv2);
+ Changed = true;
+ } else
+ functions = this.Graph1.TermMap.Keys2 (sv1);
+ }
+
+ foreach (TFunc function in functions) {
+ SymValue v1 = this.Graph1.LookupWithoutManifesting (sv1, function);
+ SymValue v2 = this.Graph2.LookupWithoutManifesting (sv2, function);
+
+ if (v1 == null) {
+ if (!this.Widen && function.ManifestField) {
+ if (DebugOptions.Debug)
+ Console.WriteLine ("---SymGraph changed due to manifestation of a top edge in G1");
+ Changed = true;
+
+ } else
+ continue;
+ }
+ if (v2 == null && (this.Widen || !function.ManifestField)) {
+ if (DebugOptions.Debug)
+ Console.WriteLine ("---SymGraph changed due to absence of map {0}-{1} -> in G2", sv2, function);
+ Changed = true;
+ }
+
+ if (v1 != null && v2 != null)
+ {
+ //we have to joint ends of edges
+ SymValue r1 = AddJointEdge (v1, v2, function, r);
+ if (r1 != null)
+ JoinSymbolicValue (v1, v2, r1);
+ }
+ }
+ }
+
+ JoinMultiEdges (sv1, sv2);
+ }
+
+ public void JoinMultiEdge (SymValue sv1, SymValue sv2, MultiEdge<TFunc, TADomain> edge)
+ {
+ var key = new Tuple<SymValue, SymValue, MultiEdge<TFunc, TADomain>> (sv1, sv2, edge);
+ if (!this.visited_multi_edges.Add (key))
+ return;
+
+ LispList<SymValue> list1 = this.Graph1.MultiEdgeMap [sv1, edge];
+ LispList<SymValue> list2 = this.Graph2.MultiEdgeMap [sv2, edge];
+ if (list2.IsEmpty ())
+ return;
+ foreach (SymValue v1 in list1.AsEnumerable ()) {
+ foreach (SymValue v2 in list2.AsEnumerable ()) {
+ if (UpdatePendingCount (v1, v2, edge.Arity)) {
+ SymGraphTerm<TFunc> term1 = this.Graph1.EqualMultiTermsMap [v1];
+ SymGraphTerm<TFunc> term2 = this.Graph2.EqualMultiTermsMap [v2];
+ if (term1.Args != null && term2.Args != null) {
+ var resultRoots = new SymValue[term1.Args.Length];
+ for (int i = 0; i < resultRoots.Length; i++)
+ resultRoots [i] = this.mappings [term1.Args [i], term2.Args [i]];
+ SymValue r = AddJointEdge (v1, v2, edge.Function, resultRoots);
+ if (r != null)
+ JoinSymbolicValue (sv1, sv2, r);
+ } else
+ break;
+ }
+ }
+ }
+ }
+
+ public void Replay (SymGraph<TFunc, TADomain> common)
+ {
+ PrimeMapWithCommon ();
+ Replay (this.Graph1.Updates, common.Updates);
+ Replay (this.Graph2.Updates, common.Updates);
+ }
+
+ public void ReplayEliminations (SymGraph<TFunc, TADomain> common)
+ {
+ ReplayEliminations (this.Graph1.Updates, common.Updates);
+ ReplayEliminations (this.Graph2.Updates, common.Updates);
+ }
+
+ public void Commit ()
+ {
+ if (Changed)
+ return;
+
+ bool needContinue = false;
+ foreach (var edge in this.Graph1.ValidMultiTerms)
+ {
+ SymGraphTerm<TFunc> term = edge.Value;
+ var args = new SymValue[term.Args.Length];
+
+ for (int i = 0; i < args.Length; ++i)
+ {
+ SymValue sv = term.Args[i];
+ if (IsMappingAlreadyAdded (sv, null))
+ {
+ if (this.mappings.Keys2 (sv) != null && this.mappings.Keys2 (sv).Count () == 1)
+ args[i] = this.mappings[sv, this.mappings.Keys2 (sv).First ()];
+ }
+ else
+ {
+ needContinue = true;
+ break;
+ }
+
+ if (args[i] == null)
+ {
+ Changed = true;
+ return;
+ }
+ }
+
+ if (needContinue)
+ continue;
+
+ SymValue symbol = this.Result.LookupWithoutManifesting (args, term.Function);
+ if (symbol != null)
+ {
+ SymValue key = edge.Key;
+ if (this.mappings.Keys2 (key) != null && this.mappings.Keys2 (key).Count () == 1 && this.mappings[key, this.mappings.Keys2 (key).First ()] == symbol)
+ continue;
+ }
+
+ Changed = true;
+ return;
+ }
+ }
+
+ private IImmutableMap<SymValue, LispList<SymValue>> GetForwardGraphMap (Func<Tuple<SymValue, SymValue, SymValue>, SymValue> sourceSelector)
+ {
+ IImmutableMap<SymValue, LispList<SymValue>> res = ImmutableIntKeyMap<SymValue, LispList<SymValue>>.Empty (SymValue.GetUniqueKey);
+ foreach (var tuple in this.merge_triples.AsEnumerable ()) {
+ SymValue sv = sourceSelector (tuple);
+ if (sv != null)
+ res = res.Add (sv, res [sv].Cons (tuple.Item3));
+ }
+ return res;
+ }
+
+ private bool UpdatePendingCount (SymValue xi, SymValue yi, int arity)
+ {
+ int result;
+ this.pending_counts.TryGetValue (xi, yi, out result);
+ result = result + 1;
+
+ this.pending_counts [xi, yi] = result;
+ if (result == arity)
+ return true;
+
+ return false;
+ }
+
+ private void JoinMultiEdges (SymValue sv1, SymValue sv2)
+ {
+ if (sv1 == null || sv2 == null)
+ return;
+
+ IEnumerable<MultiEdge<TFunc, TADomain>> edges =
+ this.Graph1.MultiEdgeMap.Keys2Count (sv1) > this.Graph2.MultiEdgeMap.Keys2Count (sv2)
+ ? this.Graph2.MultiEdgeMap.Keys2 (sv2)
+ : this.Graph1.MultiEdgeMap.Keys2 (sv1);
+ foreach (var edge in edges)
+ JoinMultiEdge (sv1, sv2, edge);
+ }
+
+ private TADomain Graph1ADomain (SymValue sv)
+ {
+ if (sv != null)
+ return this.Graph1 [sv];
+ return this.Graph1.UnderlyingTopValue.ForManifestedField ();
+ }
+
+ private TADomain Graph2ADomain (SymValue sv)
+ {
+ if (sv != null)
+ return this.Graph2 [sv];
+ return this.Graph2.UnderlyingTopValue.ForManifestedField ();
+ }
+
+ private void AddMergeTriple (SymValue v1, SymValue v2, SymValue result)
+ {
+ this.merge_triples = this.merge_triples.Cons (new Tuple<SymValue, SymValue, SymValue> (v1, v2, result));
+ }
+
+ private bool IsMappingAlreadyAdded (SymValue v1, SymValue v2)
+ {
+ if (v1 != null)
+ return this.visited_key1.Contains (v1) || this.mappings.ContainsKey1 (v1);
+
+ return this.visited_key1.Contains (v2);
+ }
+
+ private SymValue LookupMapping (SymValue v1, SymValue v2)
+ {
+ if (v1 == null || v2 == null)
+ return null;
+
+ return this.mappings [v1, v2];
+ }
+
+ private void PrimeMapWithCommon ()
+ {
+ LispList<SymValue> rest = null;
+ foreach (SymValue sv in this.Graph1.EqualTermsMap.Keys) {
+ if (IsCommon (sv) && (this.Graph2.EqualTermsMap.ContainsKey (sv) || this.Graph2.EqualMultiTermsMap.ContainsKey (sv))) {
+ if (this.Graph1.MultiEdgeMap.ContainsKey1 (sv))
+ rest = rest.Cons (sv);
+ AddMapping (sv, sv, sv);
+ }
+ }
+ foreach (SymValue sv in this.Graph1.EqualMultiTermsMap.Keys) {
+ if (IsCommon (sv) && (this.Graph2.EqualTermsMap.ContainsKey (sv) || this.Graph2.EqualMultiTermsMap.ContainsKey (sv)) && this.mappings [sv, sv] == null) {
+ if (this.Graph1.MultiEdgeMap.ContainsKey1 (sv))
+ rest = rest.Cons (sv);
+ AddMapping (sv, sv, sv);
+ }
+ }
+ while (rest != null) {
+ SymValue sv = rest.Head;
+ rest = rest.Tail;
+ foreach (var edge in this.Graph1.MultiEdgeMap.Keys2 (sv))
+ JoinMultiEdge (sv, sv, edge);
+ }
+ }
+
+ private void Replay (LispList<Update<TFunc, TADomain>> updates, LispList<Update<TFunc, TADomain>> common)
+ {
+ for (Update<TFunc, TADomain> update = Update<TFunc, TADomain>.Reverse (updates, common); update != null; update = update.Next)
+ update.Replay (this);
+ }
+
+ private void ReplayEliminations (LispList<Update<TFunc, TADomain>> updates, LispList<Update<TFunc, TADomain>> common)
+ {
+ for (Update<TFunc, TADomain> update = Update<TFunc, TADomain>.Reverse (updates, common); update != null; update = update.Next)
+ update.ReplayElimination (this);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// MultiEdge.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph {
+ struct MultiEdge<TFunc, TAbstractDomain> : IEquatable<MultiEdge<TFunc, TAbstractDomain>>
+ where TFunc : IEquatable<TFunc>, IConstantInfo
+ where TAbstractDomain : IAbstractDomainForEGraph<TAbstractDomain>, IEquatable<TAbstractDomain> {
+
+ public readonly int Arity;
+ public readonly int Index;
+ public readonly TFunc Function;
+
+ public MultiEdge (TFunc function, int index, int arity)
+ {
+ this.Function = function;
+ this.Index = index;
+ this.Arity = arity;
+ }
+
+ #region Implementation of IEquatable<MultiEdge>
+ public bool Equals (MultiEdge<TFunc, TAbstractDomain> other)
+ {
+ return (this.Index == other.Index && this.Arity == other.Arity && this.Function.Equals (other.Function));
+ }
+ #endregion
+
+ public override bool Equals (object obj)
+ {
+ if (obj is MultiEdge<TFunc, TAbstractDomain>)
+ return Equals ((MultiEdge<TFunc, TAbstractDomain>) obj);
+ return false;
+ }
+
+ public override int GetHashCode ()
+ {
+ return this.Arity*13 + this.Index;
+ }
+
+ public override string ToString ()
+ {
+ return String.Format ("[{0}:{1}]", this.Function, this.Index);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// MultiEdgeUpdate.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph {
+ class MultiEdgeUpdate<TFunc, TAbstractDomain> : Update<TFunc, TAbstractDomain>
+ where TFunc : IEquatable<TFunc>, IConstantInfo
+ where TAbstractDomain : IAbstractDomainForEGraph<TAbstractDomain>, IEquatable<TAbstractDomain> {
+ private readonly SymValue[] from;
+ private readonly TFunc function;
+
+ public MultiEdgeUpdate (SymValue[] from, TFunc function)
+ {
+ this.function = function;
+ this.from = from;
+ }
+
+ #region Overrides of Update
+ public override void Replay (MergeInfo<TFunc, TAbstractDomain> merge)
+ {
+ int len = this.from.Length;
+ for (int i = 0; i < len; i++) {
+ SymValue sv = this.from [i];
+ if (merge.IsCommon (sv))
+ merge.JoinMultiEdge (sv, sv, new MultiEdge<TFunc, TAbstractDomain> (this.function, i, len));
+ }
+ }
+
+ public override void ReplayElimination (MergeInfo<TFunc, TAbstractDomain> merge)
+ {
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// SymGraph.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+using System.Linq;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Extensions;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph {
+ class SymGraph<TFunc, TADomain> : ISymGraph<TFunc, TADomain, SymGraph<TFunc, TADomain>>
+ where TFunc : IEquatable<TFunc>, IConstantInfo
+ where TADomain : IAbstractDomainForEGraph<TADomain>, IEquatable<TADomain> {
+ public const bool DoIncrementalJoin = false;
+ private static int egraphIdGenerator;
+ private static SymGraph<TFunc, TADomain> BottomValue;
+ public readonly SymValue BottomPlaceHolder;
+ public readonly SymGraph<TFunc, TADomain> Parent;
+ public readonly TADomain UnderlyingTopValue;
+
+ private readonly SymValue const_root;
+ private readonly int egraph_id;
+ private readonly int history_size;
+
+ private readonly SymGraph<TFunc, TADomain> root_graph;
+
+ private readonly TADomain underlying_bottom_value;
+ private IImmutableMap<SymValue, TADomain> abs_map;
+ private IImmutableMap<SymValue, SymValue> forw_map;
+ private bool is_immutable;
+
+ public SymGraph (TADomain topValue, TADomain bottomValue)
+ : this (topValue, bottomValue, false)
+ {
+ if (BottomValue != null)
+ return;
+ BottomValue = new SymGraph<TFunc, TADomain> (topValue, bottomValue, false);
+ }
+
+ private SymGraph (TADomain topValue, TADomain bottomValue, bool _)
+ {
+ this.egraph_id = egraphIdGenerator++;
+ this.const_root = FreshSymbol ();
+
+ TermMap = DoubleImmutableMap<SymValue, TFunc, SymValue>.Empty (SymValue.GetUniqueKey);
+ MultiEdgeMap = DoubleImmutableMap<SymValue, MultiEdge<TFunc, TADomain>, LispList<SymValue>>.Empty (SymValue.GetUniqueKey);
+ this.abs_map = ImmutableIntKeyMap<SymValue, TADomain>.Empty (SymValue.GetUniqueKey);
+ this.forw_map = ImmutableIntKeyMap<SymValue, SymValue>.Empty (SymValue.GetUniqueKey);
+ EqualTermsMap = ImmutableIntKeyMap<SymValue, LispList<SymGraphTerm<TFunc>>>.Empty (SymValue.GetUniqueKey);
+ EqualMultiTermsMap = ImmutableIntKeyMap<SymValue, SymGraphTerm<TFunc>>.Empty (SymValue.GetUniqueKey);
+
+ this.BottomPlaceHolder = FreshSymbol ();
+ this.abs_map = this.abs_map.Add (this.BottomPlaceHolder, bottomValue);
+ this.is_immutable = false;
+ this.history_size = 1;
+ this.Parent = null;
+ this.root_graph = this;
+ Updates = null;
+ this.UnderlyingTopValue = topValue;
+ this.underlying_bottom_value = bottomValue;
+ }
+
+ private SymGraph (SymGraph<TFunc, TADomain> from)
+ {
+ this.egraph_id = egraphIdGenerator++;
+ this.const_root = from.const_root;
+ this.BottomPlaceHolder = from.BottomPlaceHolder;
+ TermMap = from.TermMap;
+ MultiEdgeMap = from.MultiEdgeMap;
+ IdGenerator = from.IdGenerator;
+ this.abs_map = from.abs_map;
+ this.forw_map = from.forw_map;
+ EqualTermsMap = from.EqualTermsMap;
+ EqualMultiTermsMap = from.EqualMultiTermsMap;
+ this.UnderlyingTopValue = from.UnderlyingTopValue;
+ this.underlying_bottom_value = from.underlying_bottom_value;
+ Updates = from.Updates;
+ this.Parent = from;
+ this.root_graph = from.root_graph;
+ this.history_size = from.history_size + 1;
+
+ from.MarkAsImmutable ();
+ }
+
+ public IImmutableMap<SymValue, SymGraphTerm<TFunc>> EqualMultiTermsMap { get; private set; }
+ public IImmutableMap<SymValue, LispList<SymGraphTerm<TFunc>>> EqualTermsMap { get; private set; }
+ public DoubleImmutableMap<SymValue, MultiEdge<TFunc, TADomain>, LispList<SymValue>> MultiEdgeMap { get; private set; }
+ public DoubleImmutableMap<SymValue, TFunc, SymValue> TermMap { get; private set; }
+ public int IdGenerator { get; private set; }
+ public LispList<Update<TFunc, TADomain>> Updates { get; private set; }
+
+ public bool IsImmutable
+ {
+ get { return this.is_immutable; }
+ }
+
+ private int LastSymbolId
+ {
+ get { return IdGenerator; }
+ }
+
+ public SymValue this [SymValue[] args, TFunc function]
+ {
+ get
+ {
+ int len = args.Length;
+ for (int i = 0; i < len; i++)
+ args [i] = Find (args [i]);
+
+ SymValue candidate = FindCandidate (args, function);
+ if (candidate != null)
+ return candidate;
+ candidate = FreshSymbol ();
+ for (int i = 0; i < len; i++) {
+ var edge = new MultiEdge<TFunc, TADomain> (function, i, len);
+ MultiEdgeMap = MultiEdgeMap.Add (args [i], edge, MultiEdgeMap [args [i], edge].Cons (candidate));
+ }
+ EqualMultiTermsMap = EqualMultiTermsMap.Add (candidate, new SymGraphTerm<TFunc> (function, args));
+ AddMultiEdgeUpdate (args, function);
+ return candidate;
+ }
+ set
+ {
+ int len = args.Length;
+ for (int i = 0; i < len; i++)
+ args [i] = Find (args [i]);
+
+ bool isTermEqual = true;
+ SymGraphTerm<TFunc> term = EqualMultiTermsMap [value];
+ if (term.Args != null) {
+ for (int i = 0; i < len; i++) {
+ if (term.Args [i] != args [i]) {
+ isTermEqual = false;
+ break;
+ }
+ }
+ }
+
+ for (int i = 0; i < len; i++) {
+ var edge = new MultiEdge<TFunc, TADomain> (function, i, len);
+ LispList<SymValue> list = MultiEdgeMap [args [i], edge];
+ if (isTermEqual && !LispList<SymValue>.Contains (list, value))
+ isTermEqual = false;
+ if (!isTermEqual)
+ MultiEdgeMap = MultiEdgeMap.Add (args [i], edge, list.Cons (value));
+ }
+ if (isTermEqual)
+ return;
+ EqualMultiTermsMap = EqualMultiTermsMap.Add (value, new SymGraphTerm<TFunc> (function, args));
+ AddMultiEdgeUpdate (args, function);
+ }
+ }
+
+ public SymValue this [TFunc function, params SymValue[] args]
+ {
+ get { return this [args, function]; }
+ }
+
+ private SymValue this [SymValue source, TFunc function]
+ {
+ get
+ {
+ source = Find (source);
+ SymValue sv = TermMap [source, function];
+ SymValue key;
+ if (sv == null) {
+ key = FreshSymbol ();
+ TermMap = TermMap.Add (source, function, key);
+ EqualTermsMap = EqualTermsMap.Add (key, LispList<SymGraphTerm<TFunc>>.Cons (new SymGraphTerm<TFunc> (function, source), null));
+ AddEdgeUpdate (source, function);
+ } else
+ key = Find (sv);
+
+ return key;
+ }
+ set
+ {
+ source = Find (source);
+ value = Find (value);
+
+ TermMap = TermMap.Add (source, function, value);
+ LispList<SymGraphTerm<TFunc>> rest = EqualTermsMap [value];
+ if (rest.IsEmpty () || (!rest.Head.Function.Equals (function) || rest.Head.Args [0] != source))
+ EqualTermsMap = EqualTermsMap.Add (value, rest.Cons (new SymGraphTerm<TFunc> (function, source)));
+
+ AddEdgeUpdate (source, function);
+ }
+ }
+
+ public IEnumerable<Pair<SymValue, SymGraphTerm<TFunc>>> ValidMultiTerms {
+ get
+ {
+ foreach (SymValue sv in EqualMultiTermsMap.Keys) {
+ SymGraphTerm<TFunc> term = EqualMultiTermsMap [sv];
+ if (IsValidMultiTerm (term))
+ yield return new Pair<SymValue, SymGraphTerm<TFunc>> (sv, term);
+ }
+ }
+ }
+
+ public SymValue ConstRoot
+ {
+ get { return this.const_root; }
+ }
+
+ #region ISymGraph<TFunc,TADomain,SymGraph<TFunc,TADomain>> Members
+ public TADomain this [SymValue symbol]
+ {
+ get
+ {
+ symbol = Find (symbol);
+ if (this.abs_map.ContainsKey (symbol))
+ return this.abs_map [symbol];
+
+ return this.UnderlyingTopValue;
+ }
+ set
+ {
+ SymValue newSym = Find (symbol);
+ if (this [symbol].Equals (value))
+ return;
+ AddAbstractValueUpdate (newSym);
+ if (value.IsTop)
+ this.abs_map = this.abs_map.Remove (newSym);
+ else
+ this.abs_map = this.abs_map.Add (newSym, value);
+ }
+ }
+
+ public SymValue this [TFunc function]
+ {
+ get { return this [this.const_root, function]; }
+ set { this [this.const_root, function] = value; }
+ }
+
+ public SymValue this [TFunc function, SymValue arg]
+ {
+ get { return this [arg, function]; }
+ set { this [arg, function] = value; }
+ }
+
+ public IEnumerable<TFunc> Constants
+ {
+ get { return TermMap.Keys2 (this.const_root); }
+ }
+
+ public IEnumerable<SymValue> Variables
+ {
+ get { return TermMap.Keys1; }
+ }
+
+ public SymGraph<TFunc, TADomain> Top
+ {
+ get { return new SymGraph<TFunc, TADomain> (this.UnderlyingTopValue, this.underlying_bottom_value); }
+ }
+
+ public SymGraph<TFunc, TADomain> Bottom
+ {
+ get
+ {
+ if (BottomValue == null) {
+ BottomValue = new SymGraph<TFunc, TADomain> (this.UnderlyingTopValue, this.underlying_bottom_value);
+ BottomValue.MarkAsImmutable ();
+ }
+ return BottomValue;
+ }
+ }
+
+ public bool IsTop
+ {
+ get { return TermMap.Keys2Count (this.const_root) == 0; }
+ }
+
+ public bool IsBottom
+ {
+ get { return this == BottomValue; }
+ }
+
+ public SymValue FreshSymbol ()
+ {
+ return new SymValue (++IdGenerator);
+ }
+
+ public SymValue TryLookup (TFunc function)
+ {
+ return LookupWithoutManifesting (this.const_root, function);
+ }
+
+ public SymValue TryLookup (TFunc function, SymValue arg)
+ {
+ return LookupWithoutManifesting (arg, function);
+ }
+
+ public void Eliminate (TFunc function, SymValue arg)
+ {
+ SymValue value = Find (arg);
+ DoubleImmutableMap<SymValue, TFunc, SymValue> newTermMap = TermMap.Remove (value, function);
+ if (newTermMap == TermMap)
+ return;
+ TermMap = newTermMap;
+ AddEliminateEdgeUpdate (value, function);
+ }
+
+ public void Eliminate (TFunc function)
+ {
+ TermMap = TermMap.Remove (this.const_root, function);
+ AddEliminateEdgeUpdate (this.const_root, function);
+ }
+
+ public void EliminateAll (SymValue arg)
+ {
+ SymValue value = Find (arg);
+ AddEliminateAllUpdate (value);
+ TermMap = TermMap.RemoveAll (value);
+ this [arg] = this.UnderlyingTopValue;
+ }
+
+ public void AssumeEqual (SymValue v1, SymValue v2)
+ {
+ var workList = new WorkList<EqualityPair<TFunc, TADomain>> ();
+ SymValue sv1 = Find (v1);
+ SymValue sv2 = Find (v2);
+
+ if (TryPushEquality (workList, sv1, sv2))
+ AddEqualityUpdate (sv1, sv2);
+
+ DrainEqualityWorkList (workList);
+ }
+
+ public bool IsEqual (SymValue v1, SymValue v2)
+ {
+ return Find (v1) == Find (v2);
+ }
+
+ public IEnumerable<TFunc> Functions (SymValue sv)
+ {
+ return TermMap.Keys2 (Find (sv));
+ }
+
+ public IEnumerable<SymGraphTerm<TFunc>> EqTerms (SymValue sv)
+ {
+ foreach (var term in EqualTermsMap [Find (sv)].AsEnumerable ()) {
+ if (TryLookup (term.Function, term.Args) == sv)
+ yield return term;
+ }
+ }
+
+ public SymGraph<TFunc, TADomain> Clone ()
+ {
+ return new SymGraph<TFunc, TADomain> (this);
+ }
+
+ public SymGraph<TFunc, TADomain> Join (SymGraph<TFunc, TADomain> that, bool widening, out bool weaker)
+ {
+ IMergeInfo info;
+ SymGraph<TFunc, TADomain> join = Join (that, out info, widening);
+ weaker = info.Changed;
+ return join;
+ }
+
+ public SymGraph<TFunc, TADomain> Join (SymGraph<TFunc, TADomain> that, out IMergeInfo mergeInfo, bool widen)
+ {
+ SymGraph<TFunc, TADomain> egraph = this;
+ int updateSize;
+ SymGraph<TFunc, TADomain> commonTail = ComputeCommonTail (egraph, that, out updateSize);
+ bool hasCommonTail = true;
+ if (commonTail == null)
+ hasCommonTail = false;
+
+ bool doingIncrementalJoin = hasCommonTail & commonTail != egraph.root_graph & !widen & DoIncrementalJoin;
+
+ //debug
+
+ if (DebugOptions.Debug)
+ {
+ Console.WriteLine ("SymGraph {0}", widen ? "widen" : "join");
+ if (commonTail != null)
+ Console.WriteLine ("Last common symbol: {0}", commonTail.LastSymbolId);
+
+ Console.WriteLine (" Doing {0}", doingIncrementalJoin ? "incremental join" : "full join");
+ }
+
+ SymGraph<TFunc, TADomain> result;
+ MergeInfo<TFunc, TADomain> mergeState;
+ if (doingIncrementalJoin) {
+ result = new SymGraph<TFunc, TADomain> (commonTail);
+ mergeState = new MergeInfo<TFunc, TADomain> (result, egraph, that, widen);
+ mergeState.Replay (commonTail);
+ mergeState.Commit ();
+ } else {
+ result = new SymGraph<TFunc, TADomain> (commonTail);
+ mergeState = new MergeInfo<TFunc, TADomain> (result, egraph, that, widen);
+ mergeState.ReplayEliminations (commonTail);
+ mergeState.AddMapping (egraph.const_root, that.const_root, result.const_root);
+ mergeState.JoinSymbolicValue (egraph.const_root, that.const_root, result.const_root);
+ mergeState.Commit ();
+ }
+ mergeInfo = mergeState;
+
+ if (DebugOptions.Debug)
+ {
+ Console.WriteLine (" Result update size {0}", result.Updates.Length ());
+ Console.WriteLine ("Done with Egraph join: changed = {0}", mergeInfo.Changed ? 1 : 0);
+ }
+
+ return result;
+ }
+
+ public void Dump (TextWriter tw)
+ {
+ var set = new HashSet<SymValue> ();
+ var workList = new WorkList<SymValue> ();
+ IImmutableMap<SymValue, int> triggers = ImmutableIntKeyMap<SymValue, int>.Empty (SymValue.GetUniqueKey);
+ tw.WriteLine ("EGraphId: {0}", this.egraph_id);
+ tw.WriteLine ("LastSymbolId: {0}", LastSymbolId);
+
+ foreach (TFunc function in TermMap.Keys2 (this.const_root)) {
+ SymValue sv = this [this.const_root, function];
+ tw.WriteLine ("{0} = {1}", function, sv);
+ workList.Add (sv);
+ }
+
+ while (!workList.IsEmpty ()) {
+ SymValue sv = workList.Pull ();
+ if (!set.Add (sv))
+ continue;
+
+ foreach (TFunc function in TermMap.Keys2 (sv)) {
+ SymValue target = this [sv, function];
+
+ tw.WriteLine ("{0}({2}) = {1})", function, target, sv);
+ workList.Add (target);
+ }
+ foreach (var edge in MultiEdgeMap.Keys2 (sv)) {
+ foreach (SymValue target in MultiEdgeMap [sv, edge].AsEnumerable ()) {
+ if (!UpdateTrigger (target, edge, ref triggers))
+ continue;
+ SymGraphTerm<TFunc> term = EqualMultiTermsMap [target];
+ if (term.Args != null) {
+ tw.WriteLine ("{0}({1}) = {2}",
+ term.Function,
+ term.Args.ToString (", "), target);
+ workList.Add (target);
+ }
+ }
+ }
+ }
+
+ tw.WriteLine ("**Abstract value map");
+ foreach (SymValue sv in set) {
+ TADomain abstractValue = this [sv];
+ if (!abstractValue.IsTop)
+ tw.WriteLine ("{0} -> {1}", sv, abstractValue);
+ }
+ }
+ #endregion
+
+ #region Implementation of IAbstractDomain<SymGraph<Constant,AbstractValue>>
+ public SymGraph<TFunc, TADomain> Meet (SymGraph<TFunc, TADomain> that)
+ {
+ if (this == that || IsBottom || that.IsTop)
+ return this;
+ if (that.IsBottom || IsTop)
+ return that;
+
+ return this;
+ }
+
+ public bool LessEqual (SymGraph<TFunc, TADomain> that)
+ {
+ IImmutableMap<SymValue, LispList<SymValue>> forwardMap;
+ IImmutableMap<SymValue, SymValue> backwardMap;
+
+ return LessEqual (that, out forwardMap, out backwardMap);
+ }
+
+ public SymGraph<TFunc, TADomain> ImmutableVersion ()
+ {
+ MarkAsImmutable ();
+ return this;
+ }
+
+ public bool LessEqual (SymGraph<TFunc, TADomain> that,
+ out IImmutableMap<SymValue, LispList<SymValue>> forward,
+ out IImmutableMap<SymValue, SymValue> backward)
+ {
+ if (!IsSameEGraph (that))
+ return InternalLessEqual (this, that, out forward, out backward);
+
+ forward = null;
+ backward = null;
+ return true;
+ }
+ #endregion
+
+ public bool HasAllBottomFields (SymValue sv)
+ {
+ if (sv == null)
+ return false;
+
+ return this [sv].HasAllBottomFields;
+ }
+
+ public SymValue LookupOrManifest (TFunc function, SymValue arg, out bool fresh)
+ {
+ int oldCnt = IdGenerator;
+ SymValue result = this [function, arg];
+
+ fresh = oldCnt < IdGenerator;
+ return result;
+ }
+
+ public SymValue TryLookup (TFunc function, params SymValue[] args)
+ {
+ if (args.Length == 0 || args.Length == 1)
+ return LookupWithoutManifesting (this.const_root, function);
+ return LookupWithoutManifesting (args, function);
+ }
+
+ public SymValue LookupWithoutManifesting (SymValue sv, TFunc function)
+ {
+ if (sv == null)
+ return null;
+ sv = Find (sv);
+ SymValue result = TermMap [sv, function];
+
+ if (result == null)
+ return null;
+ return Find (result);
+ }
+
+ public SymValue LookupWithoutManifesting (SymValue[] args, TFunc function)
+ {
+ int length = args.Length;
+ for (int i = 0; i < length; i++)
+ args [i] = Find (args [i]);
+ return FindCandidate (args, function);
+ }
+
+ public SymValue LookupOrBottomPlaceHolder (SymValue arg, TFunc function, out bool isPlaceHolder)
+ {
+ SymValue result = LookupWithoutManifesting (arg, function);
+
+ isPlaceHolder = result == null;
+ return isPlaceHolder ? this.BottomPlaceHolder : result;
+ }
+
+ private SymValue Find (SymValue v)
+ {
+ SymValue forw = this.forw_map [v];
+ if (forw == null)
+ return v;
+
+ return Find (forw);
+ }
+
+ private bool IsOldSymbol (SymValue sv)
+ {
+ if (this.Parent == null)
+ return false;
+ return sv.UniqueId <= this.Parent.LastSymbolId;
+ }
+
+ private SymValue FindCandidate (SymValue[] args, TFunc function)
+ {
+ int length = args.Length;
+ var multiEdge = new MultiEdge<TFunc, TADomain> (function, 0, length);
+ for (LispList<SymValue> list = MultiEdgeMap [args [0], multiEdge]; list != null; list = list.Tail) {
+ SymGraphTerm<TFunc> term = EqualMultiTermsMap [list.Head];
+ if (term.Args.Length == length) {
+ bool found = true;
+
+ for (int i = 0; i < length; ++i) {
+ if (Find (term.Args [i]) != args [i]) {
+ found = false;
+ break;
+ }
+ }
+
+ if (found)
+ return list.Head;
+ }
+ }
+ return null;
+ }
+
+ private bool TryPushEquality (WorkList<EqualityPair<TFunc, TADomain>> workList, SymValue sv1, SymValue sv2)
+ {
+ if (sv1 != sv2) {
+ workList.Add (new EqualityPair<TFunc, TADomain> (sv1, sv2));
+ return true;
+ }
+
+ return false;
+ }
+
+ private void DrainEqualityWorkList (WorkList<EqualityPair<TFunc, TADomain>> workList)
+ {
+ while (!workList.IsEmpty ()) {
+ EqualityPair<TFunc, TADomain> equalityPair = workList.Pull ();
+ SymValue sv1 = Find (equalityPair.Sv1);
+ SymValue sv2 = Find (equalityPair.Sv2);
+ if (sv1 != sv2) {
+ if (sv1.UniqueId < sv2.UniqueId) {
+ SymValue tmp = sv1;
+ sv1 = sv2;
+ sv2 = tmp;
+ }
+
+ foreach (TFunc function in Functions (sv1)) {
+ SymValue v2 = LookupWithoutManifesting (sv2, function);
+ if (v2 == null)
+ this [sv2, function] = this [sv1, function];
+ else
+ TryPushEquality (workList, this [sv1, function], v2);
+ }
+ TADomain thisValue = this [sv1];
+ TADomain thatValue = this [sv2];
+ foreach (var elem in EqualTermsMap [sv1].AsEnumerable ())
+ EqualTermsMap = EqualTermsMap.Add (sv2, EqualTermsMap [sv2].Cons (elem));
+
+ this.forw_map = this.forw_map.Add (sv1, sv2);
+ this [sv2] = thisValue.Meet (thatValue);
+ }
+ }
+ }
+
+ private IEnumerable<MultiEdge<TFunc, TADomain>> MultiEdges (SymValue sv)
+ {
+ return MultiEdgeMap.Keys2 (Find (sv));
+ }
+
+ public IEnumerable<SymGraphTerm<TFunc>> EqMultiTerms (SymValue sv)
+ {
+ SymGraphTerm<TFunc> term = EqualMultiTermsMap [sv];
+ if (term.Args != null && IsValidMultiTerm (term))
+ yield return term;
+ }
+
+ public bool IsValidSymbol (SymValue sv)
+ {
+ return EqualTermsMap.ContainsKey (sv);
+ }
+
+ private bool IsValidMultiTerm (SymGraphTerm<TFunc> term)
+ {
+ return LookupWithoutManifesting (term.Args, term.Function) != null;
+ }
+
+ private static SymGraph<TFunc, TADomain> ComputeCommonTail (SymGraph<TFunc, TADomain> g1, SymGraph<TFunc, TADomain> g2, out int updateSize)
+ {
+ SymGraph<TFunc, TADomain> graph1 = g1;
+ SymGraph<TFunc, TADomain> graph2 = g2;
+ while (graph1 != graph2) {
+ if (graph1 == null)
+ break;
+ if (graph2 == null) {
+ graph1 = null;
+ break;
+ }
+ if (graph1.history_size > graph2.history_size)
+ graph1 = graph1.Parent;
+ else if (graph2.history_size > graph1.history_size)
+ graph2 = graph2.Parent;
+ else {
+ graph1 = graph1.Parent;
+ graph2 = graph2.Parent;
+ }
+ }
+ SymGraph<TFunc, TADomain> tail = graph1;
+ int historySize = tail != null ? tail.history_size : 0;
+ updateSize = g1.history_size + g2.history_size - 2*historySize;
+ return tail;
+ }
+
+ private static bool InternalLessEqual (SymGraph<TFunc, TADomain> thisG, SymGraph<TFunc, TADomain> thatG,
+ out IImmutableMap<SymValue, LispList<SymValue>> forward,
+ out IImmutableMap<SymValue, SymValue> backward)
+ {
+ int updateSize;
+ SymGraph<TFunc, TADomain> commonTail = ComputeCommonTail (thisG, thatG, out updateSize);
+ if (thisG.IsImmutable)
+ thisG = thisG.Clone ();
+
+ var workList = new WorkList<EqualityPair<TFunc, TADomain>> ();
+ workList.Add (new EqualityPair<TFunc, TADomain> (thisG.const_root, thatG.const_root));
+ IImmutableSet<SymValue> backwardManifested = ImmutableSet<SymValue>.Empty (SymValue.GetUniqueKey);
+ IImmutableMap<SymValue, SymValue> backwardMap = ImmutableIntKeyMap<SymValue, SymValue>.Empty (SymValue.GetUniqueKey);
+ IImmutableMap<SymValue, LispList<SymValue>> forwardMap = ImmutableIntKeyMap<SymValue, LispList<SymValue>>.Empty (SymValue.GetUniqueKey);
+ IImmutableMap<SymValue, int> triggers = ImmutableIntKeyMap<SymValue, int>.Empty (SymValue.GetUniqueKey);
+
+ while (!workList.IsEmpty ()) {
+ EqualityPair<TFunc, TADomain> equalityPair = workList.Pull ();
+ SymValue sv1 = equalityPair.Sv1;
+ SymValue sv2 = equalityPair.Sv2;
+
+ SymValue s;
+ if (VisitedBefore (sv2, backwardManifested, backwardMap, out s)) {
+ if (s != null && s == sv1)
+ continue;
+
+ if (DebugOptions.Debug)
+ Console.WriteLine ("---LessEqual fails due to pre-existing relation: {0} <- {1}", s, sv2);
+ forward = null;
+ backward = null;
+ return false;
+ }
+
+ TADomain val1 = sv1 == null ? thisG.UnderlyingTopValue.ForManifestedField () : thisG [sv1];
+ TADomain val2 = thatG [sv2];
+ if (!val1.LessEqual (val2)) {
+ if (DebugOptions.Debug)
+ Console.WriteLine ("---LessEqual fails due to abstract values: !({0} <= {1})", val1, val2);
+ forward = null;
+ backward = null;
+ return false;
+ }
+ if (sv1 != null) {
+ backwardMap = backwardMap.Add (sv2, sv1);
+ forwardMap = forwardMap.Add (sv1, forwardMap [sv1].Cons (sv2));
+ } else
+ backwardManifested = backwardManifested.Add (sv2);
+ if (thisG.HasAllBottomFields (sv1))
+ continue;
+ if (thatG.HasAllBottomFields (sv2)) {
+ if (DebugOptions.Debug)
+ {
+ Console.WriteLine ("---LessEqual fails due to bottom field difference");
+ }
+ forward = null;
+ backward = null;
+ return false;
+ }
+
+ foreach (TFunc function in thatG.Functions (sv2)) {
+ SymValue v1 = thisG [function, sv1];
+ SymValue v2 = thatG [function, sv2];
+ if (DebugOptions.Debug)
+ Console.WriteLine (" {0}-{1}->{2} <=? {3}-{4}->{5}", sv1, function, v1, sv2, function, v2);
+ workList.Add (new EqualityPair<TFunc, TADomain> (v1, v2));
+ }
+
+ foreach (var e in thatG.MultiEdges (sv2)) {
+ foreach (SymValue sv in thatG.MultiEdgeMap [sv2, e].AsEnumerable ()) {
+ if (!UpdateTrigger (sv, e, ref triggers))
+ continue;
+
+ SymGraphTerm<TFunc> term = thatG.EqualMultiTermsMap [sv];
+ var args = new SymValue[term.Args.Length];
+ for (int i = 0; i < args.Length; i++)
+ args [i] = backwardMap [term.Args [i]];
+
+ SymValue v1 = thisG.LookupWithoutManifesting (args, e.Function);
+ if (v1 == null) {
+ if (DebugOptions.Debug)
+ Console.WriteLine ("---LessEqual fails due to missing multi term {0}({1})",
+ e.Function,
+ string.Join (", ", term.Args.Select (it => it.ToString ())));
+ forward = null;
+ backward = null;
+ return false;
+ }
+
+ workList.Add (new EqualityPair<TFunc, TADomain> (v1, sv));
+ }
+ }
+ }
+ forward = forwardMap;
+ backward = CompleteWithCommon (backwardMap, thisG, commonTail.IdGenerator);
+ return true;
+ }
+
+ private static IImmutableMap<SymValue, SymValue> CompleteWithCommon (IImmutableMap<SymValue, SymValue> map,
+ SymGraph<TFunc, TADomain> thisGraph, int lastCommonId)
+ {
+ IEnumerable<SymValue> symValues = thisGraph.EqualTermsMap.Keys.Concat (thisGraph.EqualMultiTermsMap.Keys);
+ foreach (SymValue sv in symValues) {
+ if (IsCommon (sv, lastCommonId) && !map.ContainsKey (sv))
+ map = map.Add (sv, sv);
+ }
+ return map;
+ }
+
+ private static bool IsCommon (SymValue sv, int lastCommonId)
+ {
+ return sv.UniqueId <= lastCommonId;
+ }
+
+ private static bool UpdateTrigger (SymValue sv, MultiEdge<TFunc, TADomain> edge, ref IImmutableMap<SymValue, int> triggers)
+ {
+ int val = triggers [sv] + 1;
+ triggers = triggers.Add (sv, val);
+ return (val == edge.Arity);
+ }
+
+ private static bool VisitedBefore (SymValue sv2,
+ IImmutableSet<SymValue> backwardManifested,
+ IImmutableMap<SymValue, SymValue> backward,
+ out SymValue sv1)
+ {
+ sv1 = backward [sv2];
+ return sv1 != null || backwardManifested.Contains (sv2);
+ }
+
+ private bool IsSameEGraph (SymGraph<TFunc, TADomain> that)
+ {
+ if (this == that)
+ return true;
+ if (that.Parent == this)
+ return that.Updates == Updates;
+
+ return false;
+ }
+
+ private void MarkAsImmutable ()
+ {
+ this.is_immutable = true;
+ }
+
+ #region Merge updates
+ private void AddUpdate (Update<TFunc, TADomain> update)
+ {
+ Updates = Updates.Cons (update);
+ }
+
+ private void AddAbstractValueUpdate (SymValue sv)
+ {
+ if (!IsOldSymbol (sv))
+ return;
+ AddUpdate (new AbstractDomainUpdate<TFunc, TADomain> (sv));
+ }
+
+ private void AddEqualityUpdate (SymValue sv1, SymValue sv2)
+ {
+ if (!IsOldSymbol (sv1) || !IsOldSymbol (sv2))
+ return;
+ AddUpdate (new EqualityUpdate<TFunc, TADomain> (sv1, sv2));
+ }
+
+ private void AddEdgeUpdate (SymValue from, TFunc function)
+ {
+ if (!IsOldSymbol (from))
+ return;
+ AddUpdate (new EdgeUpdate<TFunc, TADomain> (from, function));
+ }
+
+ private void AddEliminateAllUpdate (SymValue from)
+ {
+ if (!IsOldSymbol (from))
+ return;
+ foreach (TFunc function in TermMap.Keys2 (from))
+ AddUpdate (new EliminateEdgeUpdate<TFunc, TADomain> (from, function));
+ }
+
+ private void AddEliminateEdgeUpdate (SymValue from, TFunc function)
+ {
+ if (!IsOldSymbol (from))
+ return;
+ AddUpdate (new EliminateEdgeUpdate<TFunc, TADomain> (from, function));
+ }
+
+ private void AddMultiEdgeUpdate (SymValue[] from, TFunc function)
+ {
+ for (int i = 0; i < from.Length; i++) {
+ if (!IsOldSymbol (from [i]))
+ return;
+ }
+
+ AddUpdate (new MultiEdgeUpdate<TFunc, TADomain> (from, function));
+ }
+ #endregion
+
+ public IImmutableMap<SymValue, LispList<SymValue>> GetForwardIdentityMap ()
+ {
+ var res = ImmutableIntKeyMap<SymValue, LispList<SymValue>>.Empty (SymValue.GetUniqueKey);
+ foreach (var sv in this.EqualTermsMap.Keys.Union (this.EqualMultiTermsMap.Keys)) {
+ res = res.Add (sv, LispList<SymValue>.Cons (sv, null));
+ }
+ return res;
+ }
+ }
+}
--- /dev/null
+//
+// SymGraphTerm.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Linq;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph {
+ struct SymGraphTerm<TFunc> : IEquatable<SymGraphTerm<TFunc>>
+ where TFunc : IEquatable<TFunc> {
+ public readonly SymValue[] Args;
+ public readonly TFunc Function;
+
+ public SymGraphTerm (TFunc function, params SymValue[] args)
+ {
+ this.Function = function;
+ this.Args = args;
+ }
+
+ public bool Equals (SymGraphTerm<TFunc> that)
+ {
+ if (!this.Function.Equals (that.Function) || this.Args.Length != that.Args.Length)
+ return false;
+
+ for (int i = 0; i < this.Args.Length; i++) {
+ if (!this.Args [i].Equals (that.Args [i]))
+ return false;
+ }
+ return true;
+ }
+
+ public override string ToString ()
+ {
+ var args = this.Args == null ? "<no args>" : string.Join (", ", this.Args.Select (a => a.ToString ()));
+ return string.Format ("Term({0}, {{{1}}})", this.Function, args);
+ }
+ }
+}
--- /dev/null
+//
+// Update.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph {
+ abstract class Update<TFunc, TAbstractDomain>
+ where TFunc : IEquatable<TFunc>, IConstantInfo
+ where TAbstractDomain : IAbstractDomainForEGraph<TAbstractDomain>, IEquatable<TAbstractDomain> {
+ public Update<TFunc, TAbstractDomain> Next { get; private set; }
+
+ public abstract void Replay (MergeInfo<TFunc, TAbstractDomain> merge);
+ public abstract void ReplayElimination (MergeInfo<TFunc, TAbstractDomain> merge);
+
+ public static Update<TFunc, TAbstractDomain> Reverse (LispList<Update<TFunc, TAbstractDomain>> updates,
+ LispList<Update<TFunc, TAbstractDomain>> common)
+ {
+ Update<TFunc, TAbstractDomain> last = null;
+ for (; updates != common; updates = updates.Tail) {
+ Update<TFunc, TAbstractDomain> head = updates.Head;
+ head.Next = last;
+ last = head;
+ }
+ return last;
+ }
+ }
+}
--- /dev/null
+//
+// AbstractType.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.Lattices;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis {
+ struct AbstractType : IAbstractDomainForEGraph<AbstractType>, IEquatable<AbstractType> {
+ public static AbstractType TopValue = new AbstractType (FlatDomain<TypeNode>.TopValue, false);
+ public static AbstractType BottomValue = new AbstractType (FlatDomain<TypeNode>.BottomValue, true);
+
+ private FlatDomain<TypeNode> value;
+
+ public AbstractType (FlatDomain<TypeNode> value, bool isZero) : this ()
+ {
+ IsZero = isZero;
+ this.value = value;
+ }
+
+ public bool IsZero { get; private set; }
+
+ public FlatDomain<TypeNode> Type
+ {
+ get { return this.value; }
+ }
+
+ public TypeNode ConcreteType
+ {
+ get { return this.value.Concrete; }
+ }
+
+ public bool IsNormal
+ {
+ get { return this.value.IsNormal; }
+ }
+
+ private static AbstractType ForManifestedFieldValue
+ {
+ get { return TopValue; }
+ }
+
+ public AbstractType ButZero
+ {
+ get { return new AbstractType (this.value, true); }
+ }
+ public AbstractType With (FlatDomain<TypeNode> type)
+ {
+ return new AbstractType (type, this.IsZero);
+ }
+
+ #region IAbstractDomainForEGraph<AbstractType> Members
+ public AbstractType Top
+ {
+ get { return new AbstractType (FlatDomain<TypeNode>.TopValue, false); }
+ }
+
+ public AbstractType Bottom
+ {
+ get { return new AbstractType (FlatDomain<TypeNode>.BottomValue, true); }
+ }
+
+ public bool IsTop
+ {
+ get { return !IsZero && this.value.IsTop; }
+ }
+
+ public bool IsBottom
+ {
+ get { return IsZero && this.value.IsBottom; }
+ }
+
+ public AbstractType Join (AbstractType that, bool widening, out bool weaker)
+ {
+ if (that.IsZero) {
+ weaker = false;
+ if (this.value.IsBottom)
+ return new AbstractType (that.value, IsZero);
+ return this;
+ }
+ if (IsZero) {
+ weaker = true;
+ if (that.value.IsBottom)
+ return new AbstractType (this.value, that.IsZero);
+ return that;
+ }
+
+ FlatDomain<TypeNode> resultType = this.value.Join (that.value, widening, out weaker);
+ return new AbstractType (resultType, false);
+ }
+
+ public AbstractType Meet (AbstractType that)
+ {
+ return new AbstractType (this.value.Meet (that.value), IsZero || that.IsZero);
+ }
+
+ public bool LessEqual (AbstractType that)
+ {
+ if (IsZero)
+ return true;
+ if (that.IsZero)
+ return false;
+
+ return this.value.LessEqual (that.value);
+ }
+
+ public AbstractType ImmutableVersion ()
+ {
+ return this;
+ }
+
+ public AbstractType Clone ()
+ {
+ return this;
+ }
+
+ public void Dump (TextWriter tw)
+ {
+ if (IsZero)
+ tw.Write ("(Zero) ");
+
+ this.value.Dump (tw);
+ }
+
+ public bool HasAllBottomFields
+ {
+ get { return IsZero; }
+ }
+
+ public AbstractType ForManifestedField ()
+ {
+ return ForManifestedFieldValue;
+ }
+ #endregion
+
+ #region IEquatable<AbstractType> Members
+ public bool Equals (AbstractType that)
+ {
+ return this.IsZero == that.IsZero && this.value.Equals (that.value);
+ }
+ #endregion
+
+ public override string ToString ()
+ {
+ return (IsZero ? "(Zero) " : "") + this.value;
+ }
+ }
+}
--- /dev/null
+//
+// AnalysisDecoder.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Lattices;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis {
+ struct AnalysisDecoder : IILVisitor<APC, int, int, Domain, Domain> {
+ private readonly HeapAnalysis parent;
+
+ public AnalysisDecoder (HeapAnalysis parent)
+ {
+ this.parent = parent;
+ }
+
+ public IContractProvider ContractProvider
+ {
+ get { return this.parent.ContractProvider; }
+ }
+
+ public IMetaDataProvider MetaDataProvider
+ {
+ get { return this.parent.MetaDataProvider; }
+ }
+ #region Helper Methods
+ private void UnaryEffect (UnaryOperator op, int dest, int source, Domain data)
+ {
+ switch (op)
+ {
+ case UnaryOperator.Conv_i:
+ data.AssignValueAndNullnessAtConv_IU (dest, source, false);
+ break;
+ case UnaryOperator.Conv_u:
+ data.AssignValueAndNullnessAtConv_IU (dest, source, true);
+ break;
+ case UnaryOperator.Not:
+ data.AssignSpecialUnary (dest, data.Functions.UnaryNot, source, MetaDataProvider.System_Int32);
+ break;
+ default:
+ data.AssignPureUnary (dest, op, data.UnaryResultType (op, data.CurrentType (source)), source);
+ break;
+ }
+ }
+
+ private Domain BinaryEffect (APC pc, BinaryOperator op, int dest, int op1, int op2, Domain data)
+ {
+ FlatDomain<TypeNode> resultType = data.BinaryResultType (op, data.CurrentType (op1), data.CurrentType (op2));
+ switch (op) {
+ case BinaryOperator.Ceq:
+ case BinaryOperator.Cobjeq:
+ {
+ SymValue srcValue = data.Value (op1);
+ if (data.IsZero (srcValue)) {
+ data.AssignSpecialUnary (dest, data.Functions.UnaryNot, op2, resultType);
+ break;
+ }
+ SymValue val2 = data.Value (op2);
+ if (data.IsZero (val2)) {
+ data.AssignSpecialUnary (dest, data.Functions.UnaryNot, op1, resultType);
+ break;
+ }
+ goto default;
+ }
+ case BinaryOperator.Cne_Un:
+ {
+ SymValue val1 = data.Value (op1);
+ if (data.IsZero (val1)) {
+ data.AssignSpecialUnary (dest, data.Functions.NeZero, op2, resultType);
+ break;
+ }
+ SymValue val2 = data.Value (op2);
+ if (data.IsZero (val2)) {
+ data.AssignSpecialUnary (dest, data.Functions.NeZero, op1, resultType);
+ break;
+ }
+ goto default;
+ }
+ default:
+ data.AssignPureBinary (dest, op, resultType, op1, op2);
+ break;
+ }
+
+ data.Havoc (2);
+ return data;
+ }
+
+ private void LoadArgEffect (Parameter argument, bool isOld, int dest, Domain data)
+ {
+ SymValue address = isOld ? data.OldValueAddress (argument) : data.Address (argument);
+ IMetaDataProvider metadataDecoder = MetaDataProvider;
+ data.CopyValue (data.Address (dest), address, metadataDecoder.ManagedPointer (metadataDecoder.ParameterType (argument)));
+ }
+
+ private void StoreLocalEffect (Local local, int source, Domain data)
+ {
+ data.CopyValue (data.Address (local), data.Address (source), MetaDataProvider.ManagedPointer (MetaDataProvider.LocalType (local)));
+ data.Havoc (source);
+ }
+
+ private void IsinstEffect (TypeNode type, int dest, Domain data)
+ {
+ data.AssignValue (dest, type);
+ }
+
+ private void LoadLocalEffect (Local local, int dest, Domain data)
+ {
+ data.CopyValue (data.Address (dest), data.Address (local), MetaDataProvider.ManagedPointer (MetaDataProvider.LocalType (local)));
+ }
+
+ private Domain AssumeEffect (APC pc, EdgeTag tag, int condition, Domain data)
+ {
+ data = data.Assume (condition, tag != EdgeTag.False);
+ if (!data.IsBottom)
+ data.Havoc (condition);
+
+ return data;
+ }
+
+ private Domain AssertEffect (APC pc, EdgeTag tag, int condition, Domain data)
+ {
+ data = data.Assume (condition, true);
+ if (!data.IsBottom)
+ data.Havoc (condition);
+
+ return data;
+ }
+
+ private static void LoadStackAddressEffect (APC pc, int offset, int dest, int source, Domain data)
+ {
+ data.CopyStackAddress (data.Address (dest), source);
+ }
+
+ private Domain CallEffect<TypeList, ArgList> (APC pc, Method method, bool virt, TypeList extraVarargs, int dest, ArgList args, Domain data, TypeNode constraint, bool constrainedCall)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<int>
+ {
+ TypeNode t = constraint;
+ if (!pc.InsideContract)
+ data.ResetModifiedAtCall ();
+
+ IImmutableMap<TypeNode, TypeNode> instantiationMap = ComputeTypeInstantiationMap (pc, method);
+ bool derefThis = false;
+ if (virt)
+ {
+ if (MetaDataProvider.IsStruct (constraint))
+ DevirtualizeImplementingMethod (constraint, ref method);
+ else
+ {
+ if (constrainedCall && MetaDataProvider.IsReferenceType (Specialize (instantiationMap, constraint)))
+ derefThis = true;
+ SymValue loc = data.Value (args[0]);
+ if (derefThis)
+ loc = data.Value (loc);
+ AbstractType aType = data.GetType (loc);
+ if (aType.IsNormal)
+ DevirtualizeImplementingMethod (aType.ConcreteType, ref method);
+ }
+ }
+ string name = MetaDataProvider.Name (method);
+ if (args.Count > 0)
+ {
+ if ((MetaDataProvider.Equal (t, MetaDataProvider.System_String) || MetaDataProvider.Equal (t, MetaDataProvider.System_Array))
+ && (name == "get_Length" || name == "get_LongLength"))
+ {
+ data.AssignArrayLength (data.Address (dest), data.Value (args[0]));
+ return data;
+ }
+ if (MetaDataProvider.Equal (t, MetaDataProvider.System_Object) && name == "MemberwiseClone")
+ {
+ TypeNode t2 = data.GetType (data.Value (args[0])).ConcreteType;
+ SymValue obj = data.CreateObject (t2);
+ data.CopyStructValue (obj, data.Value (args[0]), t2);
+ data.CopyAddress (data.Address (dest), obj, t2);
+ return data;
+ }
+ if (args.Count > 1 && MetaDataProvider.IsReferenceType (t))
+ {
+ if (name.EndsWith ("op_Inequality"))
+ return Binary (pc, BinaryOperator.Cne_Un, dest, args[0], args[1], data);
+ if (name.EndsWith ("op_Equality"))
+ return Binary (pc, BinaryOperator.Cobjeq, dest, args[0], args[1], data);
+ }
+ if (MetaDataProvider.Equal (t, MetaDataProvider.System_IntPtr) && name.StartsWith ("op_Explicit"))
+ {
+ data.Copy (dest, args[0]);
+ return data;
+ }
+ }
+ //todo:
+ // if (extraVarargs.Count == 0 && !this.MetaDataProvider.IsVoidMethod(method) && this.ContractProvider.)
+
+ {
+ Property property;
+ if (MetaDataProvider.IsPropertySetter (method, out property))
+ {
+ if (args.Count <= 2)
+ {
+ Method getter;
+ if (MetaDataProvider.HasGetter (property, out getter))
+ {
+ SymValue obj;
+ SymValue srcAddr;
+ if (args.Count == 1)
+ {
+ obj = data.Globals;
+ srcAddr = data.Address (args[0]);
+ }
+ else
+ {
+ obj = data.Value (args[0]);
+ if (derefThis)
+ obj = data.Value (obj);
+ srcAddr = data.Address (args[1]);
+ }
+ if (MetaDataProvider.Equal (MetaDataProvider.DeclaringType (this.parent.CurrentMethod), MetaDataProvider.Unspecialized (MetaDataProvider.DeclaringType (method))))
+ {
+ data.HavocUp (obj, ref data.ModifiedAtCall, false);
+
+ if (MetaDataProvider.IsAutoPropertyMember (method))
+ {
+ foreach (Field f in this.parent.StackContextProvider.MethodContext.Modifies (method))
+ {
+ TypeNode fieldAddressType;
+ SymValue destAddr = data.FieldAddress (obj, f, out fieldAddressType);
+ data.CopyValue (destAddr, srcAddr, fieldAddressType);
+ }
+ }
+ else
+ data.HavocFields (obj, this.parent.StackContextProvider.MethodContext.Modifies (method), ref data.ModifiedAtCall);
+ }
+ TypeNode pseudoFieldAddressType;
+ SymValue destAddr1 = data.PseudoFieldAddress (obj, getter, out pseudoFieldAddressType, true);
+ data.CopyValue (destAddr1, srcAddr, pseudoFieldAddressType);
+ data.AssignValue (dest, MetaDataProvider.System_Void);
+ return data;
+ }
+ }
+ else
+ {
+ Method getter;
+ if (MetaDataProvider.HasGetter (property, out getter))
+ {
+ var args1 = new SymValue[GetNonOutArgs (method) - 1];
+ int num = 0;
+ for (int i = 0; i < args.Count - 1; i++)
+ {
+ bool isOut;
+ SymValue sv = KeyForPureFunctionArgument (method, i, args[i], data, instantiationMap, out isOut);
+ if (!isOut)
+ args1[num++] = sv;
+ }
+ SymValue thisSV = data.Value (args[0]);
+ if (derefThis)
+ thisSV = data.Value (thisSV);
+ TypeNode pseudoFieldAddressType;
+ SymValue pseudoField = data.PseudoFieldAddress (args1, getter, out pseudoFieldAddressType, false);
+ AssignAllOutParameters (data, pseudoField, method, args);
+ SymValue srcAddr = data.Address (args[args.Count - 1]);
+ data.CopyValue (pseudoField, srcAddr, pseudoFieldAddressType);
+ if (MetaDataProvider.Equal (MetaDataProvider.DeclaringType (this.parent.CurrentMethod), MetaDataProvider.Unspecialized (MetaDataProvider.DeclaringType (method))))
+ {
+ data.HavocUp (thisSV, ref data.ModifiedAtCall, false);
+ data.HavocFields (thisSV, this.parent.StackContextProvider.MethodContext.Modifies (method), ref data.ModifiedAtCall);
+ }
+ }
+ data.AssignValue (dest, MetaDataProvider.System_Void);
+ return data;
+ }
+ }
+ bool insideConstructor = MetaDataProvider.IsConstructor (method);
+ HavocParameters (pc, method, extraVarargs, args, data, constraint, insideConstructor, false, derefThis);
+ data.AssignReturnValue (dest, MetaDataProvider.ReturnType (method));
+ return data;
+ }
+ }
+
+ private static Domain DoWithBothDomains (Domain data, Func<Domain, Domain> action)
+ {
+ data = action (data);
+ if (data.OldDomain != null)
+ data.OldDomain = action (data.OldDomain);
+ return data;
+ }
+
+ private static Domain DoWithBothDomains (Domain data, Action<Domain> action)
+ {
+ action (data);
+ if (data.OldDomain != null)
+ action (data.OldDomain);
+ return data;
+ }
+ #endregion
+
+ #region IILVisitor<APC,int,int,Domain,Domain> Members
+ public Domain Binary (APC pc, BinaryOperator op, int dest, int operand1, int operand2, Domain data)
+ {
+ AnalysisDecoder it = this;
+ return DoWithBothDomains (data, d => it.BinaryEffect (pc, op, dest, operand1, operand2, d));
+ }
+
+ public Domain Isinst (APC pc, TypeNode type, int dest, int obj, Domain data)
+ {
+ AnalysisDecoder it = this;
+ return DoWithBothDomains (data, d => it.IsinstEffect (type, dest, d));
+ }
+
+ public Domain LoadNull (APC pc, int dest, Domain polarity)
+ {
+ return DoWithBothDomains (polarity, d => d.AssignNull (dest));
+ }
+
+ public Domain LoadConst (APC pc, TypeNode type, object constant, int dest, Domain data)
+ {
+ return DoWithBothDomains (data, d => d.AssignConst (dest, type, constant));
+ }
+
+ public Domain Sizeof (APC pc, TypeNode type, int dest, Domain data)
+ {
+ AnalysisDecoder it = this;
+ return DoWithBothDomains (data, d => d.AssignValue (dest, it.MetaDataProvider.System_Int32));
+ }
+
+ public Domain Unary (APC pc, UnaryOperator op, bool unsigned, int dest, int source, Domain data)
+ {
+ AnalysisDecoder it = this;
+ return DoWithBothDomains (data, d => it.UnaryEffect (op, dest, source, d));
+ }
+
+ public Domain Entry (APC pc, Method method, Domain data)
+ {
+ IIndexable<Local> locals = MetaDataProvider.Locals (method);
+ for (int i = 0; i < locals.Count; i++)
+ MaterializeLocal (locals [i], method, data);
+
+ TypeNode declaringType = MetaDataProvider.DeclaringType (method);
+ IIndexable<Parameter> parameters = MetaDataProvider.Parameters (method);
+ for (int i = 0; i < parameters.Count; i++)
+ MaterializeParameter (parameters [i], declaringType, data, false);
+
+ if (!MetaDataProvider.IsStatic (method))
+ MaterializeParameter (MetaDataProvider.This (method), declaringType, data, true);
+
+ if (MetaDataProvider.IsConstructor (method)) {
+ Parameter p = MetaDataProvider.This (method);
+ SymValue ptr = data.Value (p);
+
+ foreach (Field field in MetaDataProvider.Fields (declaringType)) {
+ if (MetaDataProvider.IsStatic (field))
+ continue;
+
+ TypeNode fieldType = MetaDataProvider.FieldType (field);
+ if (MetaDataProvider.IsStruct (fieldType))
+ data.AssignConst (data.FieldAddress (ptr, field), fieldType, 0);
+ else
+ data.AssignNull (data.FieldAddress (ptr, field));
+ }
+
+ foreach (Property property in MetaDataProvider.Properties (declaringType)) {
+ Method getter;
+ if (!MetaDataProvider.IsStatic (property) && MetaDataProvider.HasGetter (property, out getter)
+ && MetaDataProvider.IsCompilerGenerated (getter) && MetaDataProvider.Parameters (getter).Count == 0) {
+ TypeNode propertyType = MetaDataProvider.ReturnType (getter);
+ if (MetaDataProvider.IsStruct (propertyType))
+ data.AssignConst (data.PseudoFieldAddress (ptr, getter), propertyType, 0);
+ else
+ data.AssignNull (data.PseudoFieldAddress (ptr, getter));
+ }
+ }
+ }
+
+ return data;
+ }
+
+ public Domain Assume (APC pc, EdgeTag tag, int condition, Domain data)
+ {
+ AnalysisDecoder it = this;
+ return DoWithBothDomains (data, d => it.AssumeEffect (pc, tag, condition, data));
+ }
+
+ public Domain Assert (APC pc, EdgeTag tag, int condition, Domain data)
+ {
+ AnalysisDecoder it = this;
+ return DoWithBothDomains (data, d => it.AssertEffect (pc, tag, condition, data));
+ }
+
+ public Domain BeginOld (APC pc, APC matchingEnd, Domain data)
+ {
+ if (data.InsideOld++ == 0) {
+ Domain oldState = FindOldState (pc, data);
+ if (oldState == null)
+ throw new InvalidOperationException ("begin_old in weird calling context");
+ Domain domain = oldState.Clone ();
+ domain.BeginOldPC = pc;
+ data.OldDomain = domain;
+ }
+
+ return data;
+ }
+
+ public Domain EndOld (APC pc, APC matchingBegin, TypeNode type, int dest, int source, Domain data)
+ {
+ if (--data.InsideOld == 0)
+ data.OldDomain = null;
+
+ data.Copy (dest, source);
+ return data;
+ }
+
+ public Domain LoadStack (APC pc, int offset, int dest, int source, bool isOld, Domain data)
+ {
+ if (isOld) {
+ Domain oldState = FindOldState (pc, data);
+ oldState.CopyOldValue (pc, dest, source, data, false);
+ if (data.OldDomain != null)
+ oldState.CopyOldValue (pc, dest, source, data.OldDomain, false);
+ } else {
+ data.Copy (dest, source);
+ if (data.OldDomain != null)
+ data.OldDomain.Copy (dest, source);
+ }
+
+ return data;
+ }
+
+ public Domain LoadStackAddress (APC pc, int offset, int dest, int source, TypeNode type, bool isOld, Domain data)
+ {
+ if (isOld) {
+ TypeNode ptrType = MetaDataProvider.ManagedPointer (type);
+ Domain oldState = FindOldState (pc, data);
+ SymValue srcOldAddr = oldState.Address (source);
+ SymValue sv = data.CreateValue (type);
+
+ oldState.CopyOldValue (pc, sv, srcOldAddr, data, true);
+ data.CopyAddress (data.Address (dest), sv, ptrType);
+ if (data.OldDomain != null) {
+ TypeNode ptrPtrType = MetaDataProvider.ManagedPointer (ptrType);
+ oldState.CopyOldValueToDest (pc, data.OldDomain.Address (dest), srcOldAddr, ptrPtrType, data.OldDomain);
+ }
+ } else {
+ LoadStackAddressEffect (pc, offset, dest, source, data);
+ if (data.OldDomain != null)
+ LoadStackAddressEffect (pc, offset, dest, source, data.OldDomain);
+ }
+ return data;
+ }
+
+ public Domain LoadResult (APC pc, TypeNode type, int dest, int source, Domain data)
+ {
+ return DoWithBothDomains (data, d => d.Copy (dest, source));
+ }
+
+ public Domain Arglist (APC pc, int dest, Domain data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Domain Branch (APC pc, APC target, bool leavesExceptionBlock, Domain data)
+ {
+ throw new InvalidOperationException ("Should not see branches, should see assumes. See APCDecoder");
+ }
+
+ public Domain BranchCond (APC pc, APC target, BranchOperator bop, int value1, int value2, Domain data)
+ {
+ throw new InvalidOperationException ("Should not see branches, should see assumes. See APCDecoder");
+ }
+
+ public Domain BranchTrue (APC pc, APC target, int cond, Domain data)
+ {
+ throw new InvalidOperationException ("Should not see branches, should see assumes. See APCDecoder");
+ }
+
+ public Domain BranchFalse (APC pc, APC target, int cond, Domain data)
+ {
+ throw new InvalidOperationException ("Should not see branches, should see assumes. See APCDecoder");
+ }
+
+ public Domain Break (APC pc, Domain data)
+ {
+ return data;
+ }
+
+ public Domain Call<TypeList, ArgList> (APC pc, Method method, bool virt, TypeList extraVarargs, int dest, ArgList args, Domain data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<int>
+ {
+ TypeNode declaringType = MetaDataProvider.DeclaringType (method);
+ if (data.OldDomain == null)
+ return CallEffect (pc, method, virt, extraVarargs, dest, args, data, declaringType, false);
+ data.OldDomain = CallEffect (pc, method, virt, extraVarargs, dest, args, data.OldDomain, declaringType, false);
+ if (!MetaDataProvider.IsVoidMethod (method))
+ data.OldDomain.CopyOldValue (data.OldDomain.BeginOldPC, dest, dest, data, true);
+ return data;
+ }
+
+ public Domain Calli<TypeList, ArgList> (APC pc, TypeNode returnType, TypeList argTypes, bool instance, int dest, int functionPointer, ArgList args, Domain data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<int>
+ {
+ if (data.OldDomain == null)
+ return CalliEffect (pc, returnType, argTypes, instance, dest, functionPointer, args, data);
+ data.OldDomain = CalliEffect (pc, returnType, argTypes, instance, dest, functionPointer, args, data.OldDomain);
+ if (!MetaDataProvider.IsVoid (returnType))
+ data.OldDomain.CopyOldValue (data.OldDomain.BeginOldPC, dest, dest, data, true);
+ return data;
+ }
+
+ public Domain CheckFinite (APC pc, int dest, int source, Domain data)
+ {
+ data.Copy (dest, source);
+ if (data.OldDomain != null)
+ data.OldDomain.Copy (dest, source);
+
+ return data;
+ }
+
+ public Domain CopyBlock (APC pc, int destAddress, int srcAddress, int len, Domain data)
+ {
+ data.Havoc (destAddress);
+ data.Havoc (srcAddress);
+ data.Havoc (len);
+
+ return data;
+ }
+
+ public Domain EndFilter (APC pc, int decision, Domain data)
+ {
+ data.Havoc (decision);
+
+ return data;
+ }
+
+ public Domain EndFinally (APC pc, Domain data)
+ {
+ return data;
+ }
+
+ public Domain Jmp (APC pc, Method method, Domain data)
+ {
+ return data;
+ }
+
+ public Domain LoadArg (APC pc, Parameter argument, bool isOld, int dest, Domain data)
+ {
+ LoadArgEffect (argument, isOld, dest, data);
+ if (data.OldDomain != null)
+ LoadArgEffect (argument, isOld, dest, data.OldDomain);
+
+ return data;
+ }
+
+ public Domain LoadArgAddress (APC pc, Parameter argument, bool isOld, int dest, Domain data)
+ {
+ LoadArgAddressEffect (argument, isOld, dest, data);
+ if (data.OldDomain != null)
+ LoadArgAddressEffect (argument, isOld, dest, data.OldDomain);
+ return data;
+ }
+
+ public Domain LoadLocal (APC pc, Local local, int dest, Domain data)
+ {
+ LoadLocalEffect (local, dest, data);
+ if (data.OldDomain != null)
+ data.CopyValueToOldState (data.OldDomain.BeginOldPC, MetaDataProvider.LocalType (local), dest, dest, data.OldDomain);
+
+ return data;
+ }
+
+ public Domain LoadLocalAddress (APC pc, Local local, int dest, Domain data)
+ {
+ LoadLocalAddressEffect (local, dest, data);
+ if (data.OldDomain != null)
+ LoadLocalAddressEffect (local, dest, data.OldDomain);
+
+ return data;
+ }
+
+ public Domain Nop (APC pc, Domain data)
+ {
+ return data;
+ }
+
+ public Domain Pop (APC pc, int source, Domain data)
+ {
+ data.Havoc (source);
+ if (data.OldDomain != null)
+ data.OldDomain.Havoc (source);
+
+ return data;
+ }
+
+ public Domain Return (APC pc, int source, Domain data)
+ {
+ data.Havoc (source);
+
+ return data;
+ }
+
+ public Domain StoreArg (APC pc, Parameter argument, int source, Domain data)
+ {
+ data.CopyValue (data.Address (argument), data.Address (source), MetaDataProvider.ManagedPointer (MetaDataProvider.ParameterType (argument)));
+ data.Havoc (source);
+
+ return data;
+ }
+
+ public Domain StoreLocal (APC pc, Local local, int source, Domain data)
+ {
+ AnalysisDecoder it = this;
+ return DoWithBothDomains (data, d => it.StoreLocalEffect (local, source, d));
+ }
+
+ public Domain Switch (APC pc, TypeNode type, IEnumerable<Pair<object, APC>> cases, int value, Domain data)
+ {
+ throw new InvalidOperationException ("Should only see assumes");
+ }
+
+ public Domain Box (APC pc, TypeNode type, int dest, int source, Domain data)
+ {
+ AnalysisDecoder it = this;
+ return DoWithBothDomains (data, (d) => it.BoxEffect (type, dest, source, d));
+ }
+
+ public Domain ConstrainedCallvirt<TypeList, ArgList> (APC pc, Method method, TypeNode constraint, TypeList extraVarargs, int dest, ArgList args, Domain data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<int>
+ {
+ if (data.OldDomain == null)
+ return CallEffect (pc, method, true, extraVarargs, dest, args, data, constraint, true);
+
+ data.OldDomain = CallEffect (pc, method, true, extraVarargs, dest, args, data.OldDomain, constraint, true);
+ if (!MetaDataProvider.IsVoidMethod (method))
+ data.OldDomain.CopyOldValue (data.OldDomain.BeginOldPC, dest, dest, data, true);
+ return data;
+ }
+
+ public Domain CastClass (APC pc, TypeNode type, int dest, int obj, Domain data)
+ {
+ AnalysisDecoder it = this;
+ return DoWithBothDomains (data, d => it.CastClassEffect (type, dest, obj, d));
+ }
+
+ public Domain CopyObj (APC pc, TypeNode type, int destPtr, int sourcePtr, Domain data)
+ {
+ data.CopyValue (data.Value (destPtr), data.Value (sourcePtr), MetaDataProvider.ManagedPointer (type));
+ data.Havoc (destPtr);
+ data.Havoc (sourcePtr);
+ return data;
+ }
+
+ public Domain Initobj (APC pc, TypeNode type, int ptr, Domain data)
+ {
+ SymValue obj = data.Value (ptr);
+ data.Havoc (obj);
+ foreach (Field field in MetaDataProvider.Fields (type)) {
+ SymValue dest = data.FieldAddress (obj, field);
+ data.AssignZeroEquivalent (dest, MetaDataProvider.FieldType (field));
+ }
+ data.Havoc (ptr);
+ return data;
+ }
+
+ public Domain LoadElement (APC pc, TypeNode type, int dest, int array, int index, Domain data)
+ {
+ if (data.OldDomain != null) {
+ LoadElementEffect (type, dest, array, index, data.OldDomain);
+ data.OldDomain.CopyOldValue (data.OldDomain.BeginOldPC, dest, dest, data, true);
+ } else
+ LoadElementEffect (type, dest, array, index, data);
+
+ return data;
+ }
+
+ public Domain LoadField (APC pc, Field field, int dest, int obj, Domain data)
+ {
+ if (data.OldDomain != null) {
+ LoadFieldEffect (field, dest, obj, data.OldDomain);
+ data.OldDomain.CopyOldValue (data.OldDomain.BeginOldPC, dest, dest, data, true);
+ } else
+ LoadFieldEffect (field, dest, obj, data);
+
+ return data;
+ }
+
+ public Domain LoadFieldAddress (APC pc, Field field, int dest, int obj, Domain data)
+ {
+ AnalysisDecoder it = this;
+ return DoWithBothDomains (data, domain => it.LoadFieldAddressEffect (pc, field, dest, obj, domain));
+ }
+
+ public Domain LoadLength (APC pc, int dest, int array, Domain data)
+ {
+ AnalysisDecoder it = this;
+ return DoWithBothDomains (data, domain => it.LoadLengthEffect (dest, array, domain));
+ }
+
+ public Domain LoadStaticField (APC pc, Field field, int dest, Domain data)
+ {
+ if (data.OldDomain != null) {
+ LoadStaticFieldEffect (field, dest, data.OldDomain);
+ data.OldDomain.CopyOldValue (data.OldDomain.BeginOldPC, dest, dest, data, true);
+ } else
+ LoadStaticFieldEffect (field, dest, data);
+ return data;
+ }
+
+ public Domain LoadStaticFieldAddress (APC pc, Field field, int dest, Domain data)
+ {
+ AnalysisDecoder it = this;
+ return DoWithBothDomains (data, domain => it.LoadStaticFieldAddressEffect (field, dest, domain));
+ }
+
+ public Domain LoadTypeToken (APC pc, TypeNode type, int dest, Domain data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Domain LoadFieldToken (APC pc, Field type, int dest, Domain data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Domain LoadMethodToken (APC pc, Method type, int dest, Domain data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Domain NewArray<ArgList> (APC pc, TypeNode type, int dest, ArgList lengths, Domain data) where ArgList : IIndexable<int>
+ {
+ AnalysisDecoder it = this;
+ return DoWithBothDomains (data, d => it.NewArrayEffect<ArgList> (type, dest, lengths, d));
+ }
+
+ public Domain NewObj<ArgList> (APC pc, Method ctor, int dest, ArgList args, Domain data) where ArgList : IIndexable<int>
+ {
+ AnalysisDecoder it = this;
+ return DoWithBothDomains (data, d => it.NewObjEffect (pc, ctor, dest, args, d));
+ }
+
+ public Domain MkRefAny (APC pc, TypeNode type, int dest, int obj, Domain data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Domain RefAnyType (APC pc, int dest, int source, Domain data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Domain RefAnyVal (APC pc, TypeNode type, int dest, int source, Domain data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Domain Rethrow (APC pc, Domain data)
+ {
+ return data.Bottom;
+ }
+
+ public Domain StoreElement (APC pc, TypeNode type, int array, int index, int value, Domain data)
+ {
+ AnalysisDecoder it = this;
+ return DoWithBothDomains (data, d => it.StoreElementEffect (type, array, index, value, d));
+ }
+
+ public Domain StoreField (APC pc, Field field, int obj, int value, Domain data)
+ {
+ data.CopyValue (data.FieldAddress (data.Value (obj), field), data.Address (value));
+ if (!MetaDataProvider.IsCompilerGenerated (field))
+ data.HavocPseudoFields (data.Value (obj));
+ data.Havoc (obj);
+ data.Havoc (value);
+ return data;
+ }
+
+ public Domain StoreStaticField (APC pc, Field field, int value, Domain data)
+ {
+ data.CopyValue (data.FieldAddress (data.Globals, field), data.Address (value));
+ data.Havoc (value);
+ return data;
+ }
+
+ public Domain Throw (APC pc, int exception, Domain data)
+ {
+ data.Havoc (exception);
+ return data;
+ }
+
+ public Domain Unbox (APC pc, TypeNode type, int dest, int obj, Domain data)
+ {
+ AnalysisDecoder it = this;
+ return DoWithBothDomains (data, d => d.AssignValue (dest, it.MetaDataProvider.ManagedPointer (type)));
+ }
+
+ public Domain UnboxAny (APC pc, TypeNode type, int dest, int obj, Domain data)
+ {
+ return DoWithBothDomains (data, d => d.AssignValue (dest, type));
+ }
+ #endregion
+
+ private void MaterializeParameter (Parameter parameter, TypeNode declaringType, Domain data, bool aggressiveMaterialization)
+ {
+ TypeNode type = MetaDataProvider.ParameterType (parameter);
+ data.Assign (parameter, type);
+ MaterializeParameterInfo (data.Address (parameter), MetaDataProvider.ManagedPointer (type), 0, data, declaringType, aggressiveMaterialization);
+ data.CopyParameterIntoShadow (parameter);
+ }
+
+ private void MaterializeParameterInfo (SymValue sv, TypeNode t, int depth, Domain data, TypeNode fromType, bool aggressiveMaterialization)
+ {
+ data.MakeUnmodified (sv);
+ data.SetType (sv, t);
+ if (depth > 2 && !aggressiveMaterialization || depth > 5)
+ return;
+ if (MetaDataProvider.IsManagedPointer (t)) {
+ TypeNode elemType = MetaDataProvider.ElementType (t);
+ if (!MetaDataProvider.HasValueRepresentation (elemType)) {
+ data.ManifestStructId (sv);
+ foreach (Field field in MetaDataProvider.Fields (elemType)) {
+ if (!MetaDataProvider.IsStatic (field) && MetaDataProvider.IsVisibleFrom (field, fromType)) {
+ TypeNode fieldAddressType;
+ MaterializeParameterInfo (data.FieldAddress (sv, field, out fieldAddressType), fieldAddressType, depth + 1, data, fromType, aggressiveMaterialization);
+ }
+ }
+ ManifestProperties (sv, depth + 1, data, fromType, aggressiveMaterialization, elemType);
+ } else
+ MaterializeParameterInfo (data.Value (sv), elemType, depth + 1, data, fromType, aggressiveMaterialization);
+ } else {
+ if (MetaDataProvider.IsClass (t)) {
+ foreach (Field field in MetaDataProvider.Fields (t)) {
+ if (!MetaDataProvider.IsStatic (field) && MetaDataProvider.IsVisibleFrom (field, fromType)) {
+ TypeNode fieldAddressType;
+ MaterializeParameterInfo (data.FieldAddress (sv, field, out fieldAddressType), fieldAddressType, depth + 1, data, fromType, aggressiveMaterialization);
+ }
+ }
+ } else if (data.NeedsArrayLengthManifested (t))
+ data.ManifestArrayLength (sv);
+ }
+ }
+
+ private void ManifestProperties (SymValue sv, int depth, Domain data, TypeNode fromType, bool aggressiveMaterialization, TypeNode type)
+ {
+ foreach (Property property in MetaDataProvider.Properties (type)) {
+ Method getter;
+ if (MetaDataProvider.IsStatic (property) || !MetaDataProvider.HasGetter (property, out getter) || !MetaDataProvider.IsVisibleFrom (getter, fromType))
+ continue;
+
+ TypeNode pseudoFieldAddressType;
+ MaterializeParameterInfo (data.PseudoFieldAddress (sv, getter, out pseudoFieldAddressType, false), pseudoFieldAddressType, depth + 1, data, fromType, aggressiveMaterialization);
+ }
+
+ if (!MetaDataProvider.IsInterface (type))
+ return;
+
+ foreach (TypeNode iface in MetaDataProvider.Interfaces (type)) {
+ if (MetaDataProvider.IsVisibleFrom (iface, fromType))
+ ManifestProperties (sv, depth, data, fromType, aggressiveMaterialization, iface);
+ }
+ }
+
+ private void MaterializeLocal (Local local, Method method, Domain data)
+ {
+ TypeNode t = MetaDataProvider.LocalType (local);
+ data.AssignZeroEquivalent (data.Address (local), t);
+ }
+
+ private void HavocParameters (APC pc, Method method, IIndexable<TypeNode> extraVarargs, IIndexable<int> args, Domain data, TypeNode declaringType, bool insideConstructor, bool thisArgMissing,
+ bool derefThis)
+ {
+ IIndexable<Parameter> parameters = MetaDataProvider.Parameters (method);
+ IIndexable<Parameter> unspecializedParameters = null;
+ if (MetaDataProvider.IsSpecialized (method))
+ unspecializedParameters = MetaDataProvider.Parameters (MetaDataProvider.Unspecialized (method));
+ int index2 = 0;
+ int num1 = 0;
+ for (int index1 = 0; index1 < args.Count; ++index1) {
+ bool materialize = false;
+ bool nonFirstThis = false;
+ int num2 = args [index1];
+ bool parameterHasGenericType = false;
+ bool havocReadonlyFields = false;
+ TypeNode ype;
+
+ if (index1 == 0 && !thisArgMissing && !MetaDataProvider.IsStatic (method)) {
+ num1 = 1;
+ ype = MetaDataProvider.ParameterType (MetaDataProvider.This (method));
+ if (MetaDataProvider.IsPrimitive (declaringType) || MetaDataProvider.Equal (declaringType, MetaDataProvider.System_Object)) {
+ if (MetaDataProvider.IsStruct (declaringType))
+ data.Value (data.Value (args [0]));
+ continue;
+ }
+ if (MetaDataProvider.IsConstructor (method)) {
+ if (insideConstructor && data.IsThis (this.parent.CurrentMethod, num2)) {
+ if (TypesEqualModuloInstantiation (declaringType, MetaDataProvider.DeclaringType (this.parent.CurrentMethod)))
+ havocReadonlyFields = true;
+ else
+ continue;
+ }
+ if (MetaDataProvider.IsStruct (declaringType))
+ materialize = true;
+ }
+ } else if (index2 < parameters.Count) {
+ if (data.IsThis (this.parent.CurrentMethod, num2))
+ nonFirstThis = true;
+ Parameter p = parameters [index2];
+ materialize = MetaDataProvider.IsOut (p);
+ ype = MetaDataProvider.ParameterType (p);
+ if (unspecializedParameters != null) {
+ TypeNode unspecType = MetaDataProvider.ParameterType (unspecializedParameters [index2]);
+ parameterHasGenericType = MetaDataProvider.IsFormalTypeParameter (unspecType) || MetaDataProvider.IsMethodFormalTypeParameter (unspecType);
+ }
+ ++index2;
+ } else if (!data.IsThis (this.parent.CurrentMethod, num2))
+ ype = extraVarargs [index1 - index2 - num1];
+ else
+ continue;
+ if (!pc.InsideContract) {
+ bool havocFields = AggressiveUpHavocMethod (method);
+ if (havocFields || materialize || MustHavocParameter (method, declaringType, ype, parameterHasGenericType, nonFirstThis)) {
+ SymValue loc = data.Value (num2);
+ if (derefThis && index1 == 0 && num1 == 1)
+ loc = data.Value (loc);
+ data.HavocObjectAtCall (loc, ref data.ModifiedAtCall, havocFields, havocReadonlyFields);
+ if (materialize)
+ data.MaterializeAccordingToType (loc, ype, 0);
+ }
+ }
+ data.Havoc (num2);
+ }
+ }
+
+ private bool MustHavocParameter (Method method, TypeNode declaringType, TypeNode pt, bool parameterHasGenericType, bool nonFirstThis)
+ {
+ if (parameterHasGenericType || MetaDataProvider.IsStruct (pt) || MetaDataProvider.Equal (declaringType, MetaDataProvider.System_Object) ||
+ IsImmutable (pt) || nonFirstThis || MetaDataProvider.Equal (pt, MetaDataProvider.System_Object))
+ return false;
+
+ return true;
+ }
+
+ private bool IsImmutable (TypeNode pt)
+ {
+ return MetaDataProvider.Equal (pt, MetaDataProvider.System_String);
+ }
+
+ private bool AggressiveUpHavocMethod (Method method)
+ {
+ if (MetaDataProvider.Name (MetaDataProvider.DeclaringType (method)) != "Monitor")
+ return false;
+ string name = MetaDataProvider.Name (method);
+
+ return (name == "Exit" || name == "Wait");
+ }
+
+ private bool TypesEqualModuloInstantiation (TypeNode a, TypeNode b)
+ {
+ a = MetaDataProvider.Unspecialized (a);
+ b = MetaDataProvider.Unspecialized (b);
+ return MetaDataProvider.Equal (a, b);
+ }
+
+ private SymValue KeyForPureFunctionArgument (Method method, int index, int arg, Domain data, IImmutableMap<TypeNode, TypeNode> specialization, out bool isOut)
+ {
+ bool isByRef;
+ TypeNode type;
+ bool isPrimitive;
+ if (!ParameterHasValueRepresentation (method, index, specialization, out isPrimitive, out isOut, out isByRef, out type))
+ return data.StructId (isByRef ? data.Value (arg) : data.Address (arg));
+ SymValue sv = data.Value (arg);
+ if (isByRef)
+ sv = data.Value (sv);
+ return isPrimitive || IsImmutableType (type) ? sv : data.ObjectVersion (sv);
+ }
+
+ private bool ParameterHasValueRepresentation (Method method, int index, IImmutableMap<TypeNode, TypeNode> specialization, out bool isPrimitive, out bool isOut, out bool isByRef, out TypeNode type)
+ {
+ if (index == 0 && !MetaDataProvider.IsStatic (method)) {
+ isOut = false;
+ type = MetaDataProvider.DeclaringType (method);
+ isPrimitive = MetaDataProvider.IsPrimitive (type);
+ bool hasValueRepresentation = MetaDataProvider.HasValueRepresentation (type);
+ isByRef = (isPrimitive || !hasValueRepresentation);
+ return hasValueRepresentation;
+ }
+
+ int paramIndex = MetaDataProvider.IsStatic (method) ? index : (index - 1);
+ Parameter p = MetaDataProvider.Parameters (method) [paramIndex];
+ type = MetaDataProvider.ParameterType (p);
+ type = Specialize (specialization, type);
+ isOut = MetaDataProvider.IsOut (p);
+ if (isByRef = MetaDataProvider.IsManagedPointer (type))
+ type = MetaDataProvider.ElementType (type);
+
+ isPrimitive = MetaDataProvider.IsPrimitive (type);
+ return MetaDataProvider.HasValueRepresentation (type);
+ }
+
+ private bool IsImmutableType (TypeNode type)
+ {
+ //todo: implement
+ return false;
+ }
+
+ private int GetNonOutArgs (Method method)
+ {
+ int res = MetaDataProvider.IsStatic (method) ? 1 : 0;
+ IIndexable<Parameter> parameters = MetaDataProvider.Parameters (method);
+ for (int i = 0; i < parameters.Count; ++i) {
+ if (!MetaDataProvider.IsOut (parameters [i]))
+ ++res;
+ }
+
+ return res;
+ }
+
+ private void AssignAllOutParameters<ArgList> (Domain data, SymValue fieldAddr, Method method, ArgList args)
+ where ArgList : IIndexable<int>
+ {
+ int index = 0;
+
+ if (!MetaDataProvider.IsStatic (method))
+ ++index;
+ IIndexable<Parameter> parameters = MetaDataProvider.Parameters (method);
+ for (; index < parameters.Count; index++) {
+ Parameter p = parameters [index];
+ if (MetaDataProvider.IsOut (p)) {
+ TypeNode pType = MetaDataProvider.ParameterType (p);
+ SymValue srcAddr = data.PseudoFieldAddressOfOutParameter (index, fieldAddr, pType);
+ SymValue destAddr = data.Value (args [index]);
+ data.CopyValue (destAddr, srcAddr, pType);
+ }
+ }
+ }
+
+ private TypeNode Specialize (IImmutableMap<TypeNode, TypeNode> instantiationMap, TypeNode declaringType)
+ {
+ throw new NotImplementedException ();
+ }
+
+ private void DevirtualizeImplementingMethod (TypeNode declaringType, ref Method method)
+ {
+ throw new NotImplementedException ();
+ }
+
+ private IImmutableMap<TypeNode, TypeNode> ComputeTypeInstantiationMap (APC pc, Method method)
+ {
+ IImmutableMap<TypeNode, TypeNode> specialization = ImmutableMap<TypeNode, TypeNode>.Empty;
+ foreach (var edge in pc.SubroutineContext.AsEnumerable ()) {
+ Method calledMethod;
+ bool isVirtual;
+ bool isNewObj;
+ if (edge.From.IsMethodCallBlock (out calledMethod, out isNewObj, out isVirtual))
+ MetaDataProvider.IsSpecialized (calledMethod, ref specialization);
+ else if (edge.To.IsMethodCallBlock (out calledMethod, out isNewObj, out isVirtual))
+ MetaDataProvider.IsSpecialized (calledMethod, ref specialization);
+ }
+ return specialization;
+ }
+
+ private Domain CalliEffect<TypeList, ArgList> (APC pc, TypeNode returnType, TypeList argTypes, bool isInstance, int dest, int functionPointer, ArgList args, Domain data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<int>
+ {
+ for (int i = 0; i < args.Count; i++) {
+ int num = args [i];
+ TypeNode type;
+ if (isInstance) {
+ if (i > 0)
+ type = argTypes [i - 1];
+ else {
+ SymValue sv = data.Value (num);
+ AbstractType aType = data.GetType (sv);
+ type = aType.IsNormal ? aType.ConcreteType : MetaDataProvider.System_Object;
+ }
+ } else
+ type = argTypes [i];
+ if (!MetaDataProvider.IsStruct (type)) {
+ data.ResetModifiedAtCall ();
+ data.HavocObjectAtCall (data.Value (num), ref data.ModifiedAtCall, false, false);
+ }
+ data.Havoc (num);
+ }
+ data.AssignValue (dest, returnType);
+ return data;
+ }
+
+ private void LoadArgAddressEffect (Parameter p, bool isOld, int dest, Domain data)
+ {
+ SymValue srcAddr = isOld ? data.OldValueAddress (p) : data.Address (p);
+ data.CopyAddress (data.Address (dest), srcAddr, MetaDataProvider.ManagedPointer (MetaDataProvider.ParameterType (p)));
+ }
+
+ private void LoadLocalAddressEffect (Local local, int dest, Domain data)
+ {
+ data.CopyAddress (data.Address (dest), data.Address (local), MetaDataProvider.ManagedPointer (MetaDataProvider.LocalType (local)));
+ }
+
+ private void BoxEffect (TypeNode type, int dest, int source, Domain data)
+ {
+ if (MetaDataProvider.IsReferenceType (type))
+ data.Copy (dest, source);
+ else {
+ SymValue srcAddr = data.Address (source);
+ TypeNode systemObject = MetaDataProvider.System_Object;
+ SymValue specialUnary = data.GetSpecialUnary (data.Functions.BoxOperator, source, systemObject);
+ data.SetValue (specialUnary, srcAddr, MetaDataProvider.ManagedPointer (type), false);
+ data.AssignSpecialUnary (dest, specialUnary, systemObject);
+ }
+ }
+
+ private void CastClassEffect (TypeNode type, int dest, int obj, Domain data)
+ {
+ SymValue destAddr = data.Address (dest);
+ TypeNode mp = MetaDataProvider.ManagedPointer (type);
+ data.CopyValueAndCast (destAddr, data.Address (obj), mp);
+ }
+
+ private void LoadElementEffect (TypeNode type, int dest, int array, int index, Domain data)
+ {
+ TypeNode t = type;
+ if (!MetaDataProvider.IsStruct (type)) {
+ SymValue sv = data.Value (array);
+ AbstractType aType = data.GetType (sv);
+ if (aType.IsNormal && MetaDataProvider.IsArray (aType.ConcreteType)) {
+ t = MetaDataProvider.ElementType (aType.ConcreteType);
+ if (t == null)
+ t = type;
+ }
+ }
+ TypeNode elementAddressType = MetaDataProvider.ManagedPointer (t);
+ data.CopyValue (data.Address (dest), data.ElementAddress (data.Value (array), data.Value (index), elementAddressType), elementAddressType);
+ data.Havoc (index);
+ }
+
+ private void LoadFieldEffect (Field field, int dest, int obj, Domain data)
+ {
+ SymValue ptr;
+ if (MetaDataProvider.IsStruct (MetaDataProvider.DeclaringType (field))) {
+ AbstractType abstractType = data.GetType (data.Address (obj));
+ ptr = abstractType.IsNormal
+ && MetaDataProvider.IsManagedPointer (abstractType.ConcreteType)
+ && MetaDataProvider.IsStruct (MetaDataProvider.ElementType (abstractType.ConcreteType))
+ ? data.Address (obj)
+ : data.Value (obj);
+ } else
+ ptr = data.Value (obj);
+ TypeNode fieldAddressType;
+ SymValue srcAddr = data.FieldAddress (ptr, field, out fieldAddressType);
+ data.CopyValue (data.Address (dest), srcAddr, fieldAddressType);
+ }
+
+ private void LoadFieldAddressEffect (APC pc, Field field, int dest, int obj, Domain data)
+ {
+ SymValue sv = data.Value (obj);
+ TypeNode fieldAddressType;
+ SymValue srcAddr = data.FieldAddress (sv, field, out fieldAddressType);
+ data.CopyAddress (data.Address (dest), srcAddr, fieldAddressType);
+ if (!pc.InsideContract && MetaDataProvider.Equal (MetaDataProvider.DeclaringType (this.parent.CurrentMethod), MetaDataProvider.Unspecialized (MetaDataProvider.DeclaringType (field))))
+ data.HavocPseudoFields (this.parent.StackContextProvider.MethodContext.AffectedGetters (field), sv);
+ }
+
+ private void LoadLengthEffect (int dest, int array, Domain data)
+ {
+ data.AssignArrayLength (data.Address (dest), data.Value (array));
+ }
+
+ private void LoadStaticFieldEffect (Field field, int dest, Domain data)
+ {
+ TypeNode fieldAddressType;
+ SymValue srcAddr = data.FieldAddress (data.Globals, field, out fieldAddressType);
+ data.CopyValue (data.Address (dest), srcAddr, fieldAddressType);
+ }
+
+ private void LoadStaticFieldAddressEffect (Field field, int dest, Domain data)
+ {
+ TypeNode fieldAddressType;
+ SymValue srcAddr = data.FieldAddress (data.Globals, field, out fieldAddressType);
+ data.CopyAddress (data.Address (dest), srcAddr, fieldAddressType);
+ }
+
+ private void NewArrayEffect<T> (TypeNode type, int dest, IIndexable<int> list, Domain data)
+ {
+ if (list.Count == 1) {
+ SymValue array = data.CreateArray (type, data.Value (list [0]));
+ data.CopyAddress (data.Address (dest), array, MetaDataProvider.ArrayType (type, 1));
+ } else
+ data.AssignValue (dest, type);
+ }
+
+ private void NewObjEffect<ArgList> (APC pc, Method ctor, int dest, ArgList args, Domain data)
+ where ArgList : IIndexable<int>
+ {
+ for (int i = 0; i < args.Count; ++i)
+ data.Havoc (args [i]);
+
+ TypeNode declaringType = MetaDataProvider.DeclaringType (ctor);
+ if (MetaDataProvider.IsStruct (declaringType)) {
+ SymValue srcAddr = data.CreateValue (declaringType);
+ data.MaterializeAccordingToType (srcAddr, MetaDataProvider.ManagedPointer (declaringType), 0);
+ HavocParameters (pc, ctor, Indexable<TypeNode>.Empty, args, data, declaringType, false, true, false);
+ data.CopyValue (data.Address (dest), srcAddr, MetaDataProvider.ManagedPointer (declaringType));
+ return;
+ }
+
+ SymValue sv = data.CreateObject (declaringType);
+ HavocParameters (pc, ctor, Indexable<TypeNode>.Empty, args, data, declaringType, false, true, false);
+ data.CopyAddress (data.Address (dest), sv, declaringType);
+ }
+
+ private void StoreElementEffect (TypeNode type, int array, int index, int value, Domain data)
+ {
+ TypeNode elementAddressType = MetaDataProvider.ManagedPointer (type);
+ SymValue arrayValue = data.Value (array);
+ SymValue indexValue = data.Value (index);
+ data.HavocArrayAtIndex (arrayValue, indexValue);
+ data.CopyValue (data.ElementAddress (arrayValue, indexValue, elementAddressType), data.Address (value), elementAddressType);
+ data.Havoc (array);
+ data.Havoc (index);
+ data.Havoc (value);
+ }
+
+ public static Domain FindOldState (APC pc, Domain data)
+ {
+ for (LispList<Edge<CFGBlock, EdgeTag>> list = pc.SubroutineContext; list != null; list = list.Tail) {
+ Edge<CFGBlock, EdgeTag> pair = list.Head;
+ if (pair.Tag == EdgeTag.Exit || pair.Tag.Is (EdgeTag.AfterMask))
+ return data.GetStateAt (new APC (pair.From.Subroutine.EntryAfterRequires, 0, list.Tail));
+ }
+ return null;
+ }
+ }
+}
--- /dev/null
+//
+// Domain.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+using System.Linq;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths;
+using Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Lattices;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis {
+ class Domain : IAbstractDomain<Domain> {
+ private static Domain BottomValue;
+ public readonly FunctionsTable Functions;
+ private readonly Dictionary<APC, Domain> begin_old_saved_states;
+ private readonly SymGraph<SymFunction, AbstractType> egraph;
+ private readonly HeapAnalysis parent;
+ private TypeCache IEnumerable1Type = new TypeCache (@"System.Collections.IEnumerable`1");
+ private TypeCache IEnumerableType = new TypeCache (@"System.Collections.IEnumerable");
+ public int InsideOld;
+ public IImmutableSet<SymValue> ModifiedAtCall;
+ private IImmutableMap<SymValue, SymFunction> constantLookup;
+ private IImmutableSet<SymValue> unmodifiedFieldsSinceEntry;
+ private IImmutableSet<SymValue> unmodifiedSinceEntry;
+
+ private Domain (SymGraph<SymFunction, AbstractType> newEgraph,
+ IImmutableMap<SymValue, SymFunction> constantMap,
+ IImmutableSet<SymValue> unmodifiedSinceEntry, IImmutableSet<SymValue> unmodifiedFieldsSinceEntry, IImmutableSet<SymValue> modifiedAtCall,
+ Domain from, Domain oldDomain)
+ {
+ this.egraph = newEgraph;
+ this.Functions = from.Functions;
+ this.parent = from.parent;
+ this.begin_old_saved_states = from.begin_old_saved_states;
+ this.constantLookup = constantMap;
+ this.unmodifiedSinceEntry = unmodifiedSinceEntry;
+ this.unmodifiedFieldsSinceEntry = unmodifiedFieldsSinceEntry;
+ this.ModifiedAtCall = modifiedAtCall;
+ this.InsideOld = from.InsideOld;
+ OldDomain = oldDomain;
+ BeginOldPC = from.BeginOldPC;
+ }
+
+ public Domain (HeapAnalysis parent)
+ {
+ this.parent = parent;
+ this.egraph = new SymGraph<SymFunction, AbstractType> (AbstractType.TopValue, AbstractType.BottomValue);
+ this.constantLookup = ImmutableIntKeyMap<SymValue, SymFunction>.Empty (SymValue.GetUniqueKey);
+ this.unmodifiedSinceEntry = ImmutableSet<SymValue>.Empty (SymValue.GetUniqueKey);
+ this.unmodifiedFieldsSinceEntry = ImmutableSet<SymValue>.Empty (SymValue.GetUniqueKey);
+ this.ModifiedAtCall = ImmutableSet<SymValue>.Empty (SymValue.GetUniqueKey);
+ this.Functions = new FunctionsTable (parent.MetaDataProvider);
+ this.begin_old_saved_states = new Dictionary<APC, Domain> ();
+
+ SymValue nullValue = this.egraph.FreshSymbol ();
+ this.egraph [this.Functions.NullValue] = nullValue;
+ this.egraph [nullValue] = AbstractType.BottomValue;
+ this.egraph [ConstantValue (0, MetaDataProvider.System_Int32)] = new AbstractType (MetaDataProvider.System_Int32, true);
+ }
+
+ public Domain OldDomain { get; set; }
+ public APC BeginOldPC { get; set; }
+
+ public SymValue Globals
+ {
+ get { return this.egraph.ConstRoot; }
+ }
+
+ private SymValue Null
+ {
+ get { return this.egraph [this.Functions.NullValue]; }
+ }
+
+ private SymValue Zero
+ {
+ get { return this.egraph [this.Functions.ZeroValue]; }
+ }
+
+ public SymValue VoidAddr
+ {
+ get { return this.egraph [this.Functions.VoidAddr]; }
+ }
+
+ private IMetaDataProvider MetaDataProvider
+ {
+ get { return this.parent.MetaDataProvider; }
+ }
+
+ public IEnumerable<SymValue> Variables
+ {
+ get { return this.egraph.Variables; }
+ }
+
+ #region IAbstractDomain<Domain> Members
+ public void Dump (TextWriter tw)
+ {
+ this.egraph.Dump (tw);
+ tw.WriteLine ("Unmodified locations:");
+ foreach (SymValue sv in this.unmodifiedSinceEntry.Elements)
+ tw.Write ("{0} ", sv);
+ tw.WriteLine ();
+
+ tw.WriteLine ("Unmodified locations for fields:");
+ foreach (SymValue sv in this.unmodifiedFieldsSinceEntry.Elements)
+ tw.Write ("{0} ", sv);
+ tw.WriteLine ();
+
+ if (this.ModifiedAtCall != null) {
+ tw.WriteLine ("Modified locations at last call");
+ foreach (SymValue sv in this.ModifiedAtCall.Elements)
+ tw.Write ("{0} ", sv);
+ tw.WriteLine ();
+ }
+ if (OldDomain == null)
+ return;
+
+ tw.WriteLine ("## has old domain ##");
+ OldDomain.egraph.Dump (tw);
+ tw.WriteLine ("## end old domain ##");
+ }
+
+ public Domain Clone ()
+ {
+ return new Domain (this.egraph.Clone (), this.constantLookup, this.unmodifiedSinceEntry, this.unmodifiedFieldsSinceEntry, this.ModifiedAtCall, this, OldDomain == null ? null : OldDomain.Clone ());
+ }
+ #endregion
+
+ public static bool IsRootedInParameter (LispList<PathElement> path)
+ {
+ return path.Head is PathElement<Parameter>;
+ }
+
+ public SymValue Address (Local local)
+ {
+ SymFunction function = this.Functions.For (local);
+ SymValue sv = this.egraph.TryLookup (function);
+ if (sv == null) {
+ sv = this.egraph [function];
+ SetType (sv, MetaDataProvider.ManagedPointer (MetaDataProvider.LocalType (local)));
+ }
+ return sv;
+ }
+
+ public SymValue Address (Parameter v)
+ {
+ SymFunction function = this.Functions.For (v);
+ SymValue sv = this.egraph.TryLookup (function);
+ if (sv == null) {
+ sv = this.egraph [function];
+ SetType (sv, MetaDataProvider.ManagedPointer (MetaDataProvider.ParameterType (v)));
+ }
+ return sv;
+ }
+
+ public SymValue Address (SymFunction v)
+ {
+ return this.egraph [v];
+ }
+
+ public SymValue Address (int v)
+ {
+ return Address (this.Functions.For (v));
+ }
+
+ public void AssignConst (int dest, TypeNode type, object constant)
+ {
+ AssignConst (Address (this.Functions.For (dest)), type, constant);
+ }
+
+ public void AssignConst (SymValue address, TypeNode type, object constant)
+ {
+ SymValue value = ConstantValue (constant, type);
+ SetType (address, MetaDataProvider.ManagedPointer (type));
+ this.egraph [this.Functions.ValueOf, address] = value;
+
+ var str = constant as string;
+ if (str != null)
+ this.egraph [this.Functions.Length, value] = ConstantValue (str.Length, MetaDataProvider.System_Int32);
+ }
+
+ public void AssignValue (int dest, FlatDomain<TypeNode> type)
+ {
+ AssignValue (Address (this.Functions.For (dest)), type);
+ }
+
+ private void AssignValue (SymValue address, FlatDomain<TypeNode> type)
+ {
+ Havoc (address);
+ SetType (address, type.IsNormal ? MetaDataProvider.ManagedPointer (type.Concrete) : type);
+ if (IsStructWithFields (type))
+ return;
+
+ SymValue fresh = this.egraph.FreshSymbol ();
+ SetType (fresh, type);
+ this.egraph [this.Functions.ValueOf, address] = fresh;
+
+ if (!type.IsNormal)
+ return;
+
+ if (NeedsArrayLengthManifested (type.Concrete))
+ ManifestArrayLength (fresh);
+ }
+
+ public void AssignNull (int addr)
+ {
+ AssignNull (Address (this.Functions.For (addr)));
+ }
+
+ public void AssignNull (SymValue addr)
+ {
+ Havoc (addr);
+ this.egraph [this.Functions.ValueOf, addr] = Null;
+ }
+
+ private void AssignZero (SymValue addr)
+ {
+ this.egraph [this.Functions.ValueOf, addr] = Zero;
+ }
+
+ public void AssignZeroEquivalent (SymValue addr, TypeNode t)
+ {
+ if (MetaDataProvider.IsReferenceType (t))
+ AssignNull (addr);
+ else if (MetaDataProvider.HasValueRepresentation (t))
+ AssignZero (addr);
+ }
+
+ public void AssignSpecialUnary (int dest, SymFunction op, int source, FlatDomain<TypeNode> typeOfValue)
+ {
+ SymValue specialUnary = GetSpecialUnary (op, source, typeOfValue);
+ AssignSpecialUnary (dest, specialUnary, typeOfValue);
+ }
+
+ public void AssignSpecialUnary (int dest, SymValue result, FlatDomain<TypeNode> typeOfValue)
+ {
+ SymValue address = Address (dest);
+ AssignValue (address, typeOfValue);
+ this.egraph [this.Functions.ValueOf, address] = result;
+ }
+
+ public void AssignPureBinary (int dest, BinaryOperator op, FlatDomain<TypeNode> typeOpt, int op1, int op2)
+ {
+ var args = new[] {Value (op1), Value (op2)};
+ SymFunction c = this.Functions.For (op);
+ TypeNode type = !typeOpt.IsNormal ? MetaDataProvider.System_Int32 : typeOpt.Concrete;
+
+ bool fresh;
+
+ SymValue pointerValue = LookupAddressAndManifestType (args, c, type, out fresh);
+ SymValue destAddr = Address (dest);
+
+ SetType (destAddr, MetaDataProvider.ManagedPointer (type));
+ this.egraph [this.Functions.ValueOf, destAddr] = pointerValue;
+ }
+
+ public void AssignPureUnary (int dest, UnaryOperator op, FlatDomain<TypeNode> typeOpt, int operand)
+ {
+ SymFunction c = this.Functions.For (op);
+ TypeNode type = !typeOpt.IsNormal ? MetaDataProvider.System_Int32 : typeOpt.Concrete;
+
+ SymValue unaryOperand = this.egraph [c, Value (operand)];
+ SymValue sv = Address (dest);
+
+ SetType (sv, MetaDataProvider.ManagedPointer (type));
+ this.egraph [this.Functions.ValueOf, sv] = unaryOperand;
+ }
+
+ private SymValue ConstantValue (object constant, TypeNode type)
+ {
+ SymFunction symFunction = this.Functions.ForConstant (constant, type);
+ SymValue sv = this.egraph.TryLookup (symFunction);
+ if (sv == null) {
+ sv = this.egraph [symFunction];
+ SetType (sv, type);
+ this.constantLookup = this.constantLookup.Add (sv, symFunction);
+ }
+ return sv;
+ }
+
+ public void Havoc (int i)
+ {
+ Havoc (Address (i));
+ }
+
+ public void Havoc (SymValue addr)
+ {
+ this.egraph.EliminateAll (addr);
+ }
+
+ private void HavocIfStruct (SymValue address)
+ {
+ AbstractType aType = this.egraph [address];
+ if (aType.IsBottom || (aType.IsNormal && MetaDataProvider.IsStruct (aType.ConcreteType)))
+ Havoc (address);
+ }
+
+ private void HavocMutableFields (SymFunction except, SymValue address, ref IImmutableSet<SymValue> havoced)
+ {
+ HavocFields (except, address, ref havoced, false);
+ }
+
+ private void HavocFields (SymFunction except, SymValue address, ref IImmutableSet<SymValue> havoced, bool havocImmutable)
+ {
+ if (havoced.Contains (address))
+ return;
+
+ havoced = havoced.Add (address);
+ MakeTotallyModified (address);
+ foreach (SymFunction c in this.egraph.Functions (address))
+ HavocConstructor (except, address, c, ref havoced, havocImmutable);
+ }
+
+ private void HavocConstructor (SymFunction except, SymValue address, SymFunction c, ref IImmutableSet<SymValue> havoced, bool havocImmutable)
+ {
+ if (c == this.Functions.ValueOf)
+ this.egraph [this.Functions.OldValueOf, address] = this.egraph [c, address];
+ if (c == this.Functions.ValueOf || c == this.Functions.ObjectVersion || c == this.Functions.StructId) {
+ this.egraph.Eliminate (c, address);
+ havoced = havoced.Add (address);
+ } else {
+ var fieldWrapper = c as Wrapper<Field>;
+ if (fieldWrapper != null && fieldWrapper != except) {
+ if (havocImmutable || !MetaDataProvider.IsReadonly (fieldWrapper.Item))
+ HavocFields (except, this.egraph [c, address], ref havoced, havocImmutable);
+
+ return;
+ }
+
+ var methodWrapper = c as Wrapper<Method>;
+ if (methodWrapper != null && methodWrapper != except)
+ HavocFields (except, this.egraph [c, address], ref havoced, havocImmutable);
+ }
+ }
+
+ public void HavocPseudoFields (SymValue address)
+ {
+ IImmutableSet<SymValue> havoced = ImmutableSet<SymValue>.Empty (SymValue.GetUniqueKey);
+ HavocPseudoFields (null, address, ref havoced);
+ }
+
+ private void HavocPseudoFields (SymFunction except, SymValue address, ref IImmutableSet<SymValue> havoced)
+ {
+ if (havoced.Contains (address))
+ return;
+ havoced = havoced.Add (address);
+ if (IsUnmodified (address)) {
+ MakeModified (address);
+ MakeUnmodifiedField (address);
+ }
+ this.egraph.Eliminate (this.Functions.ObjectVersion, address);
+ this.egraph.Eliminate (this.Functions.StructId, address);
+ foreach (SymFunction c in this.egraph.Functions (address)) {
+ if (c != except && c is Wrapper<Method>)
+ HavocMutableFields (except, this.egraph [c, address], ref havoced);
+ }
+ }
+
+ private void HavocPseudoFields (SymFunction except, IEnumerable<Method> getters, SymValue address, ref IImmutableSet<SymValue> havoced)
+ {
+ if (havoced.Contains (address))
+ return;
+ havoced = havoced.Add (address);
+ if (IsUnmodified (address)) {
+ MakeModified (address);
+ MakeUnmodifiedField (address);
+ }
+ this.egraph.Eliminate (this.Functions.ObjectVersion, address);
+ this.egraph.Eliminate (this.Functions.StructId, address);
+ foreach (Method m in getters)
+ HavocMutableFields (except, this.egraph [this.Functions.For (m), address], ref havoced);
+ }
+
+ public void HavocPseudoFields (IEnumerable<Method> getters, SymValue address)
+ {
+ IImmutableSet<SymValue> havoced = ImmutableSet<SymValue>.Empty (SymValue.GetUniqueKey);
+ HavocPseudoFields (null, getters, address, ref havoced);
+ }
+
+ private void MakeUnmodifiedField (SymValue address)
+ {
+ this.unmodifiedFieldsSinceEntry = this.unmodifiedFieldsSinceEntry.Add (address);
+ }
+
+ private void MakeModified (SymValue address)
+ {
+ this.unmodifiedSinceEntry = this.unmodifiedSinceEntry.Remove (address);
+ }
+
+ public void CopyValue (SymValue destAddr, SymValue sourceAddr)
+ {
+ AbstractType type = this.egraph [sourceAddr];
+ CopyValue (destAddr, sourceAddr, type.Type);
+ }
+
+ public void CopyValue (SymValue destAddr, SymValue sourceAddr, FlatDomain<TypeNode> addrType)
+ {
+ CopyValue (destAddr, sourceAddr, addrType, true, false);
+ }
+
+ private void CopyValue (SymValue destAddr, SymValue sourceAddr, FlatDomain<TypeNode> addrType, bool setTargetAddrType, bool cast)
+ {
+ MakeTotallyModified (destAddr);
+ if (destAddr != sourceAddr)
+ HavocIfStruct (destAddr);
+ if (setTargetAddrType)
+ SetType (destAddr, addrType);
+
+ SetValue (destAddr, sourceAddr, addrType, cast);
+ }
+
+ public void CopyOldValue (APC pc, int dest, int source, Domain target, bool atEndOld)
+ {
+ CopyOldValue (pc, target.Address (dest), Address (source), target, atEndOld);
+ }
+
+ public void CopyOldValue (APC pc, SymValue destAddr, SymValue srcAddr, Domain target, bool atEndOld)
+ {
+ AbstractType abstractType = this.egraph [srcAddr];
+ CopyOldValue (pc, destAddr, srcAddr, abstractType.Type, target, atEndOld);
+ }
+
+ private void CopyOldValue (APC pc, SymValue destAddr, SymValue srcAddr, FlatDomain<TypeNode> addrType, Domain target, bool atEndOld)
+ {
+ CopyOldValue (pc, destAddr, srcAddr, addrType, true, atEndOld, target);
+ }
+
+ private void CopyOldValue (APC pc, SymValue destAddr, SymValue srcAddr, FlatDomain<TypeNode> addrType, bool setTargetAddrType, bool atEndOld, Domain target)
+ {
+ target.MakeTotallyModified (destAddr);
+ if (destAddr != srcAddr)
+ target.HavocIfStruct (destAddr);
+ if (setTargetAddrType)
+ target.SetType (destAddr, addrType);
+
+ FlatDomain<TypeNode> targetType = TargetType (addrType);
+
+ if (IsStructWithFields (targetType))
+ CopyOldStructValue (pc, destAddr, srcAddr, targetType.Concrete, target, atEndOld);
+ else if (atEndOld && targetType.IsNormal && MetaDataProvider.IsManagedPointer (targetType.Concrete)) {
+ srcAddr = TryValue (srcAddr);
+ if (srcAddr == null)
+ return;
+ destAddr = target.Value (destAddr);
+ CopyOldValue (pc, destAddr, srcAddr, targetType, setTargetAddrType, atEndOld, target);
+ } else {
+ SymValue source = this.egraph.TryLookup (this.Functions.ValueOf, srcAddr);
+ if (source == null) {
+ if (this.egraph.IsImmutable)
+ return;
+ source = this.egraph [this.Functions.ValueOf, srcAddr];
+ }
+ CopyOldValueToDest (pc, destAddr, source, addrType, target);
+ }
+ }
+
+ public void CopyOldValueToDest (APC pc, SymValue destAddr, SymValue source, FlatDomain<TypeNode> addrType, Domain target)
+ {
+ if (pc.InsideEnsuresAtCall) {
+ TypeNode type;
+ object constant;
+
+ if (IsConstant (source, out type, out constant)) {
+ SymValue sv = target.ConstantValue (constant, type);
+ target.CopyNonStructWithFieldValue (destAddr, sv, addrType);
+ return;
+ }
+
+ foreach (var sv in GetAccessPathsRaw (source, AccessPathFilter<Method>.NoFilter, false))
+ throw new NotImplementedException ();
+ }
+ }
+
+ private IEnumerable<LispList<PathElementBase>> GetAccessPathsRaw (SymValue sv, AccessPathFilter<Method> filter, bool compress)
+ {
+ var visited = new HashSet<SymValue> ();
+ return GetAccessPathsRaw (sv, null, visited, filter, compress);
+ }
+
+ private IEnumerable<LispList<PathElementBase>> GetAccessPathsRaw (SymValue sv, LispList<PathElementBase> path, HashSet<SymValue> visited, AccessPathFilter<Method> filter, bool compress)
+ {
+ if (sv == this.egraph.ConstRoot)
+ yield return path;
+ else if (!visited.Contains (sv)) {
+ visited.Add (sv);
+ foreach (var term in this.egraph.EqTerms (sv)) {
+ if (!(term.Function is Wrapper<object>) && !(term.Function is Wrapper<int>)) {
+ PathElementBase next = term.Function.ToPathElement (compress);
+ if (next != null && !filter.FilterOutPathElement (term.Function)) {
+ LispList<PathElementBase> newPath;
+
+ if (path == null || !compress || (!(next is PathElement<Method>)))
+ newPath = path.Cons (next);
+ else
+ newPath = path.Tail.Cons (next);
+
+ foreach (var item in GetAccessPathsRaw (term.Args [0], newPath, visited, filter, compress))
+ yield return item;
+ }
+ }
+ }
+ }
+ }
+
+ private LispList<PathElementBase> GetBestAccessPath (SymValue sv, AccessPathFilter<Method> filter, bool compress, bool allowLocal, bool preferLocal)
+ {
+ LispList<PathElementBase> bestParameterPath = null;
+ LispList<PathElementBase> bestLocalPath = null;
+ LispList<PathElementBase> bestFieldMethodPath = null;
+
+ foreach (var path in GetAccessPathsFiltered (sv, filter, compress)) {
+ if (path != null) {
+ if (path.Head is PathElement<Parameter>) {
+ if (bestParameterPath == null || bestParameterPath.Length () > path.Length ())
+ bestParameterPath = path;
+ } else if (filter.AllowLocal && allowLocal && path.Head is PathElement<Local>) {
+ if (!path.Head.ToString ().Contains ("$") && (bestLocalPath == null || bestLocalPath.Length () > path.Length ()))
+ bestLocalPath = path;
+ } else if (path.Head is PathElement<Field> && path.Head.Func.IsStatic) {
+ if (bestFieldMethodPath == null || bestFieldMethodPath.Length () > path.Length ())
+ bestFieldMethodPath = path;
+ } else if (path.Head is PathElement<Method> && path.Head.Func.IsStatic) {
+ if (bestFieldMethodPath == null || bestFieldMethodPath.Length () > path.Length ())
+ bestFieldMethodPath = path;
+ }
+ }
+ }
+ if (preferLocal && bestLocalPath != null)
+ return bestLocalPath;
+ if (bestParameterPath != null)
+ return bestParameterPath;
+ if (allowLocal && bestLocalPath != null)
+ return bestLocalPath;
+
+ return bestFieldMethodPath;
+ }
+
+ public IEnumerable<LispList<PathElementBase>> GetAccessPathsFiltered (SymValue sv, AccessPathFilter<Method> filter, bool compress)
+ {
+ return GetAccessPathsTyped (sv, filter, compress).Where (path => PathIsVisibleAccordingToFilter (path, filter));
+ }
+
+ private bool PathIsVisibleAccordingToFilter (LispList<PathElementBase> path, AccessPathFilter<Method> filter)
+ {
+ if (path.Length () == 0 || !filter.HasVisibilityMember)
+ return true;
+
+ Method visibilityMember = filter.VisibilityMember;
+ TypeNode t = MetaDataProvider.DeclaringType (visibilityMember);
+ TypeNode type = default(TypeNode);
+
+ while (path != null) {
+ PathElement pathElement = path.Head;
+ if (!pathElement.TryGetResultType (out type))
+ return true;
+ while (MetaDataProvider.IsManagedPointer (type))
+ type = MetaDataProvider.ElementType (type);
+ if ("this" != pathElement.ToString ()) {
+ var peMethod = pathElement as PathElement<Method>;
+ if (peMethod != null) {
+ Method method = peMethod.Element;
+ if (!MetaDataProvider.IsVisibleFrom (method, t))
+ return false;
+ }
+
+ var peProperty = pathElement as PathElement<Property>;
+ if (peProperty != null) {
+ Property property = peProperty.Element;
+ Method method;
+ if (!MetaDataProvider.HasGetter (property, out method))
+ MetaDataProvider.HasSetter (property, out method);
+
+ if (!MetaDataProvider.IsVisibleFrom (method, t))
+ return false;
+ }
+
+ var peField = pathElement as PathElement<Field>;
+ if (peField != null) {
+ Field field = peField.Element;
+ if (!MetaDataProvider.IsVisibleFrom (field, t))
+ return false;
+ }
+ }
+ path = path.Tail;
+ }
+ return true;
+ }
+
+ private bool TryPropagateTypeInfo (LispList<PathElementBase> path, out LispList<PathElementBase> result)
+ {
+ if (path == null) {
+ result = null;
+ return true;
+ }
+ PathElementBase head = path.Head;
+ TypeNode prevType;
+ if (!head.TrySetType (MetaDataProvider.System_IntPtr, MetaDataProvider, out prevType)) {
+ result = null;
+ return false;
+ }
+
+ LispList<PathElementBase> result1;
+ if (!TryPropagateTypeInfoRecurse (path.Tail, prevType, out result1)) {
+ result = null;
+ return false;
+ }
+ if (head.IsAddressOf && head is PathElement<Parameter> && result1 != null && result1.Head.IsDeref) {
+ var pathElement = (PathElement<Parameter>) head;
+ result = result1.Tail.Cons (new ParameterPathElement (pathElement.Element, pathElement.Description, pathElement.Func, MetaDataProvider));
+ return true;
+ }
+
+ result = result1.Cons (head);
+ return true;
+ }
+
+ private bool TryPropagateTypeInfoRecurse (LispList<PathElementBase> path, TypeNode prevType, out LispList<PathElementBase> result)
+ {
+ if (path == null) {
+ result = null;
+ return true;
+ }
+ PathElementBase head = path.Head;
+ if (head.TrySetType (prevType, MetaDataProvider, out prevType)) {
+ LispList<PathElementBase> updatedPath;
+ if (TryPropagateTypeInfoRecurse (path.Tail, prevType, out updatedPath)) {
+ result = updatedPath.Cons (head);
+ return true;
+ }
+ }
+
+ result = null;
+ return false;
+ }
+
+ private IEnumerable<LispList<PathElementBase>> GetAccessPathsTyped (SymValue sv, AccessPathFilter<Method> filter, bool compress)
+ {
+ var visited = new HashSet<SymValue> ();
+ foreach (var path in GetAccessPathsRaw (sv, null, visited, filter, compress)) {
+ LispList<PathElementBase> result;
+ if (TryPropagateTypeInfo (path, out result))
+ yield return result;
+ }
+ }
+
+ private void CopyNonStructWithFieldValue (SymValue destAddr, SymValue sv, FlatDomain<TypeNode> addrType)
+ {
+ this.egraph [this.Functions.ValueOf, destAddr] = sv;
+ SetType (destAddr, addrType);
+ }
+
+ public bool IsConstant (SymValue source, out TypeNode type, out object constant)
+ {
+ SymFunction c = this.constantLookup [source];
+ if (c != null)
+ return this.Functions.IsConstant (c, out type, out constant);
+
+ type = default(TypeNode);
+ constant = null;
+ return false;
+ }
+
+ private void CopyOldStructValue (APC pc, SymValue destAddr, SymValue srcAddr, TypeNode type, Domain target, bool atEndOld)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public void SetValue (SymValue destAddr, SymValue sourceAddr, FlatDomain<TypeNode> addrType, bool cast)
+ {
+ FlatDomain<TypeNode> type = TargetType (addrType);
+ if (IsStructWithFields (type))
+ CopyStructValue (destAddr, sourceAddr, type.Concrete);
+
+ CopyPrimValue (destAddr, sourceAddr, cast, type);
+ }
+
+ private void CopyPrimValue (SymValue destAddr, SymValue sourceAddr, bool cast, FlatDomain<TypeNode> elementType)
+ {
+ SymValue value = this.egraph [this.Functions.ValueOf, sourceAddr];
+ if (cast)
+ SetType (value, elementType);
+ else
+ SetTypeIfUnknown (value, elementType);
+
+ if (elementType.IsNormal) {
+ if (NeedsArrayLengthManifested (elementType.Concrete))
+ ManifestArrayLength (value);
+ }
+
+ this.egraph [this.Functions.ValueOf, destAddr] = value;
+ }
+
+ public void CopyValueToOldState (APC pc, TypeNode type, int dest, int source, Domain target)
+ {
+ SymValue destAddress = target.Address (dest);
+ SymValue srcAddress = Address (source);
+
+ AbstractType aType = GetType (srcAddress);
+ TypeNode addrType = aType.IsNormal ? aType.ConcreteType : MetaDataProvider.ManagedPointer (type);
+ CopyValueToOldState (pc, addrType, destAddress, srcAddress, target);
+ }
+
+ private void CopyValueToOldState (APC pc, TypeNode addrType, SymValue destAddress, SymValue srcAddress, Domain target)
+ {
+ target.MakeTotallyModified (destAddress);
+ if (destAddress != srcAddress)
+ target.HavocIfStruct (destAddress);
+ target.SetType (destAddress, addrType);
+ FlatDomain<TypeNode> targetType = TargetType (addrType);
+ if (IsStructWithFields (targetType))
+ CopyStructValueToOldState (pc, destAddress, srcAddress, targetType, target);
+ else {
+ SymValue sv = this.egraph.TryLookup (this.Functions.ValueOf, srcAddress);
+ if (sv == null) {
+ if (this.egraph.IsImmutable)
+ return;
+ sv = this.egraph [this.Functions.ValueOf, srcAddress];
+ }
+ CopyPrimitiveValueToOldState (pc, addrType, destAddress, sv, target);
+ }
+ }
+
+ private void CopyPrimitiveValueToOldState (APC pc, TypeNode addrType, SymValue destAddress, SymValue sv, Domain target)
+ {
+ if (target.IsValidSymbol (sv))
+ target.CopyNonStructWithFieldValue (destAddress, sv, addrType);
+ else
+ target.Assign (destAddress, addrType);
+ }
+
+ private bool IsValidSymbol (SymValue sv)
+ {
+ return this.egraph.IsValidSymbol (sv);
+ }
+
+ private void Assign (SymValue destAddress, TypeNode addrType)
+ {
+ Havoc (destAddress);
+ SetType (destAddress, addrType);
+ FlatDomain<TypeNode> targetType = TargetType (addrType);
+ if (IsStructWithFields (targetType))
+ return;
+
+ SymValue fresh = this.egraph.FreshSymbol ();
+ SetType (fresh, targetType);
+ this.egraph [this.Functions.ValueOf, destAddress] = fresh;
+ if (!targetType.IsNormal)
+ return;
+
+ if (NeedsArrayLengthManifested (targetType.Concrete))
+ ManifestArrayLength (fresh);
+ }
+
+ private void CopyStructValueToOldState (APC pc, SymValue destAddress, SymValue srcAddress, FlatDomain<TypeNode> targetType, Domain target)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public void ManifestArrayLength (SymValue arrayValue)
+ {
+ SetType (this.egraph [this.Functions.Length, arrayValue], MetaDataProvider.System_Int32);
+ }
+
+ public bool NeedsArrayLengthManifested (TypeNode type)
+ {
+ return MetaDataProvider.IsArray (type) || MetaDataProvider.System_String.Equals (type);
+ }
+
+ public void CopyStructValue (SymValue destAddr, SymValue sourceAddr, TypeNode type)
+ {
+ if (destAddr == null)
+ return;
+ this.egraph [this.Functions.StructId, destAddr] = this.egraph [this.Functions.StructId, sourceAddr];
+ foreach (SymFunction function in this.egraph.Functions (sourceAddr)) {
+ if (function.ActsAsField) {
+ TypeNode functionType = function.FieldAddressType ();
+ CopyValue (this.egraph [function, destAddr], this.egraph [function, sourceAddr], functionType);
+ }
+ }
+ }
+
+ public SymValue OldValueAddress (Parameter p)
+ {
+ return Address (OldValueParameterConstructor (p));
+ }
+
+ private SymFunction OldValueParameterConstructor (Parameter argument)
+ {
+ return this.Functions.For ("$OldParameter_" + MetaDataProvider.Name (argument));
+ }
+
+ public void CopyParameterIntoShadow (Parameter p)
+ {
+ CopyValue (Address (OldValueParameterConstructor (p)), Address (this.Functions.For (p)));
+ }
+
+ public void Copy (int dest, int source)
+ {
+ CopyValue (Address (this.Functions.For (dest)), Address (this.Functions.For (source)));
+ }
+
+ private bool IsIEnumerable (TypeNode type)
+ {
+ TypeNode ienumerableType;
+ return (this.IEnumerable1Type.TryGet (MetaDataProvider, out ienumerableType) && MetaDataProvider.DerivesFrom (type, ienumerableType)
+ || this.IEnumerableType.TryGet (MetaDataProvider, out ienumerableType) && MetaDataProvider.DerivesFrom (type, ienumerableType));
+ }
+
+ public SymValue GetSpecialUnary (SymFunction op, int source, FlatDomain<TypeNode> type)
+ {
+ SymValue value = Value (source);
+ SymValue sv = this.egraph [op, value];
+ SetType (sv, type);
+ return sv;
+ }
+
+ private SymValue LookupAddressAndManifestType (SymValue[] args, SymFunction op, TypeNode type, out bool fresh)
+ {
+ SymValue sv = this.egraph.TryLookup (op, args);
+ if (sv != null) {
+ fresh = false;
+ return sv;
+ }
+ fresh = true;
+ sv = this.egraph [op, args];
+ SetType (sv, type);
+ return sv;
+ }
+
+ public bool IsZero (SymValue symValue)
+ {
+ return this.egraph [symValue].IsZero;
+ }
+
+ public SymValue Value (int v)
+ {
+ return Value (Address (this.Functions.For (v)));
+ }
+
+ public SymValue Value (SymValue address)
+ {
+ bool fresh;
+ SymValue symbol = this.egraph.LookupOrManifest (this.Functions.ValueOf, address, out fresh);
+
+ if (fresh && IsUnmodified (address))
+ MakeUnmodified (symbol);
+
+ return symbol;
+ }
+
+ public SymValue Value (Parameter p)
+ {
+ return Value (Address (this.Functions.For (p)));
+ }
+
+ public void MakeUnmodified (SymValue value)
+ {
+ this.unmodifiedSinceEntry = this.unmodifiedSinceEntry.Add (value);
+ }
+
+ private bool IsUnmodified (SymValue value)
+ {
+ return this.unmodifiedSinceEntry.Contains (value);
+ }
+
+ public AbstractType CurrentType (int stackPos)
+ {
+ return CurrentType (Value (Address (this.Functions.For (stackPos))));
+ }
+
+ private AbstractType CurrentType (SymValue address)
+ {
+ return this.egraph [address];
+ }
+
+ public Domain Assume (int t, bool truth)
+ {
+ return Assume (Value (t), truth);
+ }
+
+ private Domain Assume (SymValue sv, bool truth)
+ {
+ if (!truth) {
+ if (IsNonZero (sv))
+ return Bottom;
+ this.egraph [sv] = this.egraph [sv].ButZero;
+ foreach (var term in this.egraph.EqTerms (sv)) {
+ if (term.Function == this.Functions.UnaryNot || term.Function == this.Functions.NeZero)
+ return Assume (term.Args [0], true);
+ }
+ } else {
+ if (this.egraph [sv].IsZero)
+ return Bottom;
+ foreach (var term in this.egraph.EqTerms (sv)) {
+ if (term.Function == this.Functions.UnaryNot || term.Function == this.Functions.NeZero)
+ return Assume (term.Args [0], false);
+ }
+ }
+
+ return this;
+ }
+
+ private bool IsNonZero (SymValue sv)
+ {
+ foreach (var term in this.egraph.EqTerms (sv)) {
+ var wrapper = term.Function as Wrapper<object>;
+ if (wrapper != null && wrapper.Item is int && (int) wrapper.Item != 0)
+ return true;
+ }
+ return false;
+ }
+
+ public FlatDomain<TypeNode> BinaryResultType (BinaryOperator op, AbstractType t1, AbstractType t2)
+ {
+ switch (op) {
+ case BinaryOperator.Add:
+ case BinaryOperator.Add_Ovf:
+ case BinaryOperator.Add_Ovf_Un:
+ if (t1.IsZero)
+ return t2.Type;
+ return t1.Type;
+ case BinaryOperator.Sub:
+ case BinaryOperator.Sub_Ovf:
+ case BinaryOperator.Sub_Ovf_Un:
+ return t1.Type;
+ case BinaryOperator.Ceq:
+ case BinaryOperator.Cobjeq:
+ case BinaryOperator.Cne_Un:
+ case BinaryOperator.Cge:
+ case BinaryOperator.Cge_Un:
+ case BinaryOperator.Cgt:
+ case BinaryOperator.Cgt_Un:
+ case BinaryOperator.Cle:
+ case BinaryOperator.Cle_Un:
+ case BinaryOperator.Clt:
+ case BinaryOperator.Clt_Un:
+ return MetaDataProvider.System_Boolean;
+ default:
+ return t1.Type;
+ }
+ }
+
+ private bool IsStructWithFields (FlatDomain<TypeNode> type)
+ {
+ if (!type.IsNormal)
+ return false;
+
+ return !MetaDataProvider.HasValueRepresentation (type.Concrete);
+ }
+
+ private FlatDomain<TypeNode> TargetType (FlatDomain<TypeNode> type)
+ {
+ if (!type.IsNormal)
+ return type;
+
+ TypeNode normalType = type.Concrete;
+ if (MetaDataProvider.IsManagedPointer (normalType))
+ return MetaDataProvider.ElementType (normalType);
+
+ return FlatDomain<TypeNode>.TopValue;
+ }
+
+ public void SetType (SymValue sv, FlatDomain<TypeNode> type)
+ {
+ AbstractType abstractType = this.egraph [sv];
+ if (abstractType.IsZero)
+ return;
+
+ this.egraph [sv] = abstractType.With (type);
+ }
+
+ private void SetTypeIfUnknown (SymValue sv, FlatDomain<TypeNode> type)
+ {
+ AbstractType abstractType = this.egraph [sv];
+
+ if (!abstractType.IsZero && (!abstractType.Type.IsNormal || abstractType.Type.Equals (MetaDataProvider.System_IntPtr)))
+ this.egraph [sv] = abstractType.With (type);
+ }
+
+ private void MakeTotallyModified (SymValue dest)
+ {
+ this.unmodifiedSinceEntry = this.unmodifiedSinceEntry.Remove (dest);
+ this.unmodifiedFieldsSinceEntry = this.unmodifiedFieldsSinceEntry.Remove (dest);
+ }
+
+ private bool AreUnmodified (IEnumerable<SymValue> values)
+ {
+ return values.All (IsUnmodified);
+ }
+
+ private bool AnyAreModifiedAtCall (IEnumerable<SymValue> values)
+ {
+ return values.Any (IsModifiedAtCall);
+ }
+
+ private bool IsModifiedAtCall (SymValue sv)
+ {
+ return (this.ModifiedAtCall != null && this.ModifiedAtCall.Contains (sv));
+ }
+
+ public Domain GetStateAt (APC pc)
+ {
+ Domain ifFound;
+ this.parent.PreStateLookup (pc, out ifFound);
+
+ return ifFound;
+ }
+
+ public bool TryGetCorrespondingValueAbstraction (int v, out SymbolicValue sv)
+ {
+ return TryGetCorrespondingValueAbstraction (this.Functions.For (v), out sv);
+ }
+
+ private bool TryGetCorrespondingValueAbstraction (SymFunction v, out SymbolicValue sv)
+ {
+ if (!IsBottom) {
+ SymValue loc = TryAddress (v);
+ if (loc != null) {
+ SymValue symbol = TryCorrespondingValue (loc);
+ if (symbol != null) {
+ sv = new SymbolicValue (symbol);
+ return true;
+ }
+ }
+ }
+
+ sv = default(SymbolicValue);
+ return false;
+ }
+
+ private SymValue TryCorrespondingValue (SymValue address)
+ {
+ if (IsStructAddress (this.egraph [address]))
+ return address;
+
+ return TryValue (address);
+ }
+
+ private bool IsStructAddress (AbstractType abstractType)
+ {
+ if (!abstractType.IsNormal)
+ return false;
+
+ TypeNode normalType = abstractType.ConcreteType;
+ if (MetaDataProvider.IsManagedPointer (normalType))
+ return !MetaDataProvider.HasValueRepresentation (MetaDataProvider.ElementType (normalType));
+
+ return false;
+ }
+
+ private SymValue TryAddress (SymFunction c)
+ {
+ return this.egraph.TryLookup (c);
+ }
+
+ public bool TryGetCorrespondingValueAbstraction (Local v, out SymbolicValue sv)
+ {
+ return TryGetCorrespondingValueAbstraction (this.Functions.For (v), out sv);
+ }
+
+ public bool TryGetUnboxedValue (int source, out SymbolicValue sv)
+ {
+ return TryGetUnboxedValue (TryValue (Address (source)), out sv);
+ }
+
+ private bool TryGetUnboxedValue (SymValue box, out SymbolicValue sv)
+ {
+ if (box != null) {
+ SymValue symbol = TryValue (box);
+ if (symbol != null && this.egraph.TryLookup (this.Functions.BoxOperator, symbol) == box) {
+ sv = new SymbolicValue (symbol);
+ return true;
+ }
+ }
+ sv = new SymbolicValue ();
+ return false;
+ }
+
+ public SymValue TryValue (SymValue address)
+ {
+ return this.egraph.TryLookup (this.Functions.ValueOf, address);
+ }
+
+ public AbstractType GetType (SymValue symbol)
+ {
+ return this.egraph [symbol];
+ }
+
+ public SymValue CreateObject (TypeNode type)
+ {
+ SymValue sv = this.egraph.FreshSymbol ();
+ SetType (sv, type);
+ return sv;
+ }
+
+ public SymValue CreateValue (TypeNode type)
+ {
+ SymValue sv = this.egraph.FreshSymbol ();
+ SetType (sv, MetaDataProvider.ManagedPointer (type));
+ return sv;
+ }
+
+ public void HavocArrayAtIndex (SymValue arrayValue, SymValue indexValue)
+ {
+ this.egraph.Eliminate (this.Functions.ElementAddress, arrayValue);
+ }
+
+ public SymValue CreateArray (TypeNode type, SymValue len)
+ {
+ SymValue sv = this.egraph.FreshSymbol ();
+ this.egraph [this.Functions.Length, sv] = len;
+ SetType (sv, MetaDataProvider.ArrayType (type, 1));
+ return sv;
+ }
+
+ public SymValue ElementAddress (SymValue array, SymValue index, TypeNode elementAddressType)
+ {
+ SymValue objVersion = this.egraph [this.Functions.ObjectVersion, array];
+ SymValue sv = this.egraph.TryLookup (this.Functions.ElementAddress, objVersion, index);
+ if (sv == null) {
+ sv = this.egraph [this.Functions.ElementAddress, objVersion, index];
+ SetType (sv, elementAddressType);
+ this.egraph [this.Functions.ResultOfLoadElement, sv] = Zero;
+ }
+ return sv;
+ }
+
+ public void CopyValueAndCast (SymValue destAddr, SymValue srcAddr, TypeNode addrType)
+ {
+ CopyValue (destAddr, srcAddr, addrType, true, true);
+ }
+
+ public void HavocObjectAtCall (SymValue obj, ref IImmutableSet<SymValue> havoced, bool havocFields, bool havocReadonlyFields)
+ {
+ HavocFields (null, obj, ref havoced, havocReadonlyFields);
+ HavocUp (obj, ref havoced, havocFields);
+ }
+
+ public bool IsThis (Method currentMethod, int i)
+ {
+ if (MetaDataProvider.IsStatic (currentMethod))
+ return false;
+ return Value (MetaDataProvider.This (currentMethod)) == Value (i);
+ }
+
+ public void AssignValueAndNullnessAtConv_IU (int dest, int source, bool unsigned)
+ {
+ AbstractType aType = CurrentType (source);
+ AssignValueAndNullnessAtConv_IU (Address (this.Functions.For (dest)), unsigned, aType);
+ }
+
+ private void AssignValueAndNullnessAtConv_IU (SymValue address, bool unsigned, AbstractType aType)
+ {
+ Havoc (address);
+ FlatDomain<TypeNode> type = aType.Type;
+ if (!IsStructWithFields (type)) {
+ SymValue ptrValue = this.egraph.FreshSymbol ();
+ if (type.IsNormal)
+ aType = new AbstractType (!unsigned ? MetaDataProvider.System_IntPtr : MetaDataProvider.System_UIntPtr, aType.IsZero);
+ SetType (address, type.IsNormal ? MetaDataProvider.ManagedPointer (type.Concrete) : type);
+ this.egraph [ptrValue] = aType;
+ this.egraph [this.Functions.ValueOf, address] = ptrValue;
+ } else
+ SetType (address, type.IsNormal ? MetaDataProvider.ManagedPointer (type.Concrete) : type);
+ }
+
+ public TypeNode UnaryResultType (UnaryOperator op, AbstractType type)
+ {
+ switch (op) {
+ case UnaryOperator.Conv_i1:
+ return MetaDataProvider.System_Int8;
+ case UnaryOperator.Conv_i2:
+ return MetaDataProvider.System_Int16;
+ case UnaryOperator.Conv_i4:
+ return MetaDataProvider.System_Int32;
+ case UnaryOperator.Conv_i8:
+ return MetaDataProvider.System_Int64;
+ case UnaryOperator.Conv_u1:
+ return MetaDataProvider.System_UInt8;
+ case UnaryOperator.Conv_u2:
+ return MetaDataProvider.System_UInt16;
+ case UnaryOperator.Conv_u4:
+ return MetaDataProvider.System_UInt32;
+ case UnaryOperator.Conv_u8:
+ return MetaDataProvider.System_UInt64;
+ default:
+ if (type.IsNormal)
+ return type.ConcreteType;
+ return MetaDataProvider.System_Int32;
+ }
+ }
+
+ public void CopyStackAddress (SymValue destAddr, int temporaryForWhichAddressIsTaken)
+ {
+ SymValue srcAddr = Address (temporaryForWhichAddressIsTaken);
+ this.egraph [this.Functions.ValueOf, destAddr] = srcAddr;
+ AbstractType aType = CurrentType (srcAddr);
+ FlatDomain<TypeNode> t = !aType.IsNormal ? new FlatDomain<TypeNode> () : MetaDataProvider.ManagedPointer (aType.Type.Concrete);
+ SetType (destAddr, t);
+ }
+
+ public SymValue PseudoFieldAddress (SymValue ptr, Method getter)
+ {
+ TypeNode pseudoFieldAddressType;
+ return PseudoFieldAddress (ptr, getter, out pseudoFieldAddressType, false);
+ }
+
+ public SymValue PseudoFieldAddress (SymValue sv, Method m, out TypeNode pseudoFieldAddressType, bool materialize)
+ {
+ pseudoFieldAddressType = MetaDataProvider.ManagedPointer (MetaDataProvider.ReturnType (m));
+ m = MetaDataProvider.Unspecialized (m);
+ bool fresh;
+ SymValue elem = LookupAddressAndManifestType (sv, this.Functions.For (m), pseudoFieldAddressType, out fresh);
+ if (fresh) {
+ if (IsUnmodified (sv))
+ MakeModified (elem);
+ if (IsModifiedAtCall (sv))
+ this.ModifiedAtCall = this.ModifiedAtCall.Add (elem);
+ if (materialize)
+ MaterializeAccordingToType (elem, pseudoFieldAddressType, 0);
+ }
+ return elem;
+ }
+
+ public SymValue FieldAddress (SymValue ptr, Field field)
+ {
+ TypeNode fieldAddressType;
+ return FieldAddress (ptr, field, out fieldAddressType);
+ }
+
+ public SymValue FieldAddress (SymValue ptr, Field field, out TypeNode fieldAddressType)
+ {
+ fieldAddressType = MetaDataProvider.ManagedPointer (MetaDataProvider.FieldType (field));
+ bool fresh;
+ SymValue sv = LookupAddressAndManifestType (ptr, this.Functions.For (field), fieldAddressType, out fresh);
+ if (fresh) {
+ if (IsUnmodifiedForFields (ptr) || MetaDataProvider.IsReadonly (field))
+ MakeUnmodified (sv);
+ if (IsModifiedAtCall (ptr))
+ this.ModifiedAtCall = this.ModifiedAtCall.Add (sv);
+ }
+ return sv;
+ }
+
+ public void Assign (Parameter parameter, TypeNode type)
+ {
+ AssignValue (Address (this.Functions.For (parameter)), type);
+ }
+
+ public SymValue PseudoFieldAddressOfOutParameter (int index, SymValue fieldAddr, TypeNode pType)
+ {
+ SymValue sv = this.egraph [this.Functions.ForConstant (index, MetaDataProvider.System_Int32), fieldAddr];
+ MaterializeAccordingToType (sv, pType, 2);
+ return sv;
+ }
+
+ public SymValue ObjectVersion (SymValue sv)
+ {
+ return this.egraph [this.Functions.ObjectVersion, sv];
+ }
+
+ public SymValue PseudoFieldAddress (SymValue[] args, Method method, out TypeNode pseudoFieldAddressType, bool materialize)
+ {
+ if (args.Length == 0 || args.Length == 1)
+ return PseudoFieldAddress (Globals, method, out pseudoFieldAddressType, materialize);
+ pseudoFieldAddressType = MetaDataProvider.ManagedPointer (MetaDataProvider.ReturnType (method));
+ method = MetaDataProvider.Unspecialized (method);
+
+ bool fresh;
+ SymValue sv = LookupAddressAndManifestType (args, this.Functions.For (method), pseudoFieldAddressType, out fresh);
+ if (fresh) {
+ if (AreUnmodified (args))
+ MakeUnmodified (sv);
+ if (AnyAreModifiedAtCall (args))
+ this.ModifiedAtCall = this.ModifiedAtCall.Add (sv);
+ if (materialize)
+ MaterializeAccordingToType (sv, pseudoFieldAddressType, 0);
+ }
+ return sv;
+ }
+
+ public void AssignReturnValue (int dest, TypeNode type)
+ {
+ AssignValue (dest, type);
+ if (MetaDataProvider.HasValueRepresentation (type))
+ this.egraph [this.Functions.ResultOfCall, Value (dest)] = Zero;
+ else
+ MaterializeAccordingToType (Address (dest), MetaDataProvider.ManagedPointer (type), 0);
+ }
+
+ public void MaterializeAccordingToType (SymValue sv, TypeNode type, int depth)
+ {
+ SetType (sv, type);
+ if (depth > 2)
+ return;
+
+ if (MetaDataProvider.IsManagedPointer (type)) {
+ TypeNode elementType = MetaDataProvider.ElementType (type);
+ if (!MetaDataProvider.HasValueRepresentation (elementType)) {
+ ManifestStructId (sv);
+ foreach (Field field in MetaDataProvider.Fields (elementType)) {
+ if (!MetaDataProvider.IsStatic (field)) {
+ TypeNode fieldAddressType;
+ MaterializeAccordingToType (FieldAddress (sv, field, out fieldAddressType), fieldAddressType, depth + 1);
+ }
+ }
+ foreach (Property property in MetaDataProvider.Properties (elementType)) {
+ Method getter;
+ if (!MetaDataProvider.IsStatic (property) && MetaDataProvider.HasGetter (property, out getter)) {
+ TypeNode pseudoFieldAddressType;
+ MaterializeAccordingToType (PseudoFieldAddress (sv, getter, out pseudoFieldAddressType, false), pseudoFieldAddressType, depth + 1);
+ }
+ }
+ } else
+ MaterializeAccordingToType (Value (sv), elementType, depth + 1);
+ }
+ }
+
+ public void ManifestStructId (SymValue sv)
+ {
+ StructId (sv);
+ }
+
+ public SymValue StructId (SymValue sv)
+ {
+ return this.egraph [this.Functions.StructId, sv];
+ }
+
+ private SymValue LookupAddressAndManifestType (SymValue sv, SymFunction c, TypeNode type, out bool fresh)
+ {
+ SymValue value = this.egraph.TryLookup (c, sv);
+ if (value != null) {
+ fresh = false;
+ return value;
+ }
+
+ fresh = true;
+ value = this.egraph [c, sv];
+ SetType (value, type);
+
+ return value;
+ }
+
+ public void HavocFields (SymValue sv, IEnumerable<Field> fields, ref IImmutableSet<SymValue> havoced)
+ {
+ foreach (Field f in fields)
+ HavocConstructor (null, sv, this.Functions.For (f), ref havoced, false);
+ }
+
+ private bool IsUnmodifiedForFields (SymValue sv)
+ {
+ return this.unmodifiedFieldsSinceEntry.Contains (sv);
+ }
+
+ public void HavocUp (SymValue srcAddr, ref IImmutableSet<SymValue> havocedAtCall, bool havocFields)
+ {
+ foreach (var term in this.egraph.EqTerms (srcAddr)) {
+ if (term.Function == this.Functions.ValueOf)
+ HavocUpField (term.Args [0], ref havocedAtCall, havocFields);
+ }
+ }
+
+ private void HavocUpField (SymValue sv, ref IImmutableSet<SymValue> havocedAtCall, bool havocFields)
+ {
+ foreach (var term in this.egraph.EqTerms (sv)) {
+ SymFunction accessedVia = term.Function;
+ if (accessedVia is Wrapper<Field>)
+ HavocUpObjectVersion (accessedVia, term.Args [0], ref havocedAtCall, havocFields);
+ else {
+ var methodWrapper = accessedVia as Wrapper<Method>;
+ Property property;
+ if (methodWrapper != null && !MetaDataProvider.IsStatic (methodWrapper.Item) && MetaDataProvider.IsPropertyGetter (methodWrapper.Item, out property))
+ HavocUpObjectVersion (accessedVia, term.Args [0], ref havocedAtCall, havocFields);
+ }
+ }
+ }
+
+ private void HavocUpObjectVersion (SymFunction accessedVia, SymValue sv, ref IImmutableSet<SymValue> havocedAtCall, bool havocFields)
+ {
+ if (havocedAtCall.Contains (sv))
+ return;
+ this.egraph.Eliminate (this.Functions.ObjectVersion, sv);
+ if (havocFields)
+ HavocMutableFields (accessedVia, sv, ref havocedAtCall);
+ else
+ HavocPseudoFields (accessedVia, sv, ref havocedAtCall);
+
+ HavocUp (sv, ref havocedAtCall, false);
+ }
+
+ public void CopyAddress (SymValue destAddr, SymValue srcAddr, TypeNode type)
+ {
+ this.egraph [this.Functions.ValueOf, destAddr] = srcAddr;
+ SetType (destAddr, MetaDataProvider.ManagedPointer (type));
+ }
+
+ public void AssignArrayLength (SymValue destAddr, SymValue array)
+ {
+ SymValue length = this.egraph [this.Functions.Length, array];
+ SetType (length, MetaDataProvider.System_Int32);
+ this.egraph [this.Functions.ValueOf, destAddr] = length;
+ SetType (destAddr, MetaDataProvider.ManagedPointer (MetaDataProvider.System_Int32));
+ }
+
+ public void ResetModifiedAtCall ()
+ {
+ this.ModifiedAtCall = ImmutableSet<SymValue>.Empty (SymValue.GetUniqueKey);
+ }
+
+ public SymValue LoadValue (int source)
+ {
+ return Value (source);
+ }
+
+ public SymbolicValue TryLoadValue (SymValue addr)
+ {
+ return new SymbolicValue (Value (addr));
+ }
+
+ public bool TryGetArrayLength (SymValue arrayValue, out SymValue length)
+ {
+ length = this.egraph.TryLookup (this.Functions.Length, arrayValue);
+ return length != null;
+ }
+
+ public bool TryGetCorrespondingValueAbstraction (Parameter p, out SymbolicValue sv)
+ {
+ return TryGetCorrespondingValueAbstraction (this.Functions.For (p), out sv);
+ }
+
+ public string GetAccessPath (SymValue sv)
+ {
+ LispList<PathElementBase> bestAccessPath = GetBestAccessPath (sv, AccessPathFilter<Method>.NoFilter, true, true, false);
+ if (bestAccessPath == null)
+ return null;
+
+ return bestAccessPath.Select (i => (PathElement) i).ToCodeString ();
+ }
+
+ public LispList<PathElement> GetAccessPathList (SymValue symbol, AccessPathFilter<Method> filter, bool allowLocal, bool preferLocal)
+ {
+ return GetBestAccessPath (symbol, filter, true, allowLocal, preferLocal).Coerce<PathElementBase, PathElement> ();
+ }
+
+ public bool LessEqual (Domain that, out IImmutableMap<SymValue, LispList<SymValue>> forward, out IImmutableMap<SymValue, SymValue> backward)
+ {
+ return this.egraph.LessEqual (that.egraph, out forward, out backward);
+ }
+
+ public bool IsResultEGraph (IMergeInfo mi)
+ {
+ return mi.IsResultGraph (this.egraph);
+ }
+
+ public bool IsGraph1 (IMergeInfo mi)
+ {
+ return mi.IsGraph1 (this.egraph);
+ }
+
+ public bool IsGraph2 (IMergeInfo mi)
+ {
+ return mi.IsGraph2 (this.egraph);
+ }
+
+ public IImmutableMap<SymValue, LispList<SymValue>> GetForwardIdentityMap ()
+ {
+ return this.egraph.GetForwardIdentityMap ();
+ }
+
+ public Domain Join (Domain that, bool widening, out bool weaker, out IMergeInfo mergeInfo)
+ {
+ SymGraph<SymFunction, AbstractType> graph = this.egraph.Join (that.egraph, out mergeInfo, widening);
+ weaker = mergeInfo.Changed;
+
+ IImmutableSet<SymValue> resultUnmodifiedSinceEntry;
+ IImmutableSet<SymValue> resultUnmodifiedFieldsSinceEntry;
+ IImmutableSet<SymValue> resultModifiedAtCall;
+
+ ComputeJoinOfSets (mergeInfo, this, that, out resultUnmodifiedSinceEntry, out resultUnmodifiedFieldsSinceEntry, out resultModifiedAtCall, ref weaker);
+ Domain oldDomain = null;
+ if (OldDomain != null) {
+ bool oldWeaker;
+ IMergeInfo oldMergeInfo;
+ oldDomain = OldDomain.Join (that.OldDomain, widening, out oldWeaker, out oldMergeInfo);
+ }
+
+ return new Domain (graph, RecomputeConstantMap (graph), resultUnmodifiedSinceEntry, resultUnmodifiedFieldsSinceEntry, resultModifiedAtCall, this, oldDomain);
+ }
+
+ private IImmutableMap<SymValue, SymFunction> RecomputeConstantMap (SymGraph<SymFunction, AbstractType> graph)
+ {
+ IImmutableMap<SymValue, SymFunction> result = ImmutableIntKeyMap<SymValue, SymFunction>.Empty (SymValue.GetUniqueKey);
+ foreach (SymFunction constant in graph.Constants) {
+ if (this.Functions.IsConstantOrMethod (constant))
+ result.Add (graph [constant], constant);
+ }
+ return result;
+ }
+
+ private void ComputeJoinOfSets (IMergeInfo mergeInfo, Domain domain, Domain that,
+ out IImmutableSet<SymValue> resultUnmodifiedSinceEntry,
+ out IImmutableSet<SymValue> resultUnmodifiedFieldsSinceEntry,
+ out IImmutableSet<SymValue> resultModifiedAtCall, ref bool weaker)
+ {
+ resultUnmodifiedSinceEntry = ImmutableSet<SymValue>.Empty (SymValue.GetUniqueKey);
+ resultUnmodifiedFieldsSinceEntry = ImmutableSet<SymValue>.Empty (SymValue.GetUniqueKey);
+ resultModifiedAtCall = ImmutableSet<SymValue>.Empty (SymValue.GetUniqueKey);
+
+ foreach (var tuple in mergeInfo.MergeTriples) {
+ SymValue symValue1 = tuple.Item1;
+ SymValue symValue2 = tuple.Item2;
+ SymValue elem = tuple.Item3;
+
+ bool unmodifiedSinceEntryContains = domain.unmodifiedSinceEntry.ContainsSafe (symValue1);
+ bool modifiedAtCallContains = domain.ModifiedAtCall.ContainsSafe (symValue1);
+
+ if (unmodifiedSinceEntryContains) {
+ if (that.unmodifiedSinceEntry.ContainsSafe (symValue2))
+ resultUnmodifiedSinceEntry = resultUnmodifiedSinceEntry.Add (elem);
+ else if (that.unmodifiedFieldsSinceEntry.ContainsSafe (symValue2))
+ resultUnmodifiedFieldsSinceEntry = resultUnmodifiedFieldsSinceEntry.Add (elem);
+ }
+
+ if (modifiedAtCallContains)
+ resultModifiedAtCall = resultModifiedAtCall.Add (elem);
+ }
+
+ if (that.unmodifiedSinceEntry.Count () > resultUnmodifiedSinceEntry.Count ()) {
+ weaker = true;
+ if (DebugOptions.Debug)
+ Console.WriteLine ("---Result changed due to fewer unmodified locations since entry");
+ } else {
+ if (that.unmodifiedFieldsSinceEntry.Count () > resultUnmodifiedFieldsSinceEntry.Count ()) {
+ weaker = true;
+ if (DebugOptions.Debug)
+ Console.WriteLine ("---Result changed due to fewer unmodified locations for fields since entry");
+ }
+ }
+ }
+
+ #region Implementation of IAbstractDomain<Domain>
+ public Domain Top
+ {
+ get
+ {
+ return new Domain (this.egraph.Top, ImmutableIntKeyMap<SymValue, SymFunction>.Empty (SymValue.GetUniqueKey), ImmutableSet<SymValue>.Empty (SymValue.GetUniqueKey),
+ ImmutableSet<SymValue>.Empty (SymValue.GetUniqueKey), ImmutableSet<SymValue>.Empty (SymValue.GetUniqueKey), this, null);
+ }
+ }
+
+ public Domain Bottom
+ {
+ get
+ {
+ if (BottomValue == null) {
+ BottomValue = new Domain (this.egraph.Bottom, ImmutableIntKeyMap<SymValue, SymFunction>.Empty (SymValue.GetUniqueKey), ImmutableSet<SymValue>.Empty (SymValue.GetUniqueKey),
+ ImmutableSet<SymValue>.Empty (SymValue.GetUniqueKey), ImmutableSet<SymValue>.Empty (SymValue.GetUniqueKey),
+ this, null);
+ BottomValue.ImmutableVersion ();
+ }
+ return BottomValue;
+ }
+ }
+
+ public bool IsTop
+ {
+ get { return this.egraph.IsTop; }
+ }
+
+ public bool IsBottom
+ {
+ get
+ {
+ if (this == BottomValue || this.egraph.IsBottom)
+ return true;
+ if (OldDomain != null)
+ return OldDomain.IsBottom;
+
+ return false;
+ }
+ }
+
+ public Domain Join (Domain that, bool widening, out bool weaker)
+ {
+ IMergeInfo mergeInfo;
+ return Join (that, widening, out weaker, out mergeInfo);
+ }
+
+ public Domain Meet (Domain that)
+ {
+ SymGraph<SymFunction, AbstractType> graph = this.egraph.Meet (that.egraph);
+ return new Domain (graph, RecomputeConstantMap (graph), this.unmodifiedSinceEntry, this.unmodifiedFieldsSinceEntry, null, this, OldDomain);
+ }
+
+ public bool LessEqual (Domain that)
+ {
+ return this.egraph.LessEqual (that.egraph);
+ }
+
+ public Domain ImmutableVersion ()
+ {
+ this.egraph.ImmutableVersion ();
+ return this;
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// FunctionsTable.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis {
+ class FunctionsTable
+ {
+ public readonly SymFunction BoxOperator;
+ public readonly SymFunction ElementAddress;
+ public readonly SymFunction Length;
+ public readonly SymFunction NeZero;
+ public readonly SymFunction NullValue;
+ public readonly SymFunction ObjectVersion;
+ public readonly SymFunction OldValueOf;
+ public readonly SymFunction ResultOfCall;
+ public readonly SymFunction ResultOfLoadElement;
+ public readonly SymFunction StructId;
+ public readonly SymFunction UnaryNot;
+ public readonly SymFunction ValueOf;
+ public readonly SymFunction VoidAddr;
+ public readonly SymFunction ZeroValue;
+ private readonly Dictionary<BinaryOperator, Wrapper<BinaryOperator>> binary_operators;
+ private readonly Dictionary<Field, Wrapper<Field>> fields;
+ private readonly Dictionary<Local, Wrapper<Local>> locals;
+ private readonly IMetaDataProvider meta_data_provider;
+ private readonly Dictionary<Method, Wrapper<Method>> method_pointers;
+ private readonly Dictionary<Parameter, Wrapper<Parameter>> parameters;
+ private readonly Dictionary<object, Wrapper<object>> program_constants;
+ private readonly Dictionary<Method, Wrapper<Method>> pseudo_fields;
+ private readonly Dictionary<string, Wrapper<string>> strings;
+ private readonly Dictionary<int, Wrapper<int>> temp;
+ private readonly Dictionary<UnaryOperator, Wrapper<UnaryOperator>> unary_operators;
+
+ private int id_gen;
+
+ public FunctionsTable(IMetaDataProvider metaDataProvider)
+ {
+ this.meta_data_provider = metaDataProvider;
+ this.locals = new Dictionary<Local, Wrapper<Local>> ();
+ this.parameters = new Dictionary<Parameter, Wrapper<Parameter>> ();
+ this.fields = new Dictionary<Field, Wrapper<Field>> ();
+ this.pseudo_fields = new Dictionary<Method, Wrapper<Method>> ();
+ this.temp = new Dictionary<int, Wrapper<int>> ();
+ this.strings = new Dictionary<string, Wrapper<string>> ();
+ this.program_constants = new Dictionary<object, Wrapper<object>> ();
+ this.method_pointers = new Dictionary<Method, Wrapper<Method>> ();
+ this.binary_operators = new Dictionary<BinaryOperator, Wrapper<BinaryOperator>> ();
+ this.unary_operators = new Dictionary<UnaryOperator, Wrapper<UnaryOperator>> ();
+
+ this.ValueOf = For ("$Value");
+ this.OldValueOf = For ("$OldValue");
+ this.StructId = For ("$StructId");
+ this.ObjectVersion = For ("$ObjectVersion");
+ this.NullValue = For ("$Null");
+ this.ElementAddress = For ("$ElementAddress");
+ this.Length = For ("$Length");
+ this.VoidAddr = For ("$VoidAddr");
+ this.UnaryNot = For ("$UnaryNot");
+ this.NeZero = For ("$NeZero");
+ this.BoxOperator = For ("$Box");
+ this.ResultOfCall = For ("$ResultOfCall");
+ this.ResultOfLoadElement = For ("$ResultOfLoadElement");
+ this.ZeroValue = ForConstant (0, this.meta_data_provider.System_Int32);
+ }
+
+ private Wrapper<T> For<T>(T key, Dictionary<T, Wrapper<T>> cache)
+ {
+ Wrapper<T> wrapper;
+ if (!cache.TryGetValue (key, out wrapper)) {
+ wrapper = SymFunction.For (key, ref this.id_gen, this.meta_data_provider);
+ cache.Add (key, wrapper);
+ }
+ return wrapper;
+ }
+
+ public SymFunction For(Local v)
+ {
+ return For (v, this.locals);
+ }
+
+ public SymFunction For(Parameter v)
+ {
+ return For (v, this.parameters);
+ }
+
+ public SymFunction For(Field v)
+ {
+ v = this.meta_data_provider.Unspecialized (v);
+ return For (v, this.fields);
+ }
+
+ public SymFunction For(Method v)
+ {
+ return For (v, this.pseudo_fields);
+ }
+
+ public SymFunction For(string v)
+ {
+ return For (v, this.strings);
+ }
+
+ public SymFunction For(int v)
+ {
+ return For (v, this.temp);
+ }
+
+ public SymFunction For(BinaryOperator v)
+ {
+ return For (v, this.binary_operators);
+ }
+
+ public SymFunction For(UnaryOperator v)
+ {
+ return For (v, this.unary_operators);
+ }
+
+ public SymFunction ForConstant(object constant, TypeNode type)
+ {
+ Wrapper<object> wrapper = For (constant, this.program_constants);
+ wrapper.Type = type;
+ return wrapper;
+ }
+
+ public SymFunction ForMethod(Method method, TypeNode type)
+ {
+ Wrapper<Method> wrapper = For (method, this.method_pointers);
+ wrapper.Type = type;
+ return wrapper;
+ }
+
+ public bool IsConstantOrMethod(SymFunction constant)
+ {
+ var wrapper = constant as Wrapper<object>;
+ if (wrapper != null && this.program_constants.ContainsKey (wrapper.Item))
+ return true;
+
+ var wrapper1 = constant as Wrapper<Method>;
+ if (wrapper1 != null && this.method_pointers.ContainsKey (wrapper1.Item))
+ return true;
+
+ return false;
+ }
+
+ public bool IsConstant(SymFunction c, out TypeNode type, out object value)
+ {
+ var wrapper = c as Wrapper<object>;
+ if (wrapper != null && this.program_constants.ContainsKey (wrapper.Item)) {
+ type = wrapper.Type;
+ value = wrapper.Item;
+ return true;
+ }
+
+ type = null;
+ value = null;
+ return false;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// HeapAnalysis.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataFlowAnalysis;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis {
+ class HeapAnalysis : IAnalysis<APC, Domain, IILVisitor<APC, int, int, Domain, Domain>, Dummy> {
+ private readonly Dictionary<Pair<APC, APC>, IImmutableMap<SymbolicValue, LispList<SymbolicValue>>> forwardRenamings =
+ new Dictionary<Pair<APC, APC>, IImmutableMap<SymbolicValue, LispList<SymbolicValue>>> ();
+
+ public readonly Dictionary<APC, IMergeInfo> MergeInfoCache = new Dictionary<APC, IMergeInfo> ();
+ public readonly DoubleDictionary<APC, APC, Dummy> RenamePoints = new DoubleDictionary<APC, APC, Dummy> ();
+ private readonly ICodeLayer<int, int, IStackContextProvider, Dummy> stackLayer;
+ private IFixPointInfo<APC, Domain> fixPointInfo;
+
+ public HeapAnalysis (ICodeLayer<int, int, IStackContextProvider, Dummy> stackLayer)
+ {
+ this.stackLayer = stackLayer;
+ }
+
+ public IStackContextProvider StackContextProvider
+ {
+ get { return this.stackLayer.ILDecoder.ContextProvider; }
+ }
+
+ public IMetaDataProvider MetaDataProvider
+ {
+ get { return this.stackLayer.MetaDataProvider; }
+ }
+
+ public IContractProvider ContractProvider
+ {
+ get { return this.stackLayer.ContractProvider; }
+ }
+
+ public Method CurrentMethod
+ {
+ get { return this.StackContextProvider.MethodContext.CurrentMethod; }
+ }
+
+ IILVisitor<APC, int, int, Domain, Domain> IAnalysis<APC, Domain, IILVisitor<APC, int, int, Domain, Domain>, Dummy>.
+ GetVisitor ()
+ {
+ return GetVisitor ();
+ }
+
+ public Domain Join (Pair<APC, APC> edge, Domain newstate, Domain prevstate, out bool weaker, bool widen)
+ {
+ if (DebugOptions.Debug)
+ {
+ Console.WriteLine ("-----OPT Join at {0}", edge);
+ Console.WriteLine ("-----Existing state:");
+ prevstate.Dump (Console.Out);
+ Console.WriteLine ("-----New state:");
+ newstate.Dump (Console.Out);
+ }
+
+ IMergeInfo mi;
+ Domain domain = prevstate.Join (newstate, widen, out weaker, out mi);
+ if (weaker) {
+ IMergeInfo mi2;
+ if (this.MergeInfoCache.TryGetValue (edge.Value, out mi2) && mi2 == null)
+ this.MergeInfoCache [edge.Value] = mi;
+ } else
+ this.MergeInfoCache [edge.Value] = mi;
+
+ if (DebugOptions.Debug)
+ {
+ Console.WriteLine ("-----Result state: changed = {0} (widen = {1})", weaker ? 1 : 0, widen ? 1 : 0);
+ domain.Dump (Console.Out);
+ Console.WriteLine ("----------------------------------------------");
+ }
+
+ return domain;
+ }
+
+ public Domain ImmutableVersion (Domain arg)
+ {
+ return arg.ImmutableVersion ();
+ }
+
+ public Domain MutableVersion (Domain arg)
+ {
+ if (arg.IsBottom)
+ return arg;
+ return arg.Clone ();
+ }
+
+ public Domain EdgeConversion (APC @from, APC to, bool isJoinPoint, Dummy data, Domain state)
+ {
+ if (isJoinPoint) {
+ this.RenamePoints [from, to] = Dummy.Value;
+ if (!this.MergeInfoCache.ContainsKey (to))
+ this.MergeInfoCache.Add (to, null);
+ }
+
+ if (DebugOptions.Debug)
+ {
+ Console.WriteLine ("----Edge conversion on {0}->{1}------", from, to);
+ state.Dump (Console.Out);
+ Console.WriteLine ("-------------------------------------");
+ }
+
+ return state;
+ }
+
+ public bool IsBottom (APC pc, Domain state)
+ {
+ return state.IsBottom;
+ }
+
+ public Predicate<APC> SaveFixPointInfo (IFixPointInfo<APC, Domain> fixPointInfo)
+ {
+ this.fixPointInfo = fixPointInfo;
+ return pc => true;
+ }
+
+ public void Dump (Pair<Domain, TextWriter> pair)
+ {
+ pair.Key.Dump (pair.Value);
+ }
+
+ private IILVisitor<APC, int, int, Domain, Domain> GetVisitor ()
+ {
+ return new AnalysisDecoder (this);
+ }
+
+ public Domain InitialValue ()
+ {
+ return new Domain (this);
+ }
+
+ public IILDecoder<APC, SymbolicValue, SymbolicValue, IValueContextProvider<SymbolicValue>, IImmutableMap<SymbolicValue, LispList<SymbolicValue>>>
+ GetDecoder<Context>(IILDecoder<APC, int, int, Context, Dummy> underlying)
+ where Context : IStackContextProvider
+ {
+ return new ValueDecoder<Context> (this, underlying);
+ }
+
+ public bool IsUnreachable (APC pc)
+ {
+ Domain domain;
+ if (!this.fixPointInfo.PreStateLookup (pc, out domain) || domain.IsBottom)
+ return true;
+
+ return false;
+ }
+
+ public IImmutableMap<SymbolicValue, LispList<SymbolicValue>> EdgeRenaming (Pair<APC, APC> edge, bool isJoinPoint)
+ {
+ IImmutableMap<SymbolicValue, LispList<SymbolicValue>> forwardRenaming;
+
+ if (this.forwardRenamings.TryGetValue (edge, out forwardRenaming))
+ return forwardRenaming;
+
+ IImmutableMap<SymbolicValue, LispList<SymbolicValue>> renaming = null;
+ Domain afterBegin;
+ PostStateLookup (edge.Key, out afterBegin);
+ if (afterBegin == null || afterBegin.IsBottom)
+ return null;
+ Domain beforeEnd;
+ PreStateLookup (edge.Value, out beforeEnd);
+ if (beforeEnd != null) {
+ IImmutableMap<SymValue, LispList<SymValue>> forward;
+ if (!TryComputeFromJoinCache (afterBegin, beforeEnd, edge.Value, out forward)) {
+ IImmutableMap<SymValue, SymValue> backward;
+ if (!afterBegin.LessEqual (beforeEnd, out forward, out backward))
+ throw new InvalidOperationException ("Should never happen");
+ if (isJoinPoint && forward == null)
+ forward = afterBegin.GetForwardIdentityMap ();
+ }
+ if (forward != null) {
+ renaming = ImmutableIntKeyMap<SymbolicValue, LispList<SymbolicValue>>.Empty (SymbolicValue.GetUniqueKey);
+ foreach (SymValue sv in forward.Keys) {
+ LispList<SymbolicValue> targets = null;
+ foreach (SymValue target in forward [sv].AsEnumerable ())
+ targets = targets.Cons (new SymbolicValue (target));
+ if (targets != null)
+ renaming = renaming.Add (new SymbolicValue (sv), targets);
+ }
+ }
+ }
+ this.forwardRenamings.Add (edge, renaming);
+ return renaming;
+ }
+
+ private bool TryComputeFromJoinCache (Domain inDomain, Domain outDomain, APC joinPoint, out IImmutableMap<SymValue, LispList<SymValue>> forward)
+ {
+ forward = null;
+ IMergeInfo mi;
+ if (this.MergeInfoCache.TryGetValue (joinPoint, out mi) && mi != null && outDomain.IsResultEGraph (mi)) {
+ if (inDomain.IsGraph1 (mi)) {
+ forward = mi.ForwardG1Map;
+ return true;
+ }
+ if (inDomain.IsGraph2 (mi)) {
+ forward = mi.ForwardG2Map;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public Domain GetPreState (APC pc)
+ {
+ Domain domain;
+ PreStateLookup (pc, out domain);
+ return domain;
+ }
+
+ public bool PreStateLookup (APC pc, out Domain ifFound)
+ {
+ return this.fixPointInfo.PreStateLookup (pc, out ifFound);
+ }
+
+ public bool PostStateLookup (APC pc, out Domain ifFound)
+ {
+ return this.fixPointInfo.PostStateLookup (pc, out ifFound);
+ }
+ }
+}
--- /dev/null
+//
+// IAbstractDomainForEGraph.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.Lattices;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis {
+ interface IAbstractDomainForEGraph<TADomain> : IAbstractDomain<TADomain> {
+ bool HasAllBottomFields { get; }
+ TADomain ForManifestedField ();
+ }
+}
--- /dev/null
+//
+// IConstantInfo.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis {
+ interface IConstantInfo {
+ bool KeepAsBottomField { get; }
+ bool ManifestField { get; }
+ }
+}
--- /dev/null
+//
+// ISymGraph.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Lattices;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis {
+ interface ISymGraph<TFunc, TADomain, TGraph> : IAbstractDomain<TGraph>
+ where TFunc : IEquatable<TFunc>, IConstantInfo
+ where TADomain : IAbstractDomainForEGraph<TADomain> {
+ SymValue this [TFunc function, SymValue arg] { get; set; }
+ SymValue this [TFunc function] { get; set; }
+ TADomain this [SymValue symbol] { get; set; }
+ IEnumerable<TFunc> Constants { get; }
+ IEnumerable<SymValue> Variables { get; }
+
+ SymValue FreshSymbol ();
+
+ SymValue TryLookup (TFunc function, SymValue arg);
+ SymValue TryLookup (TFunc function);
+
+ IEnumerable<TFunc> Functions (SymValue symbol);
+ IEnumerable<SymGraphTerm<TFunc>> EqTerms (SymValue symbol);
+
+ void AssumeEqual (SymValue v1, SymValue v2);
+ bool IsEqual (SymValue v1, SymValue v2);
+ void Eliminate (TFunc function, SymValue arg);
+ void Eliminate (TFunc function);
+ void EliminateAll (SymValue arg);
+
+ TGraph Join (TGraph that, out IMergeInfo mergeInfo, bool widen);
+
+ bool LessEqual (TGraph that, out IImmutableMap<SymValue, LispList<SymValue>> forward,
+ out IImmutableMap<SymValue, SymValue> backward);
+ }
+}
--- /dev/null
+//
+// LabeledSymbol.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis {
+ struct LabeledSymbol<Label, TSymValue> : IEquatable<LabeledSymbol<Label, TSymValue>>
+ where TSymValue : IEquatable<TSymValue> {
+ public readonly Label ReadAt;
+ public readonly TSymValue Symbol;
+
+ public LabeledSymbol (Label readAt, TSymValue symbol)
+ {
+ this.ReadAt = readAt;
+ this.Symbol = symbol;
+ }
+
+ #region Implementation of IEquatable<ExternalExpression<Label,SymbolicValue>>
+ public bool Equals (LabeledSymbol<Label, TSymValue> other)
+ {
+ return this.Symbol.Equals (other.Symbol);
+ }
+ #endregion
+
+ public override bool Equals (object obj)
+ {
+ return obj is LabeledSymbol<Label, TSymValue> && Equals ((LabeledSymbol<Label, TSymValue>) obj);
+ }
+
+ public override int GetHashCode ()
+ {
+ return this.Symbol.GetHashCode ();
+ }
+
+ public override string ToString ()
+ {
+ return string.Format ("{0}@{1}", this.Symbol, this.ReadAt);
+ }
+ }
+}
--- /dev/null
+//
+// MethodWrapper.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis {
+ class MethodWrapper : Wrapper<Method> {
+ public MethodWrapper (Method value, ref int idGen, IMetaDataProvider metaDataProvider)
+ : base (value, ref idGen, metaDataProvider)
+ {
+ }
+
+ public override bool ActsAsField
+ {
+ get { return true; }
+ }
+
+ public override TypeNode FieldAddressType ()
+ {
+ return this.MetaDataProvider.ManagedPointer (this.MetaDataProvider.ReturnType (this.Item));
+ }
+ }
+}
--- /dev/null
+//
+// ParameterWrapper.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis {
+ class ParameterWrapper : Wrapper<Parameter>
+ {
+ private readonly int parameter_index;
+
+ public ParameterWrapper(Parameter parameter, ref int idGen, IMetaDataProvider metaDataProvider)
+ : base (parameter, ref idGen, metaDataProvider)
+ {
+ this.parameter_index = metaDataProvider.ParameterIndex (parameter);
+ }
+
+ public override bool ActsAsField
+ {
+ get { return false; }
+ }
+
+ public override TypeNode FieldAddressType()
+ {
+ throw new InvalidOperationException ();
+ }
+
+ public override string ToString()
+ {
+ return this.MetaDataProvider.Name (this.Item);
+ }
+
+ public override bool Equals(object obj)
+ {
+ var other = obj as ParameterWrapper;
+ if (other == null)
+ return false;
+
+ return other.parameter_index == this.parameter_index;
+ }
+
+ public override int GetHashCode()
+ {
+ return this.parameter_index;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// StackToSymbolicAdapter.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis {
+ struct StackToSymbolicAdapter<Data, Result, Visitor> : IILVisitor<APC, int, int, Data, Result>
+ where Visitor : IILVisitor<APC, SymbolicValue, SymbolicValue, Data, Result> {
+ private readonly Visitor delegatee;
+ private readonly HeapAnalysis parent;
+
+ public StackToSymbolicAdapter (HeapAnalysis parent, Visitor delegatee)
+ {
+ this.parent = parent;
+ this.delegatee = delegatee;
+ }
+
+ private bool PreStateLookup (APC pc, out Domain domain)
+ {
+ return this.parent.PreStateLookup (pc, out domain);
+ }
+
+ private bool PostStateLookup (APC pc, out Domain domain)
+ {
+ return this.parent.PostStateLookup (pc, out domain);
+ }
+
+ private SymbolicValue ConvertSource (APC pc, int source)
+ {
+ Domain domain;
+ if (!PreStateLookup (pc, out domain) || domain.IsBottom)
+ return new SymbolicValue ();
+ if (source < 0)
+ return new SymbolicValue (domain.VoidAddr);
+
+ SymbolicValue sv;
+ domain.TryGetCorrespondingValueAbstraction (source, out sv);
+ return sv;
+ }
+
+ private SymbolicValue ConvertOldSource (APC pc, int source)
+ {
+ Domain domain;
+ if (!PreStateLookup (pc, out domain) || domain.IsBottom)
+ return new SymbolicValue ();
+
+ if (source < 0)
+ return new SymbolicValue (domain.VoidAddr);
+
+ Domain oldDomain = AnalysisDecoder.FindOldState (pc, domain);
+ if (oldDomain == null)
+ return new SymbolicValue (domain.VoidAddr);
+
+ SymbolicValue sv;
+ oldDomain.TryGetCorrespondingValueAbstraction (source, out sv);
+ return sv;
+ }
+
+ private SymbolicValue ConvertDest (APC pc, int dest)
+ {
+ Domain domain;
+ if (!PostStateLookup (pc, out domain))
+ return new SymbolicValue ();
+
+ SymbolicValue sv;
+ domain.TryGetCorrespondingValueAbstraction (dest, out sv);
+ return sv;
+ }
+
+ private SymbolicValue ConvertOldDest (APC pc, int dest)
+ {
+ SymbolicValue sv = default(SymbolicValue);
+ Domain domain;
+ if (!PostStateLookup (pc, out domain))
+ return sv;
+
+ domain.OldDomain.TryGetCorrespondingValueAbstraction (dest, out sv);
+ return sv;
+ }
+
+ private SymbolicValue ConvertSourceDeref (APC pc, int source)
+ {
+ Domain domain;
+ if (!PreStateLookup (pc, out domain))
+ return new SymbolicValue ();
+ if (source < 0)
+ return new SymbolicValue (domain.VoidAddr);
+
+ SymValue addr = domain.LoadValue (source);
+ if (!PostStateLookup (pc, out domain))
+ return new SymbolicValue ();
+
+ return domain.TryLoadValue (addr);
+ }
+
+ private SymbolicValue TryConvertUnbox (APC pc, int source)
+ {
+ Domain domain;
+ if (!PreStateLookup (pc, out domain))
+ return new SymbolicValue ();
+
+ if (source < 0)
+ return new SymbolicValue (domain.VoidAddr);
+
+ SymbolicValue sv;
+ if (!domain.TryGetUnboxedValue (source, out sv))
+ domain.TryGetCorrespondingValueAbstraction (source, out sv);
+ return sv;
+ }
+
+ private ArgumentSourceWrapper<ArgList> ConvertSources<ArgList> (APC pc, ArgList args)
+ where ArgList : IIndexable<int>
+ {
+ return new ArgumentSourceWrapper<ArgList> (args, this.parent.GetPreState (pc));
+ }
+
+ private bool InsideOld (APC pc)
+ {
+ Domain domain;
+ return PreStateLookup (pc, out domain) && domain.OldDomain != null;
+ }
+
+ #region Implementation of IExpressionILVisitor<APC,int,int,Data,Result>
+ public Result Binary (APC pc, BinaryOperator op, int dest, int operand1, int operand2, Data data)
+ {
+ if (op != BinaryOperator.Cobjeq) {
+ return this.delegatee.Binary (pc, op, ConvertDest (pc, dest),
+ ConvertSource (pc, operand1), ConvertSource (pc, operand2),
+ data);
+ }
+
+ SymbolicValue op1 = TryConvertUnbox (pc, operand1);
+ SymbolicValue op2 = TryConvertUnbox (pc, operand2);
+
+ return this.delegatee.Binary (pc, op, ConvertDest (pc, dest), op1, op2, data);
+ }
+
+ public Result Isinst (APC pc, TypeNode type, int dest, int obj, Data data)
+ {
+ return this.delegatee.Isinst (pc, type, ConvertDest (pc, dest), ConvertSource (pc, obj), data);
+ }
+
+ public Result LoadNull (APC pc, int dest, Data polarity)
+ {
+ return this.delegatee.LoadNull (pc, ConvertDest (pc, dest), polarity);
+ }
+
+ public Result LoadConst (APC pc, TypeNode type, object constant, int dest, Data data)
+ {
+ return this.delegatee.LoadConst (pc, type, constant, ConvertDest (pc, dest), data);
+ }
+
+ public Result Sizeof (APC pc, TypeNode type, int dest, Data data)
+ {
+ return this.delegatee.Sizeof (pc, type, ConvertDest (pc, dest), data);
+ }
+
+ public Result Unary (APC pc, UnaryOperator op, bool unsigned, int dest, int source, Data data)
+ {
+ return this.delegatee.Unary (pc, op, unsigned, ConvertDest (pc, dest), ConvertSource (pc, source), data);
+ }
+ #endregion
+
+ #region Implementation of ISyntheticILVisitor<APC,int,int,Data,Result>
+ public Result Entry (APC pc, Method method, Data data)
+ {
+ return this.delegatee.Entry (pc, method, data);
+ }
+
+ public Result Assume (APC pc, EdgeTag tag, int source, Data data)
+ {
+ return this.delegatee.Assume (pc, tag, ConvertSource (pc, source), data);
+ }
+
+ public Result Assert (APC pc, EdgeTag tag, int source, Data data)
+ {
+ return this.delegatee.Assert (pc, tag, ConvertSource (pc, source), data);
+ }
+
+ public Result BeginOld (APC pc, APC matchingEnd, Data data)
+ {
+ return this.delegatee.BeginOld (pc, matchingEnd, data);
+ }
+
+ public Result EndOld (APC pc, APC matchingBegin, TypeNode type, int dest, int source, Data data)
+ {
+ return this.delegatee.Nop (pc, data);
+ }
+
+ public Result LoadStack (APC pc, int offset, int dest, int source, bool isOld, Data data)
+ {
+ SymbolicValue src = isOld ? ConvertOldSource (pc, source) : ConvertSource (pc, source);
+ return this.delegatee.LoadStack (pc, offset, ConvertDest (pc, dest), src, isOld, data);
+ }
+
+ public Result LoadStackAddress (APC pc, int offset, int dest, int source, TypeNode type, bool isOld, Data data)
+ {
+ return this.delegatee.LoadStackAddress (pc, offset, ConvertDest (pc, dest), ConvertSource (pc, source), type, isOld, data);
+ }
+
+ public Result LoadResult (APC pc, TypeNode type, int dest, int source, Data data)
+ {
+ return this.delegatee.LoadResult (pc, type, ConvertDest (pc, dest), ConvertSource (pc, source), data);
+ }
+ #endregion
+
+ #region Implementation of IILVisitor<APC,int,int,Data,Result>
+ public Result Arglist (APC pc, int dest, Data data)
+ {
+ return this.delegatee.Arglist (pc, ConvertDest (pc, dest), data);
+ }
+
+ public Result Branch (APC pc, APC target, bool leavesExceptionBlock, Data data)
+ {
+ return this.delegatee.Branch (pc, target, leavesExceptionBlock, data);
+ }
+
+ public Result BranchCond (APC pc, APC target, BranchOperator bop, int value1, int value2, Data data)
+ {
+ return this.delegatee.BranchCond (pc, target, bop, ConvertSource (pc, value1), ConvertSource (pc, value2), data);
+ }
+
+ public Result BranchTrue (APC pc, APC target, int cond, Data data)
+ {
+ return this.delegatee.BranchTrue (pc, target, ConvertSource (pc, cond), data);
+ }
+
+ public Result BranchFalse (APC pc, APC target, int cond, Data data)
+ {
+ return this.delegatee.BranchFalse (pc, target, ConvertSource (pc, cond), data);
+ }
+
+ public Result Break (APC pc, Data data)
+ {
+ return this.delegatee.Break (pc, data);
+ }
+
+ public Result Call<TypeList, ArgList> (APC pc, Method method, bool virt, TypeList extraVarargs, int dest, ArgList args, Data data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<int>
+ {
+ if (!this.parent.MetaDataProvider.IsVoidMethod (method) && InsideOld (pc))
+ return this.delegatee.LoadStack (pc, 0, ConvertDest (pc, dest), ConvertOldDest (pc, dest), true, data);
+
+ return DelegateCall (pc, method, virt, extraVarargs, dest, args, data);
+ }
+
+ public Result Calli<TypeList, ArgList> (APC pc, TypeNode returnType, TypeList argTypes, bool instance, int dest, int functionPointer, ArgList args, Data data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<int>
+ {
+ if (!this.parent.MetaDataProvider.IsVoid (returnType) && InsideOld (pc))
+ return this.delegatee.LoadStack (pc, 0, ConvertDest (pc, dest), ConvertOldDest (pc, dest), true, data);
+
+ return this.delegatee.Calli (pc, returnType, argTypes, instance,
+ ConvertDest (pc, dest), ConvertSource (pc, functionPointer),
+ ConvertSources (pc, args), data);
+ }
+
+ public Result CheckFinite (APC pc, int dest, int source, Data data)
+ {
+ return this.delegatee.CheckFinite (pc, ConvertDest (pc, dest), ConvertSource (pc, source), data);
+ }
+
+ public Result CopyBlock (APC pc, int destAddress, int srcAddress, int len, Data data)
+ {
+ return this.delegatee.CopyBlock (pc, ConvertSource (pc, destAddress), ConvertSource (pc, srcAddress), ConvertSource (pc, len), data);
+ }
+
+ public Result EndFilter (APC pc, int decision, Data data)
+ {
+ return this.delegatee.EndFilter (pc, ConvertSource (pc, decision), data);
+ }
+
+ public Result EndFinally (APC pc, Data data)
+ {
+ return this.delegatee.EndFinally (pc, data);
+ }
+
+ public Result Jmp (APC pc, Method method, Data data)
+ {
+ return this.delegatee.Jmp (pc, method, data);
+ }
+
+ public Result LoadArg (APC pc, Parameter argument, bool isOld, int dest, Data data)
+ {
+ return this.delegatee.LoadArg (pc, argument, isOld, ConvertDest (pc, dest), data);
+ }
+
+ public Result LoadArgAddress (APC pc, Parameter argument, bool isOld, int dest, Data data)
+ {
+ return this.delegatee.LoadArgAddress (pc, argument, isOld, ConvertDest (pc, dest), data);
+ }
+
+ public Result LoadLocal (APC pc, Local local, int dest, Data data)
+ {
+ return this.delegatee.LoadLocal (pc, local, ConvertDest (pc, dest), data);
+ }
+
+ public Result LoadLocalAddress (APC pc, Local local, int dest, Data data)
+ {
+ return this.delegatee.LoadLocalAddress (pc, local, ConvertDest (pc, dest), data);
+ }
+
+ public Result Nop (APC pc, Data data)
+ {
+ return this.delegatee.Nop (pc, data);
+ }
+
+ public Result Pop (APC pc, int source, Data data)
+ {
+ return this.delegatee.Pop (pc, ConvertSource (pc, source), data);
+ }
+
+ public Result Return (APC pc, int source, Data data)
+ {
+ return this.delegatee.Return (pc, ConvertSource (pc, source), data);
+ }
+
+ public Result StoreArg (APC pc, Parameter argument, int source, Data data)
+ {
+ return this.delegatee.StoreArg (pc, argument, ConvertSource (pc, source), data);
+ }
+
+ public Result StoreLocal (APC pc, Local local, int source, Data data)
+ {
+ return this.delegatee.StoreLocal (pc, local, ConvertSource (pc, source), data);
+ }
+
+ public Result Switch (APC pc, TypeNode type, IEnumerable<Pair<object, APC>> cases, int value, Data data)
+ {
+ return this.delegatee.Switch (pc, type, cases, ConvertSource (pc, value), data);
+ }
+
+ public Result Box (APC pc, TypeNode type, int dest, int source, Data data)
+ {
+ return this.delegatee.Box (pc, type, ConvertDest (pc, dest), ConvertSource (pc, source), data);
+ }
+
+ public Result ConstrainedCallvirt<TypeList, ArgList> (APC pc, Method method, TypeNode constraint,
+ TypeList extraVarargs, int dest, ArgList args, Data data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<int>
+ {
+ return this.delegatee.ConstrainedCallvirt (pc, method, constraint, extraVarargs,
+ ConvertDest (pc, dest), ConvertSources (pc, args), data);
+ }
+
+ public Result CastClass (APC pc, TypeNode type, int dest, int obj, Data data)
+ {
+ return this.delegatee.CastClass (pc, type, ConvertDest (pc, dest), ConvertSource (pc, obj), data);
+ }
+
+ public Result CopyObj (APC pc, TypeNode type, int destPtr, int sourcePtr, Data data)
+ {
+ return this.delegatee.CopyObj (pc, type, ConvertSource (pc, destPtr), ConvertSource (pc, sourcePtr), data);
+ }
+
+ public Result Initobj (APC pc, TypeNode type, int ptr, Data data)
+ {
+ return this.delegatee.Initobj (pc, type, ConvertSource (pc, ptr), data);
+ }
+
+ public Result LoadElement (APC pc, TypeNode type, int dest, int array, int index, Data data)
+ {
+ if (InsideOld (pc))
+ return this.delegatee.LoadStack (pc, 0, ConvertDest (pc, dest), ConvertOldDest (pc, dest), true, data);
+ return this.delegatee.LoadElement (pc, type, ConvertDest (pc, dest), ConvertSource (pc, array), ConvertSource (pc, index), data);
+ }
+
+ public Result LoadField (APC pc, Field field, int dest, int obj, Data data)
+ {
+ if (InsideOld (pc))
+ return this.delegatee.LoadStack (pc, 0, ConvertDest (pc, dest), ConvertOldDest (pc, dest), true, data);
+
+ return this.delegatee.LoadField (pc, field, ConvertDest (pc, dest), ConvertSource (pc, obj), data);
+ }
+
+ public Result LoadFieldAddress (APC pc, Field field, int dest, int obj, Data data)
+ {
+ return this.delegatee.LoadFieldAddress (pc, field, ConvertDest (pc, dest), ConvertSource (pc, obj), data);
+ }
+
+ public Result LoadLength (APC pc, int dest, int array, Data data)
+ {
+ return this.delegatee.LoadLength (pc, ConvertDest (pc, dest), ConvertSource (pc, array), data);
+ }
+
+ public Result LoadStaticField (APC pc, Field field, int dest, Data data)
+ {
+ if (InsideOld (pc))
+ return this.delegatee.LoadStack (pc, 0, ConvertDest (pc, dest), ConvertOldDest (pc, dest), true, data);
+
+ return this.delegatee.LoadStaticField (pc, field, ConvertDest (pc, dest), data);
+ }
+
+ public Result LoadStaticFieldAddress (APC pc, Field field, int dest, Data data)
+ {
+ return this.delegatee.LoadStaticFieldAddress (pc, field, ConvertDest (pc, dest), data);
+ }
+
+ public Result LoadTypeToken (APC pc, TypeNode type, int dest, Data data)
+ {
+ return this.delegatee.LoadTypeToken (pc, type, ConvertDest (pc, dest), data);
+ }
+
+ public Result LoadFieldToken (APC pc, Field type, int dest, Data data)
+ {
+ return this.delegatee.LoadFieldToken (pc, type, ConvertDest (pc, dest), data);
+ }
+
+ public Result LoadMethodToken (APC pc, Method type, int dest, Data data)
+ {
+ return this.delegatee.LoadMethodToken (pc, type, ConvertDest (pc, dest), data);
+ }
+
+ public Result NewArray<ArgList> (APC pc, TypeNode type, int dest, ArgList lengths, Data data) where ArgList : IIndexable<int>
+ {
+ return this.delegatee.NewArray (pc, type, ConvertDest (pc, dest), ConvertSources (pc, lengths), data);
+ }
+
+ public Result NewObj<ArgList> (APC pc, Method ctor, int dest, ArgList args, Data data) where ArgList : IIndexable<int>
+ {
+ return this.delegatee.NewObj (pc, ctor, ConvertDest (pc, dest), ConvertSources (pc, args), data);
+ }
+
+ public Result MkRefAny (APC pc, TypeNode type, int dest, int obj, Data data)
+ {
+ return this.delegatee.MkRefAny (pc, type, ConvertDest (pc, dest), ConvertSource (pc, obj), data);
+ }
+
+ public Result RefAnyType (APC pc, int dest, int source, Data data)
+ {
+ return this.delegatee.RefAnyType (pc, ConvertDest (pc, dest), ConvertSource (pc, source), data);
+ }
+
+ public Result RefAnyVal (APC pc, TypeNode type, int dest, int source, Data data)
+ {
+ return this.delegatee.RefAnyVal (pc, type, ConvertDest (pc, dest), ConvertSource (pc, source), data);
+ }
+
+ public Result Rethrow (APC pc, Data data)
+ {
+ return this.delegatee.Rethrow (pc, data);
+ }
+
+ public Result StoreElement (APC pc, TypeNode type, int array, int index, int value, Data data)
+ {
+ return this.delegatee.StoreElement (pc, type, ConvertSource (pc, array), ConvertSource (pc, index), ConvertSource (pc, value), data);
+ }
+
+ public Result StoreField (APC pc, Field field, int obj, int value, Data data)
+ {
+ return this.delegatee.StoreField (pc, field, ConvertSource (pc, obj), ConvertSource (pc, value), data);
+ }
+
+ public Result StoreStaticField (APC pc, Field field, int value, Data data)
+ {
+ return this.delegatee.StoreStaticField (pc, field, ConvertSource (pc, value), data);
+ }
+
+ public Result Throw (APC pc, int exception, Data data)
+ {
+ return this.delegatee.Throw (pc, ConvertSource (pc, exception), data);
+ }
+
+ public Result Unbox (APC pc, TypeNode type, int dest, int obj, Data data)
+ {
+ return this.delegatee.Unbox (pc, type, ConvertDest (pc, dest), ConvertSource (pc, obj), data);
+ }
+
+ public Result UnboxAny (APC pc, TypeNode type, int dest, int obj, Data data)
+ {
+ return this.delegatee.UnboxAny (pc, type, ConvertDest (pc, dest), ConvertSource (pc, obj), data);
+ }
+
+ private Result DelegateCall<TypeList, ArgList> (APC pc, Method method, bool virt, TypeList extraVarargs, int dest, ArgList args, Data data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<int>
+ {
+ TypeNode declaringType = this.parent.MetaDataProvider.DeclaringType (method);
+ if (args.Count == 2) {
+ string name = this.parent.MetaDataProvider.Name (method);
+ if (name == "Equals") {
+ return this.delegatee.Binary (pc, BinaryOperator.Cobjeq,
+ ConvertDest (pc, dest),
+ TryConvertUnbox (pc, args [0]), TryConvertUnbox (pc, args [1]), data);
+ }
+
+ if (this.parent.MetaDataProvider.IsReferenceType (declaringType)) {
+ if (name == "op_Inequality") {
+ return this.delegatee.Binary (pc, BinaryOperator.Cne_Un,
+ ConvertDest (pc, dest),
+ ConvertSource (pc, args [0]), ConvertSource (pc, args [1]), data);
+ }
+ if (name == "op_Equality") {
+ return this.delegatee.Binary (pc, BinaryOperator.Cobjeq,
+ ConvertDest (pc, dest),
+ ConvertSource (pc, args [0]), ConvertSource (pc, args [1]), data);
+ }
+ }
+ }
+
+ return this.delegatee.Call (pc, method, virt, extraVarargs, ConvertDest (pc, dest), ConvertSources (pc, args), data);
+ }
+ #endregion
+
+ #region Nested type: ArgumentSourceWrapper
+ private struct ArgumentSourceWrapper<ArgList> : IIndexable<SymbolicValue>
+ where ArgList : IIndexable<int> {
+ private readonly Domain state;
+ private readonly ArgList underlying;
+
+ public ArgumentSourceWrapper (ArgList underlying, Domain state)
+ {
+ this.underlying = underlying;
+ this.state = state;
+ }
+
+ #region Implementation of IIndexable<SymbolicValue>
+ public int Count
+ {
+ get { return this.underlying.Count; }
+ }
+
+ public SymbolicValue this [int index]
+ {
+ get { return Map (this.underlying [index]); }
+ }
+
+ private SymbolicValue Map (int i)
+ {
+ SymbolicValue sv = default(SymbolicValue);
+ if (this.state == null)
+ return sv;
+
+ this.state.TryGetCorrespondingValueAbstraction (i, out sv);
+ return sv;
+ }
+ #endregion
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// SymFunction.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis {
+ abstract class SymFunction : IConstantInfo, IEquatable<SymFunction>, IVisibilityCheck<Method> {
+ protected readonly IMetaDataProvider MetaDataProvider;
+
+ protected SymFunction (ref int idGen, IMetaDataProvider metaDataProvider)
+ {
+ this.MetaDataProvider = metaDataProvider;
+ idGen++;
+ }
+
+ public abstract bool ActsAsField { get; }
+ public abstract bool IsVirtualMethod { get; }
+ public abstract bool IsStatic { get; }
+
+ #region IConstantInfo Members
+ public abstract bool KeepAsBottomField { get; }
+ public abstract bool ManifestField { get; }
+ #endregion
+
+ #region IVisibilityCheck<Method> Members
+ public abstract bool IfRootIsParameter { get; }
+ public abstract bool IsAsVisibleAs (Method member);
+ public abstract bool IsVisibleFrom (Method member);
+ #endregion
+
+ public abstract TypeNode FieldAddressType ();
+ public abstract PathElementBase ToPathElement (bool tryCompact);
+
+ public static Wrapper<T> For<T> (T value, ref int idGen, IMetaDataProvider metadataDecoder)
+ {
+ if (value is Parameter)
+ return (Wrapper<T>) (object) new ParameterWrapper ((Parameter) (object) value, ref idGen, metadataDecoder);
+ if (value is Method)
+ return (Wrapper<T>) (object) new MethodWrapper ((Method) (object) value, ref idGen, metadataDecoder);
+
+ return new Wrapper<T> (value, ref idGen, metadataDecoder);
+ }
+
+ #region Implementation of IEquatable<HeapAnalysis<Local,Parameter,Method,Field,Property,Event,Type,Attribute,Assembly>.Domain.SymFunction>
+ public bool Equals (SymFunction other)
+ {
+ return ReferenceEquals (this, other);
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// SymValue.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis {
+ sealed class SymValue : IEquatable<SymValue>, IComparable<SymValue>, IComparable {
+ private static int _globalIdGenerator;
+
+ public readonly int UniqueId;
+ public readonly int GlobalId;
+
+ public SymValue (int uniqueId)
+ {
+ this.UniqueId = uniqueId;
+ this.GlobalId = ++_globalIdGenerator;
+ }
+
+ #region IComparable Members
+ public int CompareTo (object obj)
+ {
+ var that = obj as SymValue;
+ if (that == null)
+ return 1;
+
+ return CompareTo (that);
+ }
+ #endregion
+
+ #region Implementation of IEquatable<SymValue>
+ public bool Equals (SymValue other)
+ {
+ return this == other;
+ }
+ #endregion
+
+ #region IComparable<SymValue> Members
+ public int CompareTo (SymValue other)
+ {
+ return this.UniqueId - other.UniqueId;
+ }
+ #endregion
+
+ public static int GetUniqueKey (SymValue sv)
+ {
+ return sv == null ? 0 : sv.GlobalId;
+ }
+
+ public override string ToString ()
+ {
+ return string.Format ("sv{0} ({1})", this.UniqueId, this.GlobalId);
+ }
+ }
+}
--- /dev/null
+//
+// SymbolicValue.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis {
+ struct SymbolicValue : IEquatable<SymbolicValue>, IComparable<SymbolicValue>, IComparable {
+ public readonly SymValue Symbol;
+
+ public SymbolicValue (SymValue symbol)
+ {
+ this.Symbol = symbol;
+ }
+
+ public bool IsNull
+ {
+ get { return this.Symbol == null; }
+ }
+
+ public int MethodLocalId
+ {
+ get { return this.Symbol.UniqueId; }
+ }
+
+ #region Implementation of IEquatable<SymbolicValue>
+ public bool Equals (SymbolicValue other)
+ {
+ return this.Symbol == other.Symbol;
+ }
+ #endregion
+
+ #region Implementation of IComparable<in SymbolicValue>
+ public int CompareTo (SymbolicValue other)
+ {
+ return this.Symbol.CompareTo (other.Symbol);
+ }
+ #endregion
+
+ #region Implementation of IComparable
+ public int CompareTo (object obj)
+ {
+ if (!(obj is SymbolicValue))
+ return 1;
+
+ return CompareTo ((SymbolicValue) obj);
+ }
+ #endregion
+
+ public override bool Equals (object obj)
+ {
+ if (obj is SymbolicValue)
+ return Equals ((SymbolicValue) obj);
+
+ return false;
+ }
+
+ public override int GetHashCode ()
+ {
+ return this.Symbol == null ? 0 : this.Symbol.GetHashCode ();
+ }
+
+ public override string ToString ()
+ {
+ if (this.Symbol == null)
+ return "<!null!>";
+ return this.Symbol.ToString ();
+ }
+
+ public static int GetUniqueKey (SymbolicValue arg)
+ {
+ return SymValue.GetUniqueKey (arg.Symbol);
+ }
+ }
+}
--- /dev/null
+//
+// TypeCache.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis {
+ struct TypeCache {
+ private readonly string full_name;
+ private TypeNode cache;
+ private bool cache_is_valid;
+ private bool have_type;
+
+ public TypeCache (string fullName)
+ {
+ this.cache_is_valid = false;
+ this.have_type = false;
+ this.cache = default(TypeNode);
+ this.full_name = fullName;
+ }
+
+ public bool TryGet (IMetaDataProvider mdProvider, out TypeNode type)
+ {
+ if (!this.cache_is_valid) {
+ this.cache_is_valid = true;
+ this.have_type = mdProvider.TryGetSystemType (this.full_name, out this.cache);
+ }
+
+ type = this.cache;
+ return this.have_type;
+ }
+ }
+}
--- /dev/null
+//
+// ValueContextProvider.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Lattices;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis {
+ class ValueContextProvider<TContext> : IValueContextProvider<SymbolicValue>, IValueContext<SymbolicValue>
+ where TContext : IStackContextProvider {
+ private readonly HeapAnalysis parent;
+ private readonly TContext underlying;
+
+ public ValueContextProvider (HeapAnalysis parent, TContext underlying)
+ {
+ this.parent = parent;
+ this.underlying = underlying;
+ }
+
+ #region Implementation of IMethodContextProvider
+ public IMethodContext MethodContext
+ {
+ get { return this.underlying.MethodContext; }
+ }
+ #endregion
+
+ #region Implementation of IStackContextProvider
+ public IStackContext StackContext
+ {
+ get { return this.underlying.StackContext; }
+ }
+ #endregion
+
+ #region Implementation of IValueContextProvider<SymbolicValue>
+ IValueContext<SymbolicValue> IValueContextProvider<SymbolicValue>.ValueContext
+ {
+ get { return this; }
+ }
+ #endregion
+
+ #region Implementation of IValueContext<SymbolicValue>
+ public FlatDomain<TypeNode> GetType (APC pc, SymbolicValue value)
+ {
+ Domain domain;
+ if (!this.parent.PreStateLookup (pc, out domain) || domain.IsBottom)
+ return FlatDomain<TypeNode>.TopValue;
+
+ return domain.GetType (value.Symbol).Type;
+ }
+
+ public bool IsZero (APC at, SymbolicValue value)
+ {
+ Domain domain;
+ if (!this.parent.PreStateLookup (at, out domain))
+ return true;
+
+ return domain.IsZero (value.Symbol);
+ }
+
+ public bool TryLocalValue (APC at, Local local, out SymbolicValue sv)
+ {
+ Domain domain;
+ if (this.parent.PreStateLookup (at, out domain))
+ return domain.TryGetCorrespondingValueAbstraction (local, out sv);
+
+ sv = new SymbolicValue ();
+ return false;
+ }
+
+ public bool TryParameterValue (APC at, Parameter p, out SymbolicValue sv)
+ {
+ Domain domain;
+ if (this.parent.PreStateLookup (at, out domain))
+ return domain.TryGetCorrespondingValueAbstraction (p, out sv);
+
+ sv = new SymbolicValue ();
+ return false;
+ }
+
+ public bool TryGetArrayLength (APC at, SymbolicValue array, out SymbolicValue length)
+ {
+ Domain domain;
+ if (!this.parent.PreStateLookup (at, out domain))
+ throw new ArgumentException ("pc wasn't visited");
+ SymValue lengthValue;
+ bool arrayLength = domain.TryGetArrayLength (array.Symbol, out lengthValue);
+
+ length = new SymbolicValue (lengthValue);
+ return arrayLength;
+ }
+
+ public LispList<PathElement> AccessPathList (APC at, SymbolicValue sv, bool allowLocal, bool preferLocal)
+ {
+ Domain domain;
+ if (!this.parent.PreStateLookup (at, out domain))
+ throw new ArgumentException ("pc wasn't visited");
+
+ AccessPathFilter<Method> filter = AccessPathFilter<Method>.IsVisibleFrom (MethodContext.CurrentMethod);
+ return domain.GetAccessPathList (sv.Symbol, filter, allowLocal, preferLocal);
+ }
+
+ public bool IsConstant (APC at, SymbolicValue symbol, out TypeNode type, out object constant)
+ {
+ Domain domain;
+ if (!this.parent.PreStateLookup (at, out domain))
+ throw new ArgumentException ("pc wasn't visited");
+
+ return domain.IsConstant (symbol.Symbol, out type, out constant);
+ }
+
+ public bool TryStackValue (APC at, int stackIndex, out SymbolicValue sv)
+ {
+ Domain domain;
+ if (this.parent.PreStateLookup (at, out domain))
+ return domain.TryGetCorrespondingValueAbstraction (stackIndex, out sv);
+
+ sv = new SymbolicValue ();
+ return false;
+ }
+
+ public bool IsValid (SymbolicValue sv)
+ {
+ return sv.Symbol != null;
+ }
+
+ public string AccessPath (APC at, SymbolicValue sv)
+ {
+ Domain domain;
+ if (!this.parent.PreStateLookup (at, out domain))
+ throw new ArgumentException ("pc wasn't visited");
+
+ return domain.GetAccessPath (sv.Symbol);
+ }
+
+ public IEnumerable<LispList<PathElement>> AccessPaths (APC at, SymValue value, AccessPathFilter<Method> filter)
+ {
+ Domain domain;
+ if (!this.parent.PreStateLookup (at, out domain))
+ throw new ArgumentException ("pc wasn't visited");
+
+ return domain.GetAccessPathsFiltered (value, filter, true).Select (path => path.Coerce<PathElementBase, PathElement> ());
+ }
+
+ public LispList<PathElement> VisibleAccessPathList (APC at, SymbolicValue value)
+ {
+ Domain domain;
+ if (!this.parent.PreStateLookup (at, out domain))
+ throw new ArgumentException ("pc wasn't visited");
+
+ AccessPathFilter<Method> filter = AccessPathFilter<Method>.FromPrecondition (MethodContext.CurrentMethod);
+ return domain.GetAccessPathList (value.Symbol, filter, false, false);
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// ValueDecoder.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis {
+ class ValueDecoder<TContext> :
+ IILDecoder<APC, SymbolicValue, SymbolicValue, IValueContextProvider<SymbolicValue>, IImmutableMap<SymbolicValue, LispList<SymbolicValue>>>
+ where TContext : IStackContextProvider
+ {
+ private readonly HeapAnalysis parent;
+ private readonly IILDecoder<APC, int, int, TContext, Dummy> stack_decoder;
+ private readonly Lazy<IValueContextProvider<SymbolicValue>> context;
+
+ public ValueDecoder(HeapAnalysis parent, IILDecoder<APC, int, int, TContext, Dummy> stackDecoder)
+ {
+ this.context = new Lazy<IValueContextProvider<SymbolicValue>> (()=> new ValueContextProvider<TContext>(this.parent, this.stack_decoder.ContextProvider));
+ this.parent = parent;
+ this.stack_decoder = stackDecoder;
+ }
+
+ #region Implementation of IILDecoder<APC,SymbolicValue,SymbolicValue,IValueContext<SymbolicValue>,IImmutableMap<SymbolicValue,LispList<SymbolicValue>>>
+ public IValueContextProvider<SymbolicValue> ContextProvider { get { return context.Value; } }
+
+ public Result ForwardDecode<Data, Result, Visitor>(APC pc, Visitor visitor, Data state)
+ where Visitor : IILVisitor<APC, SymbolicValue, SymbolicValue, Data, Result>
+ {
+ return this.stack_decoder.ForwardDecode<Data, Result, StackToSymbolicAdapter<Data, Result, Visitor>>
+ (pc, new StackToSymbolicAdapter<Data, Result, Visitor> (this.parent, visitor), state);
+ }
+
+ public bool IsUnreachable(APC pc)
+ {
+ return this.parent.IsUnreachable (pc);
+ }
+
+ public IImmutableMap<SymbolicValue, LispList<SymbolicValue>> EdgeData(APC from, APC to)
+ {
+ if (!this.parent.RenamePoints.ContainsKey(from, to))
+ return null;
+ if (this.parent.MergeInfoCache.ContainsKey(to) && this.parent.MergeInfoCache[to] == null)
+ return null;
+
+ return this.parent.EdgeRenaming (new Pair<APC, APC> (from, to), this.ContextProvider.MethodContext.CFG.IsJoinPoint (to));
+ }
+
+ public void Dump(TextWriter tw, string prefix, IImmutableMap<SymValue, LispList<SymValue>> edgeData )
+ {
+ if (edgeData == null)
+ return;
+ edgeData.Visit ((key, targets) => {
+ tw.Write (" {0} -> ", key);
+ foreach (var target in targets.AsEnumerable ())
+ tw.Write ("{0} ", target);
+ tw.WriteLine ();
+ return VisitStatus.ContinueVisit;
+ });
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// Wrapper.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis {
+ class Wrapper<T> : SymFunction {
+ public readonly T Item;
+ protected PathElementBase PathElement = null;
+
+ public Wrapper (T item, ref int idGen, IMetaDataProvider metaDataProvider)
+ : base (ref idGen, metaDataProvider)
+ {
+ this.Item = item;
+ }
+
+ #region Overrides of SymFunction
+ public override bool ActsAsField
+ {
+ get { return this.Item is Field; }
+ }
+
+ public override bool IsVirtualMethod
+ {
+ get { return this.Item is Method && this.MetaDataProvider.IsVirtual ((Method) (object) this.Item); }
+ }
+
+ public override bool KeepAsBottomField
+ {
+ get
+ {
+ var str = this.Item as string;
+ if (str == null)
+ return true;
+
+ return str != "$UnaryNot" && str != "$NeZero";
+ }
+ }
+
+ public override bool ManifestField
+ {
+ get
+ {
+ var str = this.Item as string;
+ if (str != null)
+ return str == "$Value" || str == "$Length";
+
+ return (this.Item is Field || this.Item is Method);
+ }
+ }
+
+ public override bool IsStatic
+ {
+ get
+ {
+ if (this.Item is Field)
+ return this.MetaDataProvider.IsStatic ((Field) (object) this.Item);
+ if (this.Item is Method)
+ return this.MetaDataProvider.IsStatic ((Method) (object) this.Item);
+
+ return false;
+ }
+ }
+
+ public override bool IfRootIsParameter
+ {
+ get
+ {
+ if (this.Item is Field)
+ return !this.MetaDataProvider.IsStatic ((Field) (object) this.Item);
+ if (this.Item is Method)
+ return !this.MetaDataProvider.IsStatic ((Method) (object) this.Item);
+ if (this.Item is Parameter)
+ return true;
+ if (this.Item is Local)
+ return false;
+
+ return true;
+ }
+ }
+
+ public override bool IsAsVisibleAs (Method method)
+ {
+ if (this.Item is Field)
+ return this.MetaDataProvider.IsAsVisibleAs ((Field) (object) this.Item, method);
+ if (this.Item is Method)
+ return this.MetaDataProvider.IsAsVisibleAs ((Method) (object) this.Item, method);
+ if (this.MetaDataProvider.IsConstructor (method) && this.Item is Parameter
+ && this.MetaDataProvider.Name ((Parameter) (object) this.Item) == "this")
+ return false;
+
+ return true;
+ }
+
+ public override bool IsVisibleFrom (Method method)
+ {
+ TypeNode declaringType = this.MetaDataProvider.DeclaringType (method);
+ if (this.Item is Field) {
+ var f = ((Field) (object) this.Item);
+ return this.MetaDataProvider.IsVisibleFrom (f, declaringType);
+ }
+
+ if (this.Item is Method)
+ this.MetaDataProvider.IsVisibleFrom ((Method) (object) this.Item, declaringType);
+ if (this.Item is Parameter)
+ this.MetaDataProvider.Equal (this.MetaDataProvider.DeclaringMethod ((Parameter) (object) this.Item), method);
+ if (this.Item is Local) {
+ var local = (Local) (object) this.Item;
+ IIndexable<Local> locals = this.MetaDataProvider.Locals (method);
+ for (int i = 0; i < locals.Count; i++) {
+ if (locals [i].Equals (local))
+ return true;
+ }
+ return false;
+ }
+ return true;
+ }
+
+ public override TypeNode FieldAddressType ()
+ {
+ if (this.Item is Field)
+ return this.MetaDataProvider.ManagedPointer (this.MetaDataProvider.FieldType ((Field) (object) this.Item));
+
+ throw new InvalidOperationException ();
+ }
+
+ public override PathElementBase ToPathElement (bool tryCompact)
+ {
+ throw new NotImplementedException ();
+ }
+ #endregion
+
+ public TypeNode Type { get; set; }
+
+ public override string ToString ()
+ {
+ if (typeof (T).Equals (typeof (int)))
+ return String.Format ("s{0}", this.Item);
+ if (this.Item is Field) {
+ var field = (Field) (object) this.Item;
+ if (this.MetaDataProvider.IsStatic (field)) {
+ return String.Format ("{0}.{1}",
+ this.MetaDataProvider.FullName (this.MetaDataProvider.DeclaringType (field)),
+ this.MetaDataProvider.Name (field));
+ }
+
+ return this.MetaDataProvider.Name (field);
+ }
+ if (this.Item is Method) {
+ var method = (Method) (object) this.Item;
+ if (this.MetaDataProvider.IsStatic (method)) {
+ return String.Format ("{0}.{1}",
+ this.MetaDataProvider.FullName (this.MetaDataProvider.DeclaringType (method)),
+ this.MetaDataProvider.Name (method));
+ }
+
+ return this.MetaDataProvider.Name (method);
+ }
+
+ return this.Item.ToString ();
+ }
+ }
+}
--- /dev/null
+//
+// Analysis.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.Analysis.Drivers;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataFlowAnalysis;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Lattices;
+using Mono.CodeContracts.Static.Providers;
+using Mono.CodeContracts.Static.Proving;
+
+namespace Mono.CodeContracts.Static.Analysis.NonNull {
+ class Analysis<E, V> :
+ ILVisitorBase<APC, V, V, Domain<E, V>, Domain<E, V>>,
+ IAnalysis<APC, Domain<E, V>, IILVisitor<APC, V, V, Domain<E, V>, Domain<E, V>>, IImmutableMap<V, LispList<V>>>,
+ IMethodResult<V>, IFactBase<V> where E : IEquatable<E> where V : IEquatable<V> {
+ private readonly Dictionary<APC, Domain<E, V>> callSiteCache = new Dictionary<APC, Domain<E, V>> ();
+ private readonly IMethodDriver<E, V> method_driver;
+ private IFixPointInfo<APC, Domain<E, V>> fix_point_info;
+
+ public Analysis (IMethodDriver<E, V> mdriver)
+ {
+ this.method_driver = mdriver;
+ }
+
+ protected internal IExpressionContextProvider<E, V> ContextProvider
+ {
+ get { return this.method_driver.ContextProvider; }
+ }
+
+ protected IMetaDataProvider MetaDataProvider
+ {
+ get { return this.method_driver.MetaDataProvider; }
+ }
+
+ #region IAnalysis<APC,Domain<E,V>,IILVisitor<APC,V,V,Domain<E,V>,Domain<E,V>>,IImmutableMap<V,LispList<V>>> Members
+ public IILVisitor<APC, V, V, Domain<E, V>, Domain<E, V>> GetVisitor ()
+ {
+ return this;
+ }
+
+ public Domain<E, V> Join (Pair<APC, APC> edge, Domain<E, V> newstate, Domain<E, V> prevstate, out bool weaker, bool widen)
+ {
+ bool nonNullWeaker;
+ SetDomain<V> nonNulls = prevstate.NonNulls.Join (newstate.NonNulls, widen, out nonNullWeaker);
+ bool nullWeaker;
+ SetDomain<V> nulls = prevstate.Nulls.Join (newstate.Nulls, widen, out nullWeaker);
+
+ weaker = nonNullWeaker || nullWeaker;
+ return new Domain<E, V> (nonNulls, nulls);
+ }
+
+ public Domain<E, V> ImmutableVersion (Domain<E, V> state)
+ {
+ return state;
+ }
+
+ public Domain<E, V> MutableVersion (Domain<E, V> state)
+ {
+ return state;
+ }
+
+ public Domain<E, V> EdgeConversion (APC from, APC to, bool isJoinPoint, IImmutableMap<V, LispList<V>> data, Domain<E, V> state)
+ {
+ if (data == null)
+ return state;
+ SetDomain<V> oldNonNulls = state.NonNulls;
+ SetDomain<V> nonNulls = SetDomain<V>.TopValue;
+
+ SetDomain<V> oldNulls = state.Nulls;
+ SetDomain<V> nulls = SetDomain<V>.TopValue;
+ foreach (V variable in data.Keys) {
+ bool nonNullContains = oldNonNulls.Contains (variable);
+ bool nullContains = oldNulls.Contains (variable);
+
+ if (nonNullContains || nullContains) {
+ foreach (V anotherVariable in data [variable].AsEnumerable ()) {
+ if (nonNullContains)
+ nonNulls = nonNulls.Add (anotherVariable);
+ if (nullContains)
+ nulls = nulls.Add (anotherVariable);
+ }
+ }
+ }
+
+ return new Domain<E, V> (nonNulls, nulls);
+ }
+
+ public bool IsBottom (APC pc, Domain<E, V> state)
+ {
+ return state.NonNulls.IsBottom;
+ }
+
+ public Predicate<APC> SaveFixPointInfo (IFixPointInfo<APC, Domain<E, V>> fixPointInfo)
+ {
+ this.fix_point_info = fixPointInfo;
+
+ //todo: implement this
+ return pc => true;
+ }
+
+ public void Dump (Pair<Domain<E, V>, TextWriter> pair)
+ {
+ TextWriter tw = pair.Value;
+ tw.Write ("NonNulls: ");
+ pair.Key.NonNulls.Dump (tw);
+ tw.Write ("Nulls: ");
+ pair.Key.Nulls.Dump (tw);
+ }
+ #endregion
+
+ #region IFactBase<V> Members
+ public ProofOutcome IsNull (APC pc, V variable)
+ {
+ if (ContextProvider.ValueContext.IsZero (pc, variable))
+ return ProofOutcome.True;
+
+ Domain<E, V> domain;
+ if (!PreStateLookup (pc, out domain) || domain.NonNulls.IsBottom)
+ return ProofOutcome.Bottom;
+ if (domain.IsNonNull (variable))
+ return ProofOutcome.False;
+ if (domain.IsNull (variable))
+ return ProofOutcome.True;
+
+ return ProofOutcome.Top;
+ }
+
+ public ProofOutcome IsNonNull (APC pc, V variable)
+ {
+ Domain<E, V> domain;
+ if (!PreStateLookup (pc, out domain) || domain.NonNulls.IsBottom)
+ return ProofOutcome.Bottom;
+ if (domain.IsNonNull (variable))
+ return ProofOutcome.True;
+ if (ContextProvider.ValueContext.IsZero (pc, variable) || domain.IsNull (variable))
+ return ProofOutcome.False;
+
+ FlatDomain<TypeNode> aType = ContextProvider.ValueContext.GetType (pc, variable);
+ if (aType.IsNormal && MetaDataProvider.IsManagedPointer (aType.Concrete))
+ return ProofOutcome.True;
+
+ return ProofOutcome.Top;
+ }
+
+ public bool IsUnreachable (APC pc)
+ {
+ Domain<E, V> domain;
+ if (!PreStateLookup (pc, out domain) || domain.NonNulls.IsBottom)
+ return true;
+
+ return false;
+ }
+ #endregion
+
+ public override Domain<E, V> DefaultVisit (APC pc, Domain<E, V> data)
+ {
+ return data;
+ }
+
+ public static Domain<E, V> AssumeNonNull (V dest, Domain<E, V> before)
+ {
+ if (!before.NonNulls.Contains (dest))
+ return new Domain<E, V> (before.NonNulls.Add (dest), before.Nulls);
+ return before;
+ }
+
+ public static Domain<E, V> AssumeNull (V dest, Domain<E, V> before)
+ {
+ if (!before.Nulls.Contains (dest))
+ return new Domain<E, V> (before.NonNulls, before.Nulls.Add (dest));
+ return before;
+ }
+
+ public override Domain<E, V> Assert (APC pc, EdgeTag tag, V condition, Domain<E, V> data)
+ {
+ return ContextProvider.ExpressionContext.
+ Decode<Pair<bool, Domain<E, V>>, Domain<E, V>, ExpressionAssumeDecoder<E, V>>
+ (
+ ContextProvider.ExpressionContext.Refine (pc, condition),
+ new ExpressionAssumeDecoder<E, V> (ContextProvider),
+ new Pair<bool, Domain<E, V>> (true, data));
+ }
+
+ public override Domain<E, V> Assume (APC pc, EdgeTag tag, V condition, Domain<E, V> data)
+ {
+ IExpressionContext<E, V> exprCtx = ContextProvider.ExpressionContext;
+ E expr = exprCtx.Refine (pc, condition);
+
+ return exprCtx.Decode<Pair<bool, Domain<E, V>>, Domain<E, V>, ExpressionAssumeDecoder<E, V>>
+ (expr, new ExpressionAssumeDecoder<E, V> (ContextProvider),
+ new Pair<bool, Domain<E, V>> (tag != EdgeTag.False, data));
+ }
+
+ public override Domain<E, V> Unary (APC pc, UnaryOperator op, bool unsigned, V dest, V source, Domain<E, V> data)
+ {
+ switch (op) {
+ case UnaryOperator.Conv_i:
+ case UnaryOperator.Conv_u:
+ if (data.IsNonNull (source))
+ return AssumeNonNull (dest, data);
+ break;
+ }
+ return data;
+ }
+
+ public override Domain<E, V> Call<TypeList, ArgList> (APC pc, Method method, bool virt, TypeList extraVarargs, V dest, ArgList args, Domain<E, V> data)
+ {
+ this.callSiteCache [pc] = data;
+ if (!MetaDataProvider.IsStatic (method))
+ return AssumeNonNull (args [0], data);
+
+ return data;
+ }
+
+ public override Domain<E, V> CastClass (APC pc, TypeNode type, V dest, V obj, Domain<E, V> data)
+ {
+ if (data.NonNulls.Contains (obj))
+ return AssumeNonNull (dest, data);
+
+ return data;
+ }
+
+ public override Domain<E, V> Entry (APC pc, Method method, Domain<E, V> data)
+ {
+ APC at = ContextProvider.MethodContext.CFG.Next (pc);
+ Domain<E, V> domain = data;
+ IIndexable<Parameter> parameters = MetaDataProvider.Parameters (method);
+ TypeNode eventArgsType;
+ bool systemType = MetaDataProvider.TryGetSystemType ("System.EventArgs", out eventArgsType);
+ for (int i = 0; i < parameters.Count; i++) {
+ Parameter p = parameters [i];
+ TypeNode pType = MetaDataProvider.ParameterType (p);
+ if (MetaDataProvider.IsManagedPointer (pType)) {
+ V sv;
+ if (ContextProvider.ValueContext.TryParameterValue (at, p, out sv))
+ domain = AssumeNonNull (sv, domain);
+ } else {
+ V sv;
+ if (i == 0 && parameters.Count == 1 && MetaDataProvider.IsArray (pType)
+ && MetaDataProvider.Name (method) == "Main" && MetaDataProvider.IsStatic (method) &&
+ ContextProvider.ValueContext.TryParameterValue (pc, p, out sv))
+ domain = AssumeNonNull (sv, domain);
+ }
+ }
+ V sv1;
+ if (systemType && parameters.Count == 2 && MetaDataProvider.Equal (MetaDataProvider.System_Object, MetaDataProvider.ParameterType (parameters [0])) &&
+ MetaDataProvider.DerivesFrom (MetaDataProvider.ParameterType (parameters [1]), eventArgsType)
+ && ContextProvider.ValueContext.TryParameterValue (pc, parameters [1], out sv1))
+ domain = AssumeNonNull (sv1, domain);
+ if (!MetaDataProvider.IsStatic (method) && ContextProvider.ValueContext.TryParameterValue (pc, MetaDataProvider.This (method), out sv1))
+ domain = AssumeNonNull (sv1, domain);
+
+ return domain;
+ }
+
+ public override Domain<E, V> LoadStack (APC pc, int offset, V dest, V source, bool isOld, Domain<E, V> data)
+ {
+ Domain<E, V> old;
+ if (isOld && TryFindOldState (pc, out old)) {
+ if (old.IsNonNull (source))
+ return AssumeNonNull (dest, data);
+ if (old.IsNull (source))
+ return AssumeNull (dest, data);
+ }
+
+ return data;
+ }
+
+ public override Domain<E, V> Isinst (APC pc, TypeNode type, V dest, V obj, Domain<E, V> data)
+ {
+ if (data.IsNonNull (obj)) {
+ FlatDomain<TypeNode> aType = ContextProvider.ValueContext.GetType (pc, obj);
+ if (aType.IsNormal && MetaDataProvider.DerivesFrom (aType.Concrete, type))
+ return AssumeNonNull (dest, data);
+ }
+ return data;
+ }
+
+ public override Domain<E, V> LoadArgAddress (APC pc, Parameter argument, bool isOld, V dest, Domain<E, V> data)
+ {
+ return AssumeNonNull (dest, data);
+ }
+
+ public override Domain<E, V> LoadConst (APC pc, TypeNode type, object constant, V dest, Domain<E, V> data)
+ {
+ if (constant is string)
+ return AssumeNonNull (dest, data);
+
+ return data;
+ }
+
+ public override Domain<E, V> LoadElement (APC pc, TypeNode type, V dest, V array, V index, Domain<E, V> data)
+ {
+ return AssumeNonNull (array, data);
+ }
+
+ public override Domain<E, V> LoadField (APC pc, Field field, V dest, V obj, Domain<E, V> data)
+ {
+ Domain<E, V> domain = AssumeNonNull (obj, data);
+ FlatDomain<TypeNode> aType = ContextProvider.ValueContext.GetType (ContextProvider.MethodContext.CFG.Next (pc), dest);
+ if (aType.IsNormal && MetaDataProvider.IsManagedPointer (aType.Concrete))
+ domain = AssumeNonNull (dest, domain);
+
+ return domain;
+ }
+
+ public override Domain<E, V> LoadFieldAddress (APC pc, Field field, V dest, V obj, Domain<E, V> data)
+ {
+ Domain<E, V> domain = AssumeNonNull (obj, data);
+ return AssumeNonNull (dest, domain);
+ }
+
+ public override Domain<E, V> LoadStaticFieldAddress (APC pc, Field field, V dest, Domain<E, V> data)
+ {
+ return AssumeNonNull (dest, data);
+ }
+
+ public override Domain<E, V> LoadLength (APC pc, V dest, V array, Domain<E, V> data)
+ {
+ return AssumeNonNull (array, data);
+ }
+
+ public override Domain<E, V> NewArray<ArgList> (APC pc, TypeNode type, V dest, ArgList lengths, Domain<E, V> data)
+ {
+ return AssumeNonNull (dest, data);
+ }
+
+ public override Domain<E, V> NewObj<ArgList> (APC pc, Method ctor, V dest, ArgList args, Domain<E, V> data)
+ {
+ return AssumeNonNull (dest, data);
+ }
+
+ public override Domain<E, V> StoreElement (APC pc, TypeNode type, V array, V index, V value, Domain<E, V> data)
+ {
+ return AssumeNonNull (array, data);
+ }
+
+ public override Domain<E, V> StoreField (APC pc, Field field, V obj, V value, Domain<E, V> data)
+ {
+ return AssumeNonNull (obj, data);
+ }
+
+ private bool TryFindOldState (APC pc, out Domain<E, V> old)
+ {
+ for (LispList<Edge<CFGBlock, EdgeTag>> flist = pc.SubroutineContext; flist != null; flist = flist.Tail) {
+ Edge<CFGBlock, EdgeTag> head = flist.Head;
+ if (head.Tag.Is (EdgeTag.AfterMask))
+ return this.callSiteCache.TryGetValue (pc, out old);
+ }
+ old = new Domain<E, V> ();
+ return false;
+ }
+
+ public Domain<E, V> InitialValue (Func<V, int> keyConverter)
+ {
+ return new Domain<E, V> (new SetDomain<V> (keyConverter), new SetDomain<V> (keyConverter));
+ }
+
+ #region Implementation of IMethodResult<Variable>
+ public IMethodAnalysis MethodAnalysis { get; set; }
+
+ public void ValidateImplicitAssertions (IFactQuery<BoxedExpression, V> facts, List<string> proofResults)
+ {
+ }
+
+ public IFactQuery<BoxedExpression, V> FactQuery
+ {
+ get { return new SimpleLogicInference<E, V> (ContextProvider, this, this.method_driver.BasicFacts.IsUnreachable); }
+ }
+
+ public ProofOutcome ValidateExplicitAssertion (APC pc, V value)
+ {
+ Domain<E, V> domain;
+ if (PreStateLookup (pc, out domain) && !domain.NonNulls.IsBottom) {
+ IExpressionContext<E, V> exprCtx = ContextProvider.ExpressionContext;
+ return exprCtx.Decode<bool, ProofOutcome, ExpressionAssertDischarger<E, V>> (exprCtx.Refine (pc, value), new ExpressionAssertDischarger<E, V> (this, pc), true);
+ }
+ return ProofOutcome.Bottom;
+ }
+
+ private bool PreStateLookup (APC pc, out Domain<E, V> domain)
+ {
+ return this.fix_point_info.PreStateLookup (pc, out domain);
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// Domain.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.Lattices;
+
+namespace Mono.CodeContracts.Static.Analysis.NonNull {
+ struct Domain<E, V>
+ where E : IEquatable<E>
+ where V : IEquatable<V> {
+ public static readonly Domain<E, V> BottomValue
+ = new Domain<E, V> (SetDomain<V>.BottomValue, SetDomain<V>.BottomValue);
+
+ public SetDomain<V> NonNulls;
+ public SetDomain<V> Nulls;
+
+ public Domain(SetDomain<V> nonNulls, SetDomain<V> nulls)
+ {
+ this.NonNulls = nonNulls;
+ this.Nulls = nulls;
+ }
+
+ public bool IsNonNull(V v)
+ {
+ return this.NonNulls.Contains (v);
+ }
+
+ public bool IsNull(V v)
+ {
+ return this.Nulls.Contains (v);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// ExpressionAssertDischarger.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.ControlFlow;
+
+namespace Mono.CodeContracts.Static.Analysis.NonNull {
+ struct ExpressionAssertDischarger<E, V>
+ : ISymbolicExpressionVisitor<E, E, V, bool, ProofOutcome>
+ where E : IEquatable<E>
+ where V : IEquatable<V> {
+ private readonly Analysis<E, V> analysis;
+ private readonly APC pc;
+
+ public ExpressionAssertDischarger(Analysis<E, V> analysis, APC pc)
+ {
+ this.analysis = analysis;
+ this.pc = pc;
+ }
+
+ private IExpressionContextProvider<E, V> ContextProvider
+ {
+ get { return this.analysis.ContextProvider; }
+ }
+
+ #region Implementation of IExpressionILVisitor<Expression,Expression,Variable,bool,ProofOutcome>
+ private ProofOutcome Recurse(bool polarity, E expr)
+ {
+ return this.ContextProvider.ExpressionContext.Decode<bool, ProofOutcome, ExpressionAssertDischarger<E, V>> (expr, this, polarity);
+ }
+
+ public ProofOutcome Binary(E orig, BinaryOperator op, V dest, E operand1, E operand2, bool polarity)
+ {
+ switch (op) {
+ case BinaryOperator.Ceq:
+ case BinaryOperator.Cobjeq:
+ if (this.ContextProvider.ExpressionContext.IsZero (operand2) || this.ContextProvider.ExpressionContext.IsZero (operand1))
+ return this.Recurse (!polarity, operand1);
+ return ProofOutcome.Top;
+ case BinaryOperator.Cne_Un:
+ if (this.ContextProvider.ExpressionContext.IsZero(operand2) || this.ContextProvider.ExpressionContext.IsZero(operand1))
+ return this.Recurse (polarity, operand1);
+ return ProofOutcome.Top;
+ default:
+ return this.SymbolicConstant (orig, this.ContextProvider.ExpressionContext.Unrefine (orig), polarity);
+ }
+ }
+
+ public ProofOutcome Isinst(E orig, TypeNode type, V dest, E obj, bool polarity)
+ {
+ if (!polarity)
+ return this.analysis.IsNull (this.pc, dest);
+ ProofOutcome outcome = this.analysis.IsNonNull (this.pc, dest);
+
+ return outcome != ProofOutcome.True ? outcome : this.Recurse (true, obj);
+ }
+
+ public ProofOutcome LoadNull(E orig, V dest, bool polarity)
+ {
+ return polarity ? ProofOutcome.False : ProofOutcome.True;
+ }
+
+ public ProofOutcome LoadConst(E orig, TypeNode type, object constant, V dest, bool polarity)
+ {
+ var isConstantEqualZero = constant is int && (int) constant == 0;
+
+ return (isConstantEqualZero != polarity) ? ProofOutcome.True : ProofOutcome.False;
+ }
+
+ public ProofOutcome Sizeof(E pc, TypeNode type, V dest, bool polarity)
+ {
+ return polarity ? ProofOutcome.True : ProofOutcome.False;
+ }
+
+ public ProofOutcome Unary(E orig, UnaryOperator op, bool unsigned, V dest, E source, bool polarity)
+ {
+ switch (op) {
+ case UnaryOperator.Conv_i:
+ case UnaryOperator.Conv_i1:
+ case UnaryOperator.Conv_i2:
+ case UnaryOperator.Conv_i4:
+ case UnaryOperator.Conv_i8:
+ case UnaryOperator.Conv_u:
+ case UnaryOperator.Conv_u1:
+ case UnaryOperator.Conv_u2:
+ case UnaryOperator.Conv_u4:
+ case UnaryOperator.Conv_u8:
+ return this.Recurse (polarity, source);
+ case UnaryOperator.Neg:
+ return this.Recurse(polarity, source);
+ case UnaryOperator.Not:
+ return this.Recurse(!polarity, source);
+ default:
+ return this.SymbolicConstant (orig, this.ContextProvider.ExpressionContext.Unrefine (orig), polarity);
+ }
+ }
+ #endregion
+
+ #region Implementation of ISymbolicExpressionVisitor<Expression,Expression,Variable,bool,ProofOutcome>
+ public ProofOutcome SymbolicConstant(E pc, V variable, bool polarity)
+ {
+ return polarity ? this.analysis.IsNonNull (this.pc, variable) : this.analysis.IsNull(this.pc, variable);
+ }
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// ExpressionAssumeDecoder.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.NonNull {
+ struct ExpressionAssumeDecoder<E, V>
+ : ISymbolicExpressionVisitor<E, E, V, Pair<bool, Domain<E, V>>, Domain<E, V>>
+ where V : IEquatable<V>
+ where E : IEquatable<E> {
+ private readonly IExpressionContextProvider<E, V> context_provider;
+
+ public ExpressionAssumeDecoder (IExpressionContextProvider<E, V> contextProvider)
+ {
+ this.context_provider = contextProvider;
+ }
+
+ #region ISymbolicExpressionVisitor<E,E,V,Pair<bool,Domain<E,V>>,Domain<E,V>> Members
+ public Domain<E, V> Binary (E pc, BinaryOperator op, V dest, E operand1, E operand2, Pair<bool, Domain<E, V>> data)
+ {
+ IExpressionContext<E, V> exprCtx = this.context_provider.ExpressionContext;
+ switch (op) {
+ case BinaryOperator.Ceq:
+ case BinaryOperator.Cobjeq:
+ if (data.Value.IsNull (exprCtx.Unrefine (operand2)) || exprCtx.IsZero (operand2)
+ || data.Value.IsNull (exprCtx.Unrefine (operand1)) || exprCtx.IsZero (operand1))
+ return Recurse (new Pair<bool, Domain<E, V>> (!data.Key, data.Value), operand1);
+ if (data.Value.IsNonNull (exprCtx.Unrefine (operand1)) || data.Value.IsNonNull (exprCtx.Unrefine (operand2)))
+ return Analysis<E, V>.AssumeNonNull (exprCtx.Unrefine (operand2), data.Value);
+ return data.Value;
+ case BinaryOperator.Cne_Un:
+ if (data.Value.IsNull (exprCtx.Unrefine (operand2)) || exprCtx.IsZero (operand2)
+ || data.Value.IsNull (exprCtx.Unrefine (operand1)) || exprCtx.IsZero (operand1))
+ return Recurse (data, operand1);
+
+ return data.Value;
+ default:
+ return data.Value;
+ }
+ }
+
+ public Domain<E, V> Isinst (E pc, TypeNode type, V dest, E obj, Pair<bool, Domain<E, V>> data)
+ {
+ if (data.Key)
+ return Recurse (new Pair<bool, Domain<E, V>> (true, Analysis<E, V>.AssumeNonNull (dest, data.Value)), obj);
+ return data.Value;
+ }
+
+ public Domain<E, V> LoadNull (E pc, V dest, Pair<bool, Domain<E, V>> data)
+ {
+ if (data.Key)
+ return Domain<E, V>.BottomValue;
+ return data.Value;
+ }
+
+ public Domain<E, V> LoadConst (E pc, TypeNode type, object constant, V dest, Pair<bool, Domain<E, V>> data)
+ {
+ if (constant is string)
+ return data.Value;
+
+ var convertible = constant as IConvertible;
+ bool isZero = false;
+ if (convertible != null) {
+ try {
+ isZero = convertible.ToInt32 (null) == 0;
+ } catch {
+ return data.Value;
+ }
+ }
+
+ if (data.Key && isZero || !data.Key && !isZero)
+ return Domain<E, V>.BottomValue;
+
+ return data.Value;
+ }
+
+ public Domain<E, V> Sizeof (E pc, TypeNode type, V dest, Pair<bool, Domain<E, V>> data)
+ {
+ return data.Value;
+ }
+
+ public Domain<E, V> Unary (E pc, UnaryOperator op, bool unsigned, V dest, E source, Pair<bool, Domain<E, V>> data)
+ {
+ switch (op) {
+ case UnaryOperator.Conv_i:
+ case UnaryOperator.Conv_i1:
+ case UnaryOperator.Conv_i2:
+ case UnaryOperator.Conv_i4:
+ case UnaryOperator.Conv_i8:
+ case UnaryOperator.Conv_u:
+ case UnaryOperator.Conv_u1:
+ case UnaryOperator.Conv_u2:
+ case UnaryOperator.Conv_u4:
+ case UnaryOperator.Conv_u8:
+ return Recurse (data, source);
+ case UnaryOperator.Neg:
+ return Recurse (data, source);
+ case UnaryOperator.Not:
+ return Recurse (new Pair<bool, Domain<E, V>> (!data.Key, data.Value), source);
+ default:
+ return data.Value;
+ }
+ }
+
+ public Domain<E, V> SymbolicConstant (E orig, V variable, Pair<bool, Domain<E, V>> data)
+ {
+ if (data.Key) {
+ return !this.context_provider.ExpressionContext.IsZero (orig)
+ ? Domain<E, V>.BottomValue
+ : Analysis<E, V>.AssumeNonNull (variable, data.Value);
+ }
+
+ if (data.Value.NonNulls.Contains (variable))
+ return Domain<E, V>.BottomValue;
+
+ return Analysis<E, V>.AssumeNull (variable, data.Value);
+ }
+ #endregion
+
+ private Domain<E, V> Recurse (Pair<bool, Domain<E, V>> pair, E expr)
+ {
+ return this.context_provider.ExpressionContext.Decode<Pair<bool, Domain<E, V>>, Domain<E, V>, ExpressionAssumeDecoder<E, V>> (expr, this, pair);
+ }
+ }
+}
--- /dev/null
+//
+// NonNullAnalysisFacade.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.Analysis.Drivers;
+
+namespace Mono.CodeContracts.Static.Analysis.NonNull {
+ class NonNullAnalysisFacade : IMethodAnalysis {
+ #region IMethodAnalysis Members
+ public string Name
+ {
+ get { return "Non-null"; }
+ }
+
+ public IMethodResult<Variable> Analyze<Expression, Variable>
+ (string fullMethodName, IMethodDriver<Expression, Variable> methodDriver)
+ where Expression : IEquatable<Expression>
+ where Variable : IEquatable<Variable>
+ {
+ var analysis = new Analysis<Expression, Variable> (methodDriver);
+ methodDriver.HybridLayer.CreateForward (analysis) (analysis.InitialValue (methodDriver.KeyConverter));
+ analysis.MethodAnalysis = this;
+
+ return analysis;
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// APCMap.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.StackAnalysis {
+ class APCMap<T> {
+ private readonly Dictionary<int, T>[] block_map;
+ private IImmutableIntMap<bool> call_on_this_map;
+
+ public APCMap (Subroutine parent)
+ {
+ this.block_map = new Dictionary<int, T>[parent.BlockCount];
+ this.call_on_this_map = ImmutableIntMap<bool>.Empty ();
+ }
+
+ public T this [APC key]
+ {
+ get
+ {
+ T value;
+ if (!TryGetValue (key, out value))
+ throw new KeyNotFoundException ();
+ return value;
+ }
+ }
+
+ public void Add (APC pc, T value)
+ {
+ Dictionary<int, T> pcBlockMap = this.block_map [pc.Block.Index];
+ if (pcBlockMap == null)
+ this.block_map [pc.Block.Index] = pcBlockMap = new Dictionary<int, T> ();
+
+ pcBlockMap.Add (pc.Index, value);
+ }
+
+ public bool TryGetValue (APC pc, out T obj)
+ {
+ Dictionary<int, T> dictionary = this.block_map [pc.Block.Index];
+ if (dictionary != null)
+ return dictionary.TryGetValue (pc.Index, out obj);
+
+ obj = default(T);
+ return false;
+ }
+
+ public bool ContainsKey (APC pc)
+ {
+ Dictionary<int, T> dictionary = this.block_map [pc.Block.Index];
+ if (dictionary == null)
+ return false;
+ return dictionary.ContainsKey (pc.Index);
+ }
+
+ public bool IsCallOnThis (APC key)
+ {
+ return this.call_on_this_map [key.Block.Index];
+ }
+
+ public void AddCallOnThis (APC pc)
+ {
+ this.call_on_this_map = this.call_on_this_map.Add (pc.Block.Index, true);
+ }
+ }
+}
--- /dev/null
+//
+// SequenceGenerator.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections;
+using System.Collections.Generic;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.StackAnalysis {
+ class SequenceGenerator : IIndexable<int>, IEnumerable<int> {
+ private readonly short count;
+ private readonly short from;
+
+ public SequenceGenerator (int from, int count)
+ {
+ this.from = checked((short) from);
+ this.count = checked((short) count);
+ }
+
+ #region Implementation of IIndexable<int>
+ public int Count {
+ get { return this.count; }
+ }
+
+ public int this [int index] {
+ get { return this.from + index; }
+ }
+ #endregion
+
+ #region Implementation of IEnumerable
+ public IEnumerator<int> GetEnumerator ()
+ {
+ for (int i = 0; i < this.count; i++)
+ yield return this [i];
+ }
+
+ IEnumerator IEnumerable.GetEnumerator ()
+ {
+ return GetEnumerator ();
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// StackDecoder.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Analysis.StackAnalysis {
+ struct StackDecoder<TContext, TData, TResult, TVisitor> : IILVisitor<APC, Dummy, Dummy, TData, TResult>
+ where TContext : IMethodContextProvider
+ where TVisitor : IILVisitor<APC, int, int, TData, TResult>
+ {
+ private readonly StackDepthProvider<TContext> parent;
+ private readonly TVisitor visitor;
+
+ public StackDecoder(StackDepthProvider<TContext> parent,
+ TVisitor visitor)
+ {
+ this.parent = parent;
+ this.visitor = visitor;
+ }
+
+ private int Pop(APC label, int count)
+ {
+ return this.parent.GlobalStackDepth (label) - 1 - count;
+ }
+
+ private SequenceGenerator PopSequence(APC pc, int args, int offset)
+ {
+ return new SequenceGenerator (this.parent.GlobalStackDepth (pc) - args - offset, args);
+ }
+
+ private int Push(APC label, int count)
+ {
+ return this.parent.GlobalStackDepth (label) - count;
+ }
+
+ private int Push(APC label, int args, TypeNode returnType)
+ {
+ if (this.parent.MetaDataProvider.IsVoid (returnType))
+ return -1;
+
+ return Push (label, args);
+ }
+
+ private int GetParametersCount(Method ctor, int extraVarargs)
+ {
+ int result = extraVarargs + this.parent.MetaDataProvider.Parameters (ctor).Count;
+ if (!this.parent.MetaDataProvider.IsStatic (ctor))
+ ++result;
+ return result;
+ }
+
+ private bool RemapParameterToLoadStack(APC pc, ref Parameter param, out bool isLoadResult, out int loadStackOffset, out bool isOld, out APC lookupPC)
+ {
+ if (pc.SubroutineContext == null) {
+ isLoadResult = false;
+ loadStackOffset = 0;
+ isOld = false;
+ lookupPC = pc;
+ return false;
+ }
+
+ if (pc.Block.Subroutine.IsRequires) {
+ isLoadResult = false;
+ isOld = false;
+ lookupPC = pc;
+ for (LispList<Edge<CFGBlock, EdgeTag>> list = pc.SubroutineContext; list != null; list = list.Tail) {
+ EdgeTag edgeTag = list.Head.Tag;
+ if (edgeTag == EdgeTag.Entry) {
+ param = RemapParameter (param, list.Head.From, pc.Block);
+ loadStackOffset = 0;
+ return false;
+ }
+ if (edgeTag.Is (EdgeTag.BeforeMask)) {
+ int stackDepth = this.parent.LocalStackDepth (pc);
+ loadStackOffset = this.parent.MetaDataProvider.ParameterStackIndex (param) + stackDepth;
+ return true;
+ }
+ }
+ throw new InvalidOperationException ();
+ }
+
+ if (pc.Block.Subroutine.IsEnsuresOrOldValue) {
+ isOld = true;
+ for (LispList<Edge<CFGBlock, EdgeTag>> ctx = pc.SubroutineContext; ctx != null; ctx = ctx.Tail) {
+ EdgeTag tag = ctx.Head.Tag;
+ if (tag == EdgeTag.Exit) {
+ param = RemapParameter (param, ctx.Head.From, pc.Block);
+ isLoadResult = false;
+ loadStackOffset = 0;
+ lookupPC = pc;
+ return false;
+ }
+
+ if (tag == EdgeTag.AfterCall) {
+ loadStackOffset = this.parent.MetaDataProvider.ParameterStackIndex (param);
+ isLoadResult = false;
+ lookupPC = new APC (ctx.Head.From, 0, ctx.Tail);
+ return true;
+ }
+
+ if (tag == EdgeTag.AfterNewObj) {
+ if (this.parent.MetaDataProvider.ParameterIndex (param) == 0) {
+ loadStackOffset = this.parent.LocalStackDepth (pc);
+ isLoadResult = true;
+ lookupPC = pc;
+ isOld = false;
+ return false;
+ }
+
+ loadStackOffset = this.parent.MetaDataProvider.ParameterIndex (param);
+ isLoadResult = false;
+ lookupPC = new APC (ctx.Head.From, 0, ctx.Tail);
+ return true;
+ }
+ if (tag == EdgeTag.OldManifest) {
+ param = RemapParameter (param, ctx.Tail.Head.From, pc.Block);
+ isOld = false;
+ isLoadResult = false;
+ loadStackOffset = 0;
+ lookupPC = pc;
+ return false;
+ }
+ }
+ throw new InvalidOperationException ();
+ }
+
+ if (pc.Block.Subroutine.IsInvariant) {
+ for (LispList<Edge<CFGBlock, EdgeTag>> list = pc.SubroutineContext; list != null; list = list.Tail) {
+ EdgeTag tag = list.Head.Tag;
+ if (tag == EdgeTag.Entry || tag == EdgeTag.Exit) {
+ Method method;
+ if (pc.TryGetContainingMethod (out method)) {
+ param = this.parent.MetaDataProvider.This (method);
+ isLoadResult = false;
+ loadStackOffset = 0;
+ isOld = tag == EdgeTag.Exit;
+ lookupPC = pc;
+ return false;
+ }
+ isLoadResult = false;
+ loadStackOffset = 0;
+ isOld = false;
+ lookupPC = pc;
+ return false;
+ }
+ if (tag == EdgeTag.AfterCall) {
+ Method calledMethod;
+ bool isNewObj;
+ bool isVirtual;
+ list.Head.From.IsMethodCallBlock (out calledMethod, out isNewObj, out isVirtual);
+ int count = this.parent.MetaDataProvider.Parameters (calledMethod).Count;
+ loadStackOffset = count;
+ isLoadResult = false;
+ isOld = true;
+ lookupPC = new APC (list.Head.From, 0, list.Tail);
+ return true;
+ }
+ if (tag == EdgeTag.AfterNewObj) {
+ isLoadResult = true;
+ loadStackOffset = this.parent.LocalStackDepth (pc);
+ isOld = false;
+ lookupPC = pc;
+ return false;
+ }
+ if (tag.Is (EdgeTag.BeforeMask))
+ throw new InvalidOperationException ("this should never happen");
+ }
+ throw new InvalidOperationException ("this should never happen");
+ }
+
+ isLoadResult = false;
+ loadStackOffset = 0;
+ isOld = false;
+ lookupPC = pc;
+ return false;
+ }
+
+ private Parameter RemapParameter(Parameter p, CFGBlock parentMethodBlock, CFGBlock subroutineBlock)
+ {
+ Method parentMethod = ((IMethodInfo) parentMethodBlock.Subroutine).Method;
+ Method method = ((IMethodInfo) subroutineBlock.Subroutine).Method;
+
+ if (this.parent.MetaDataProvider.Equal (method, parentMethod))
+ return p;
+
+ int index = this.parent.MetaDataProvider.ParameterIndex (p);
+ if (this.parent.MetaDataProvider.IsStatic (parentMethod) || index != 0)
+ return this.parent.MetaDataProvider.Parameters (parentMethod)[index];
+
+ return this.parent.MetaDataProvider.This (parentMethod);
+ }
+
+ private bool IsReferenceType(APC pc, TypeNode type)
+ {
+ return this.parent.MetaDataProvider.IsReferenceType (type);
+ }
+
+ private TypeNode GetSpecializedType(APC pc, TypeNode type)
+ {
+ var methodInfo = pc.Block.Subroutine as IMethodInfo;
+ if (methodInfo == null)
+ return type;
+
+ throw new NotImplementedException ();
+ }
+
+ #region Implementation of IExpressionILVisitor<APC,Type,Dummy,Dummy,Data,Result>
+ public TResult Binary(APC pc, BinaryOperator op, Dummy dest, Dummy operand1, Dummy operand2, TData data)
+ {
+ return this.visitor.Binary (pc, op, Push (pc, 2), Pop (pc, 1), Pop (pc, 0), data);
+ }
+
+ public TResult Isinst(APC pc, TypeNode type, Dummy dest, Dummy obj, TData data)
+ {
+ return this.visitor.Isinst (pc, type, Push (pc, 1), Pop (pc, 0), data);
+ }
+
+ public TResult LoadNull(APC pc, Dummy dest, TData polarity)
+ {
+ return this.visitor.LoadNull (pc, Push (pc, 0), polarity);
+ }
+
+ public TResult LoadConst(APC pc, TypeNode type, object constant, Dummy dest, TData data)
+ {
+ return this.visitor.LoadConst (pc, type, constant, Push (pc, 0), data);
+ }
+
+ public TResult Sizeof(APC pc, TypeNode type, Dummy dest, TData data)
+ {
+ return this.visitor.Sizeof (pc, type, Push (pc, 0), data);
+ }
+
+ public TResult Unary(APC pc, UnaryOperator op, bool unsigned, Dummy dest, Dummy source, TData data)
+ {
+ return this.visitor.Unary (pc, op, unsigned, Push (pc, 1), Pop (pc, 0), data);
+ }
+ #endregion
+
+ #region Implementation of ISyntheticILVisitor<APC,Method,Field,Type,Dummy,Dummy,Data,Result>
+ public TResult Entry(APC pc, Method method, TData data)
+ {
+ return this.visitor.Entry (pc, method, data);
+ }
+
+ public TResult Assume(APC pc, EdgeTag tag, Dummy condition, TData data)
+ {
+ return this.visitor.Assume (pc, tag, Pop (pc, 0), data);
+ }
+
+ public TResult Assert(APC pc, EdgeTag tag, Dummy condition, TData data)
+ {
+ return this.visitor.Assert (pc, tag, Pop (pc, 0), data);
+ }
+
+ public TResult BeginOld(APC pc, APC matchingEnd, TData data)
+ {
+ return this.visitor.BeginOld (pc, matchingEnd, data);
+ }
+
+ public TResult EndOld(APC pc, APC matchingBegin, TypeNode type, Dummy dest, Dummy source, TData data)
+ {
+ if (pc.InsideOldManifestation)
+ return this.visitor.LoadStack (pc, 1, Push (matchingBegin, 0), Pop (pc, 0), false, data);
+
+ return this.visitor.EndOld (pc, matchingBegin, type, Push (matchingBegin, 0), Pop (pc, 0), data);
+ }
+
+ public TResult LoadStack(APC pc, int offset, Dummy dest, Dummy source, bool isOld, TData data)
+ {
+ return this.visitor.LoadStack (pc, offset, Push (pc, 0), Pop (pc, offset), isOld, data);
+ }
+
+ public TResult LoadStackAddress(APC pc, int offset, Dummy dest, Dummy source, TypeNode type, bool isOld, TData data)
+ {
+ return this.visitor.LoadStackAddress (pc, offset, Push (pc, 0), Pop (pc, offset), type, isOld, data);
+ }
+
+ public TResult LoadResult(APC pc, TypeNode type, Dummy dest, Dummy source, TData data)
+ {
+ int offset = this.parent.LocalStackDepth (pc);
+ return this.visitor.LoadResult (pc, type, Push (pc, 0), Pop (pc, offset), data);
+ }
+ #endregion
+
+ #region Implementation of IILVisitor<APC,Local,Parameter,Method,Field,Type,Dummy,Dummy,Data,Result>
+ public TResult Arglist(APC pc, Dummy dest, TData data)
+ {
+ return this.visitor.Arglist (pc, Push (pc, 0), data);
+ }
+
+ public TResult Branch(APC pc, APC target, bool leavesExceptionBlock, TData data)
+ {
+ return this.visitor.Branch (pc, target, leavesExceptionBlock, data);
+ }
+
+ public TResult BranchCond(APC pc, APC target, BranchOperator bop, Dummy value1, Dummy value2, TData data)
+ {
+ return this.visitor.BranchCond (pc, target, bop, Pop (pc, 1), Pop (pc, 0), data);
+ }
+
+ public TResult BranchTrue(APC pc, APC target, Dummy cond, TData data)
+ {
+ return this.visitor.BranchTrue (pc, target, Pop (pc, 0), data);
+ }
+
+ public TResult BranchFalse(APC pc, APC target, Dummy cond, TData data)
+ {
+ return this.visitor.BranchFalse (pc, target, Pop (pc, 0), data);
+ }
+
+ public TResult Break(APC pc, TData data)
+ {
+ return this.visitor.Break (pc, data);
+ }
+
+ public TResult Call<TypeList, ArgList>(APC pc, Method method, bool virt, TypeList extraVarargs, Dummy dest, ArgList args, TData data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<Dummy>
+ {
+ int argsCount = GetParametersCount (method, extraVarargs == null ? 0 : extraVarargs.Count);
+ return this.visitor.Call (pc, method, virt, extraVarargs, Push (pc, argsCount, this.parent.MetaDataProvider.ReturnType (method)), PopSequence (pc, argsCount, 0), data);
+ }
+
+ public TResult Calli<TypeList, ArgList>(APC pc, TypeNode returnType, TypeList argTypes, bool instance, Dummy dest, Dummy functionPointer, ArgList args, TData data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<Dummy>
+ {
+ int argsCount = argTypes.Count + (instance ? 1 : 0);
+ return this.visitor.Calli (pc, returnType, argTypes, instance, Push (pc, argsCount + 1, returnType), Pop (pc, 0), PopSequence (pc, argsCount, 1), data);
+ }
+
+ public TResult CheckFinite(APC pc, Dummy dest, Dummy source, TData data)
+ {
+ return this.visitor.CheckFinite (pc, Push (pc, 1), Pop (pc, 0), data);
+ }
+
+ public TResult CopyBlock(APC pc, Dummy destAddress, Dummy srcAddress, Dummy len, TData data)
+ {
+ return this.visitor.CopyBlock (pc, Pop (pc, 2), Pop (pc, 1), Pop (pc, 0), data);
+ }
+
+ public TResult EndFilter(APC pc, Dummy decision, TData data)
+ {
+ return this.visitor.EndFilter (pc, Pop (pc, 0), data);
+ }
+
+ public TResult EndFinally(APC pc, TData data)
+ {
+ return this.visitor.EndFinally (pc, data);
+ }
+
+ public TResult Jmp(APC pc, Method method, TData data)
+ {
+ return this.visitor.Jmp (pc, method, data);
+ }
+
+ public TResult LoadArg(APC pc, Parameter argument, bool dummyOld, Dummy dest, TData data)
+ {
+ Parameter p = argument;
+ bool isLdResult;
+ int loadStackOffset;
+ bool isOld;
+ APC lookupPC;
+ if (RemapParameterToLoadStack (pc, ref argument, out isLdResult, out loadStackOffset, out isOld, out lookupPC))
+ return this.visitor.LoadStack (pc, loadStackOffset, Push (pc, 0), Pop (lookupPC, loadStackOffset), isOld, data);
+
+ if (argument == null)
+ argument = p;
+
+ if (isLdResult) {
+ if (this.parent.MetaDataProvider.IsStruct (this.parent.MetaDataProvider.DeclaringType (this.parent.MetaDataProvider.DeclaringMethod (argument))))
+ return this.visitor.LoadStackAddress (pc, loadStackOffset, Push (pc, 0), Pop (pc, loadStackOffset), this.parent.MetaDataProvider.ParameterType (argument), isOld, data);
+
+ return this.visitor.LoadResult (pc, this.parent.MetaDataProvider.ParameterType (argument), Push (pc, 0), Pop (pc, loadStackOffset), data);
+ }
+
+ return this.visitor.LoadArg (pc, argument, isOld, Push (pc, 0), data);
+ }
+
+ public TResult LoadArgAddress(APC pc, Parameter argument, bool dummyOld, Dummy dest, TData data)
+ {
+ bool isLoadResult;
+ int loadStackOffset;
+ bool isOld;
+ APC lookupPC;
+ if (RemapParameterToLoadStack (pc, ref argument, out isLoadResult, out loadStackOffset, out isOld, out lookupPC))
+ return this.visitor.LoadStackAddress (pc, loadStackOffset, Push (pc, 0), Pop (lookupPC, loadStackOffset), this.parent.MetaDataProvider.ParameterType (argument), isOld, data);
+
+ if (isLoadResult)
+ throw new InvalidOperationException ();
+
+ return this.visitor.LoadArgAddress (pc, argument, isOld, Push (pc, 0), data);
+ }
+
+ public TResult LoadLocal(APC pc, Local local, Dummy dest, TData data)
+ {
+ return this.visitor.LoadLocal (pc, local, Push (pc, 0), data);
+ }
+
+ public TResult LoadLocalAddress(APC pc, Local local, Dummy dest, TData data)
+ {
+ return this.visitor.LoadLocalAddress (pc, local, Push (pc, 0), data);
+ }
+
+ public TResult Nop(APC pc, TData data)
+ {
+ return this.visitor.Nop (pc, data);
+ }
+
+ public TResult Pop(APC pc, Dummy source, TData data)
+ {
+ return this.visitor.Pop (pc, Pop (pc, 0), data);
+ }
+
+ public TResult Return(APC pc, Dummy source, TData data)
+ {
+ return this.visitor.Nop (pc, data);
+ }
+
+ public TResult StoreArg(APC pc, Parameter argument, Dummy source, TData data)
+ {
+ return this.visitor.StoreArg (pc, argument, Pop (pc, 0), data);
+ }
+
+ public TResult StoreLocal(APC pc, Local local, Dummy source, TData data)
+ {
+ return this.visitor.StoreLocal (pc, local, Pop (pc, 0), data);
+ }
+
+ public TResult Switch(APC pc, TypeNode type, IEnumerable<Pair<object, APC>> cases, Dummy value, TData data)
+ {
+ return this.visitor.Switch (pc, type, cases, Pop (pc, 0), data);
+ }
+
+ public TResult Box(APC pc, TypeNode type, Dummy dest, Dummy source, TData data)
+ {
+ type = GetSpecializedType (pc, type);
+ if (IsReferenceType (pc, type))
+ return this.visitor.Nop (pc, data);
+
+ return this.visitor.Box (pc, type, Push (pc, 1), Pop (pc, 0), data);
+ }
+
+ public TResult ConstrainedCallvirt<TypeList, ArgList>(APC pc, Method method, TypeNode constraint, TypeList extraVarargs, Dummy dest, ArgList args, TData data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<Dummy>
+ {
+ int argsCount = GetParametersCount (method, extraVarargs == null ? 0 : extraVarargs.Count);
+ return this.visitor.ConstrainedCallvirt (pc, method, constraint, extraVarargs, Push (pc, argsCount, this.parent.MetaDataProvider.ReturnType (method)), PopSequence (pc, argsCount, 0), data);
+ }
+
+ public TResult CastClass(APC pc, TypeNode type, Dummy dest, Dummy obj, TData data)
+ {
+ return this.visitor.CastClass (pc, type, Push (pc, 1), Pop (pc, 0), data);
+ }
+
+ public TResult CopyObj(APC pc, TypeNode type, Dummy destPtr, Dummy sourcePtr, TData data)
+ {
+ return this.visitor.CopyObj (pc, type, Pop (pc, 1), Pop (pc, 0), data);
+ }
+
+ public TResult Initobj(APC pc, TypeNode type, Dummy ptr, TData data)
+ {
+ return this.visitor.Initobj (pc, type, Pop (pc, 0), data);
+ }
+
+ public TResult LoadElement(APC pc, TypeNode type, Dummy dest, Dummy array, Dummy index, TData data)
+ {
+ return this.visitor.LoadElement (pc, type, Push (pc, 2), Pop (pc, 1), Pop (pc, 0), data);
+ }
+
+ public TResult LoadField(APC pc, Field field, Dummy dest, Dummy obj, TData data)
+ {
+ return this.visitor.LoadField (pc, field, Push (pc, 1), Pop (pc, 0), data);
+ }
+
+ public TResult LoadFieldAddress(APC pc, Field field, Dummy dest, Dummy obj, TData data)
+ {
+ return this.visitor.LoadFieldAddress (pc, field, Push (pc, 1), Pop (pc, 0), data);
+ }
+
+ public TResult LoadLength(APC pc, Dummy dest, Dummy array, TData data)
+ {
+ return this.visitor.LoadLength (pc, Push (pc, 1), Pop (pc, 0), data);
+ }
+
+ public TResult LoadStaticField(APC pc, Field field, Dummy dest, TData data)
+ {
+ return this.visitor.LoadStaticField (pc, field, Push (pc, 0), data);
+ }
+
+ public TResult LoadStaticFieldAddress(APC pc, Field field, Dummy dest, TData data)
+ {
+ return this.visitor.LoadStaticFieldAddress (pc, field, Push (pc, 0), data);
+ }
+
+ public TResult LoadTypeToken(APC pc, TypeNode type, Dummy dest, TData data)
+ {
+ return this.visitor.LoadTypeToken (pc, type, Push (pc, 0), data);
+ }
+
+ public TResult LoadFieldToken(APC pc, Field field, Dummy dest, TData data)
+ {
+ return this.visitor.LoadFieldToken (pc, field, Push (pc, 0), data);
+ }
+
+ public TResult LoadMethodToken(APC pc, Method method, Dummy dest, TData data)
+ {
+ return this.visitor.LoadMethodToken (pc, method, Push (pc, 0), data);
+ }
+
+ public TResult NewArray<ArgList>(APC pc, TypeNode type, Dummy dest, ArgList lengths, TData data)
+ where ArgList : IIndexable<Dummy>
+ {
+ return this.visitor.NewArray (pc, type, Push (pc, 1), PopSequence (pc, lengths.Count, 0), data);
+ }
+
+ public TResult NewObj<ArgList>(APC pc, Method ctor, Dummy dest, ArgList args, TData data)
+ where ArgList : IIndexable<Dummy>
+ {
+ int argsCount = GetParametersCount (ctor, 0) - 1;
+ return this.visitor.NewObj (pc, ctor, Push (pc, argsCount), PopSequence (pc, argsCount, 0), data);
+ }
+
+ public TResult MkRefAny(APC pc, TypeNode type, Dummy dest, Dummy obj, TData data)
+ {
+ return this.visitor.MkRefAny (pc, type, Push (pc, 1), Pop (pc, 0), data);
+ }
+
+ public TResult RefAnyType(APC pc, Dummy dest, Dummy source, TData data)
+ {
+ return this.visitor.RefAnyType (pc, Push (pc, 1), Pop (pc, 0), data);
+ }
+
+ public TResult RefAnyVal(APC pc, TypeNode type, Dummy dest, Dummy source, TData data)
+ {
+ return this.visitor.RefAnyVal (pc, type, Push (pc, 1), Pop (pc, 0), data);
+ }
+
+ public TResult Rethrow(APC pc, TData data)
+ {
+ return this.visitor.Rethrow (pc, data);
+ }
+
+ public TResult StoreElement(APC pc, TypeNode type, Dummy array, Dummy index, Dummy value, TData data)
+ {
+ return this.visitor.StoreElement (pc, type, Pop (pc, 2), Pop (pc, 1), Pop (pc, 0), data);
+ }
+
+ public TResult StoreField(APC pc, Field field, Dummy obj, Dummy value, TData data)
+ {
+ return this.visitor.StoreField (pc, field, Pop (pc, 1), Pop (pc, 0), data);
+ }
+
+ public TResult StoreStaticField(APC pc, Field field, Dummy value, TData data)
+ {
+ return this.visitor.StoreStaticField (pc, field, Pop (pc, 0), data);
+ }
+
+ public TResult Throw(APC pc, Dummy exception, TData data)
+ {
+ return this.visitor.Throw (pc, Pop (pc, 0), data);
+ }
+
+ public TResult Unbox(APC pc, TypeNode type, Dummy dest, Dummy obj, TData data)
+ {
+ return this.visitor.Unbox (pc, type, Push (pc, 1), Pop (pc, 0), data);
+ }
+
+ public TResult UnboxAny(APC pc, TypeNode type, Dummy dest, Dummy obj, TData data)
+ {
+ return this.visitor.UnboxAny (pc, type, Push (pc, 1), Pop (pc, 0), data);
+ }
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// StackDepthFactory.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis.StackAnalysis {
+ static class StackDepthFactory {
+ public static IILDecoder<APC, int, int, IStackContextProvider, Dummy> Create<TContext> (IILDecoder<APC, Dummy, Dummy, TContext, Dummy> ilDecoder,
+ IMetaDataProvider metadataDecoder) where TContext : IMethodContextProvider
+ {
+ return new StackDepthProvider<TContext> (ilDecoder, metadataDecoder);
+ }
+ }
+}
--- /dev/null
+//
+// StackDepthProvider.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis.StackAnalysis {
+ class StackDepthProvider<TContext> : IILVisitor<APC, Dummy, Dummy, StackInfo, StackInfo>,
+ IILDecoder<APC, int, int, IStackContextProvider, Dummy>,
+ IStackContextProvider, IStackContext,
+ IMethodContext,
+ ICFG,
+ IStackInfo where TContext : IMethodContextProvider {
+ private readonly IILDecoder<APC, Dummy, Dummy, TContext, Dummy> il_decoder;
+ private int cached_subroutine;
+ private APCMap<int> local_stack_depth_cache;
+ private APCMap<int> stack_depth_mirror_for_end_old;
+ private bool recursion_guard;
+
+ public StackDepthProvider (IILDecoder<APC, Dummy, Dummy, TContext, Dummy> ilDecoder,
+ IMetaDataProvider metaDataProvider)
+ {
+ this.il_decoder = ilDecoder;
+ MetaDataProvider = metaDataProvider;
+ }
+
+ #region Implementation of IILDecoder<APC,Local,Parameter,Method,Field,Type,int,int,IStackContextProvider<Field,Method>,Dummy>
+ public TResult ForwardDecode<TData, TResult, TVisitor> (APC pc, TVisitor visitor, TData data)
+ where TVisitor : IILVisitor<APC, int, int, TData, TResult>
+ {
+ if (pc.Index != 0 || pc.SubroutineContext != null || pc.Block != pc.Block.Subroutine.Exit || !pc.Block.Subroutine.IsMethod)
+ return this.il_decoder.ForwardDecode<TData, TResult, StackDecoder<TContext, TData, TResult, TVisitor>> (pc, new StackDecoder<TContext, TData, TResult, TVisitor> (this, visitor), data);
+ if (!pc.Block.Subroutine.HasReturnValue)
+ return visitor.Return (pc, -1, data);
+
+ int source = GlobalStackDepth (pc) - 1;
+ return visitor.Return (pc, source, data);
+ }
+
+ public bool IsUnreachable (APC pc)
+ {
+ return false;
+ }
+
+ public Dummy EdgeData (APC @from, APC to)
+ {
+ return Dummy.Value;
+ }
+ #endregion
+
+ public IMetaDataProvider MetaDataProvider { get; private set; }
+
+ private ICFG UnderlyingCFG
+ {
+ get { return this.il_decoder.ContextProvider.MethodContext.CFG; }
+ }
+
+ #region IILDecoder<APC,int,int,IStackContextProvider,Dummy> Members
+ public IStackContextProvider ContextProvider
+ {
+ get { return this; }
+ }
+ #endregion
+
+ #region IStackContextProvider Members
+ public IStackContext StackContext
+ {
+ get { return this; }
+ }
+
+ public IMethodContext MethodContext
+ {
+ get { return this; }
+ }
+ #endregion
+
+ public int GlobalStackDepth (APC pc)
+ {
+ int num = LocalStackDepth (pc);
+
+ if (pc.SubroutineContext == null || !pc.Block.Subroutine.HasContextDependentStackDepth)
+ return num;
+
+ CFGBlock block = pc.SubroutineContext.Head.From;
+ return num + GlobalStackDepth (APC.ForEnd (block, pc.SubroutineContext.Tail));
+ }
+
+ public int LocalStackDepth (APC pc)
+ {
+ return LocalStackMap (pc.Block.Subroutine) [pc];
+ }
+
+ private int OldStartDepth (Subroutine subroutine)
+ {
+ Method method = ((IMethodInfo) subroutine).Method;
+ int count = MetaDataProvider.Parameters (method).Count;
+ if (!MetaDataProvider.IsConstructor (method) && !MetaDataProvider.IsStatic (method))
+ ++count;
+ return count;
+ }
+
+ private APCMap<int> LocalStackMap (Subroutine subroutine)
+ {
+ if (this.local_stack_depth_cache == null || this.cached_subroutine != subroutine.Id) {
+ this.local_stack_depth_cache = GetStackDepthMap (subroutine);
+ this.cached_subroutine = subroutine.Id;
+ }
+ return this.local_stack_depth_cache;
+ }
+
+ private APCMap<int> GetStackDepthMap (Subroutine subroutine)
+ {
+ APCMap<int> result;
+ var key = new TypedKey ("stackDepthKey");
+ if (!subroutine.TryGetValue (key, out result)) {
+ result = ComputeStackDepthMap (subroutine);
+ subroutine.Add (key, result);
+ }
+ return result;
+ }
+
+ private APCMap<int> ComputeStackDepthMap (Subroutine subroutine)
+ {
+ var startDepths = new Dictionary<int, StackInfo> (subroutine.BlockCount);
+ APCMap<int> apcMap = this.stack_depth_mirror_for_end_old = new APCMap<int> (subroutine);
+
+ foreach (CFGBlock block in subroutine.Blocks) {
+ StackInfo stackInfo;
+ if (!startDepths.TryGetValue (block.Index, out stackInfo))
+ stackInfo = ComputeBlockStartDepth (block);
+ foreach (APC apc in block.APCs ()) {
+ apcMap.Add (apc, stackInfo.Depth);
+ stackInfo = this.il_decoder.ForwardDecode<StackInfo, StackInfo, IILVisitor<APC, Dummy, Dummy, StackInfo, StackInfo>> (apc, this, stackInfo);
+ }
+ if (!apcMap.ContainsKey (block.Last))
+ apcMap.Add (block.Last, stackInfo.Depth);
+ foreach (CFGBlock successor in subroutine.SuccessorBlocks (block)) {
+ bool oldRecursionGuard = this.recursion_guard;
+ this.recursion_guard = true;
+ try {
+ bool isExceptionHandlerEdge;
+ foreach (var info in subroutine.EdgeSubroutinesOuterToInner (block, successor, out isExceptionHandlerEdge, null).AsEnumerable ())
+ stackInfo.Adjust (info.Value.StackDelta);
+ } finally {
+ this.recursion_guard = oldRecursionGuard;
+ }
+ AddStartDepth (startDepths, successor, stackInfo);
+ }
+ }
+ return apcMap;
+ }
+
+ private StackInfo ComputeBlockStartDepth (CFGBlock block)
+ {
+ if (block.Subroutine.IsCatchFilterHeader (block))
+ return new StackInfo (1, 2);
+ return new StackInfo (0, 4);
+ }
+
+ private void AddStartDepth (Dictionary<int, StackInfo> dict, CFGBlock block, StackInfo stackDepth)
+ {
+ StackInfo stackInfo;
+ if (dict.TryGetValue (block.Index, out stackInfo))
+ return;
+ dict.Add (block.Index, stackDepth.Clone ());
+ }
+
+ #region Implementation of ICFG
+ APC ICFG.Entry
+ {
+ get { return UnderlyingCFG.Entry; }
+ }
+
+ APC ICFG.EntryAfterRequires
+ {
+ get { return UnderlyingCFG.EntryAfterRequires; }
+ }
+
+ APC ICFG.NormalExit
+ {
+ get { return UnderlyingCFG.NormalExit; }
+ }
+
+ APC ICFG.ExceptionExit
+ {
+ get { return UnderlyingCFG.ExceptionExit; }
+ }
+
+ Subroutine ICFG.Subroutine
+ {
+ get { return UnderlyingCFG.Subroutine; }
+ }
+
+ APC ICFG.Next (APC pc)
+ {
+ APC singleSuccessor;
+ if (((ICFG) this).HasSingleSuccessor (pc, out singleSuccessor))
+ return singleSuccessor;
+ return pc;
+ }
+
+ bool ICFG.HasSingleSuccessor (APC pc, out APC successor)
+ {
+ DecoratorHelper.Push (this);
+ try {
+ return UnderlyingCFG.HasSingleSuccessor (pc, out successor);
+ } finally {
+ DecoratorHelper.Pop ();
+ }
+ }
+
+ bool ICFG.HasSinglePredecessor (APC pc, out APC predecessor)
+ {
+ DecoratorHelper.Push (this);
+ try {
+ return UnderlyingCFG.HasSinglePredecessor (pc, out predecessor);
+ } finally {
+ DecoratorHelper.Pop ();
+ }
+ }
+
+ IEnumerable<APC> ICFG.Successors (APC pc)
+ {
+ DecoratorHelper.Push (this);
+ try {
+ return UnderlyingCFG.Successors (pc);
+ } finally {
+ DecoratorHelper.Pop ();
+ }
+ }
+
+ IEnumerable<APC> ICFG.Predecessors (APC pc)
+ {
+ DecoratorHelper.Push (this);
+ try {
+ return UnderlyingCFG.Predecessors (pc);
+ } finally {
+ DecoratorHelper.Pop ();
+ }
+ }
+
+ bool ICFG.IsJoinPoint (APC pc)
+ {
+ return UnderlyingCFG.IsJoinPoint (pc);
+ }
+
+ bool ICFG.IsSplitPoint (APC pc)
+ {
+ return UnderlyingCFG.IsSplitPoint (pc);
+ }
+
+ bool ICFG.IsBlockStart (APC pc)
+ {
+ return UnderlyingCFG.IsBlockStart (pc);
+ }
+
+ bool ICFG.IsBlockEnd (APC pc)
+ {
+ return UnderlyingCFG.IsBlockEnd (pc);
+ }
+
+ IILDecoder<APC, Dummy, Dummy, IMethodContextProvider, Dummy> ICFG.GetDecoder (IMetaDataProvider metaDataProvider)
+ {
+ return UnderlyingCFG.GetDecoder (metaDataProvider);
+ }
+
+ void ICFG.Print (TextWriter tw, ILPrinter<APC> printer, Func<CFGBlock, IEnumerable<LispList<Edge<CFGBlock, EdgeTag>>>> contextLookup,
+ LispList<Edge<CFGBlock, EdgeTag>> context)
+ {
+ DecoratorHelper.Push (this);
+ try {
+ UnderlyingCFG.Print (tw, printer, contextLookup, context);
+ } finally {
+ DecoratorHelper.Pop ();
+ }
+ }
+ #endregion
+
+ #region Implementation of IStackInfo
+ bool IStackInfo.IsCallOnThis (APC pc)
+ {
+ if (this.recursion_guard)
+ return false;
+ return LocalStackMap (pc.Block.Subroutine).IsCallOnThis (pc);
+ }
+ #endregion
+
+ #region Implementation of IStackContext<Field,Method>
+ public int StackDepth (APC pc)
+ {
+ return GlobalStackDepth (pc);
+ }
+ #endregion
+
+ #region Implementation of IMethodContext<Field,Method>
+ Method IMethodContext.CurrentMethod
+ {
+ get { return this.il_decoder.ContextProvider.MethodContext.CurrentMethod; }
+ }
+
+ ICFG IMethodContext.CFG
+ {
+ get { return this; }
+ }
+
+ public IEnumerable<Field> Modifies (Method method)
+ {
+ return this.il_decoder.ContextProvider.MethodContext.Modifies (method);
+ }
+
+ public IEnumerable<Method> AffectedGetters (Field field)
+ {
+ return this.il_decoder.ContextProvider.MethodContext.AffectedGetters (field);
+ }
+ #endregion
+
+ #region Implementation of IExpressionILVisitor<APC,Type,Dummy,Dummy,StackInfo,StackInfo>
+ public StackInfo Binary (APC pc, BinaryOperator op, Dummy dest, Dummy operand1, Dummy operand2, StackInfo data)
+ {
+ return data.Pop (2).Push ();
+ }
+
+ public StackInfo Isinst (APC pc, TypeNode type, Dummy dest, Dummy obj, StackInfo data)
+ {
+ return data;
+ }
+
+ public StackInfo LoadNull (APC pc, Dummy dest, StackInfo polarity)
+ {
+ return polarity.Push ();
+ }
+
+ public StackInfo LoadConst (APC pc, TypeNode type, object constant, Dummy dest, StackInfo data)
+ {
+ return data.Push ();
+ }
+
+ public StackInfo Sizeof (APC pc, TypeNode type, Dummy dest, StackInfo data)
+ {
+ return data.Push ();
+ }
+
+ public StackInfo Unary (APC pc, UnaryOperator op, bool unsigned, Dummy dest, Dummy source, StackInfo data)
+ {
+ return data.Pop (1).Push ();
+ }
+ #endregion
+
+ #region Implementation of ISyntheticILVisitor<APC,Method,Field,Type,Dummy,Dummy,StackInfo,StackInfo>
+ public StackInfo Entry (APC pc, Method method, StackInfo data)
+ {
+ return data;
+ }
+
+ public StackInfo Assume (APC pc, EdgeTag tag, Dummy condition, StackInfo data)
+ {
+ return data.Pop (1);
+ }
+
+ public StackInfo Assert (APC pc, EdgeTag tag, Dummy condition, StackInfo data)
+ {
+ return data.Pop (1);
+ }
+
+ public StackInfo BeginOld (APC pc, APC matchingEnd, StackInfo data)
+ {
+ return new StackInfo (OldStartDepth (pc.Block.Subroutine), 4);
+ }
+
+
+ public StackInfo EndOld (APC pc, APC matchingBegin, TypeNode type, Dummy dest, Dummy source, StackInfo data)
+ {
+ return new StackInfo (this.stack_depth_mirror_for_end_old [matchingBegin] + 1, 4);
+ }
+
+ public StackInfo LoadStack (APC pc, int offset, Dummy dest, Dummy source, bool isOld, StackInfo data)
+ {
+ return data.Push (data [offset]);
+ }
+
+ public StackInfo LoadStackAddress (APC pc, int offset, Dummy dest, Dummy source, TypeNode type, bool isOld, StackInfo data)
+ {
+ return data.Push ();
+ }
+
+ public StackInfo LoadResult (APC pc, TypeNode type, Dummy dest, Dummy source, StackInfo data)
+ {
+ return data.Push ();
+ }
+ #endregion
+
+ #region Implementation of IILVisitor<APC,Local,Parameter,Method,Field,Type,Dummy,Dummy,StackInfo,StackInfo>
+ public StackInfo Arglist (APC pc, Dummy dest, StackInfo data)
+ {
+ return data.Push ();
+ }
+
+ public StackInfo Branch (APC pc, APC target, bool leavesExceptionBlock, StackInfo data)
+ {
+ return data;
+ }
+
+ public StackInfo BranchCond (APC pc, APC target, BranchOperator bop, Dummy value1, Dummy value2, StackInfo data)
+ {
+ return data.Pop (2);
+ }
+
+ public StackInfo BranchTrue (APC pc, APC target, Dummy cond, StackInfo data)
+ {
+ return data.Pop (1);
+ }
+
+ public StackInfo BranchFalse (APC pc, APC target, Dummy cond, StackInfo data)
+ {
+ return data.Pop (1);
+ }
+
+ public StackInfo Break (APC pc, StackInfo data)
+ {
+ return data;
+ }
+
+ public StackInfo Call<TypeList, ArgList> (APC pc, Method method, bool virt, TypeList extraVarargs, Dummy dest, ArgList args, StackInfo data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<Dummy>
+ {
+ int count = MetaDataProvider.Parameters (method).Count + (extraVarargs == null ? 0 : extraVarargs.Count);
+ if (!MetaDataProvider.IsStatic (method)) {
+ if (data.IsThis (count))
+ this.stack_depth_mirror_for_end_old.AddCallOnThis (pc);
+ ++count;
+ }
+ data = data.Pop (count);
+ if (MetaDataProvider.IsVoidMethod (method))
+ return data;
+ return data.Push ();
+ }
+
+ public StackInfo Calli<TypeList, ArgList> (APC pc, TypeNode returnType, TypeList argTypes, bool instance, Dummy dest, Dummy functionPointer, ArgList args, StackInfo data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<Dummy>
+ {
+ int count = 1;
+ if (instance)
+ ++count;
+ int slots = count + (argTypes == null ? 0 : argTypes.Count);
+ data.Pop (slots);
+ if (MetaDataProvider.IsVoid (returnType))
+ return data;
+ return data.Push ();
+ }
+
+ public StackInfo CheckFinite (APC pc, Dummy dest, Dummy source, StackInfo data)
+ {
+ return data;
+ }
+
+ public StackInfo CopyBlock (APC pc, Dummy destAddress, Dummy srcAddress, Dummy len, StackInfo data)
+ {
+ return data.Pop (3);
+ }
+
+ public StackInfo EndFilter (APC pc, Dummy decision, StackInfo data)
+ {
+ return data.Pop (1);
+ }
+
+ public StackInfo EndFinally (APC pc, StackInfo data)
+ {
+ return new StackInfo (0, 0);
+ }
+
+ public StackInfo Jmp (APC pc, Method method, StackInfo data)
+ {
+ return new StackInfo (0, 0);
+ }
+
+ public StackInfo LoadArg (APC pc, Parameter argument, bool isOld, Dummy dest, StackInfo data)
+ {
+ if (!MetaDataProvider.IsStatic (MetaDataProvider.DeclaringMethod (argument)) && MetaDataProvider.ParameterIndex (argument) == 0)
+ return data.PushThis ();
+
+ return data.Push ();
+ }
+
+ public StackInfo LoadArgAddress (APC pc, Parameter argument, bool isOld, Dummy dest, StackInfo data)
+ {
+ return data.Push ();
+ }
+
+ public StackInfo LoadLocal (APC pc, Local local, Dummy dest, StackInfo data)
+ {
+ return data.Push ();
+ }
+
+ public StackInfo LoadLocalAddress (APC pc, Local local, Dummy dest, StackInfo data)
+ {
+ return data.Push ();
+ }
+
+ public StackInfo Nop (APC pc, StackInfo data)
+ {
+ return data;
+ }
+
+ public StackInfo Pop (APC pc, Dummy source, StackInfo data)
+ {
+ return data.Pop (1);
+ }
+
+ public StackInfo Return (APC pc, Dummy source, StackInfo data)
+ {
+ return data;
+ }
+
+ public StackInfo StoreArg (APC pc, Parameter argument, Dummy source, StackInfo data)
+ {
+ return data.Pop (1);
+ }
+
+ public StackInfo StoreLocal (APC pc, Local local, Dummy source, StackInfo data)
+ {
+ return data.Pop (1);
+ }
+
+ public StackInfo Switch (APC pc, TypeNode type, IEnumerable<Pair<object, APC>> cases, Dummy value, StackInfo data)
+ {
+ return data.Pop (1);
+ }
+
+ public StackInfo Box (APC pc, TypeNode type, Dummy dest, Dummy source, StackInfo data)
+ {
+ return data.Pop (1).Push ();
+ }
+
+ public StackInfo ConstrainedCallvirt<TypeList, ArgList> (APC pc, Method method, TypeNode constraint, TypeList extraVarargs, Dummy dest, ArgList args, StackInfo data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<Dummy>
+ {
+ int paramsCount = MetaDataProvider.Parameters (method).Count + (extraVarargs == null ? 0 : extraVarargs.Count);
+ if (!MetaDataProvider.IsStatic (method)) {
+ if (data.IsThis (paramsCount))
+ this.stack_depth_mirror_for_end_old.AddCallOnThis (pc);
+ ++paramsCount;
+ }
+
+ data = data.Pop (paramsCount);
+ if (MetaDataProvider.IsVoid (MetaDataProvider.ReturnType (method)))
+ return data;
+
+ return data.Push ();
+ }
+
+ public StackInfo CastClass (APC pc, TypeNode type, Dummy dest, Dummy obj, StackInfo data)
+ {
+ return data;
+ }
+
+ public StackInfo CopyObj (APC pc, TypeNode type, Dummy destPtr, Dummy sourcePtr, StackInfo data)
+ {
+ return data.Pop (2);
+ }
+
+ public StackInfo Initobj (APC pc, TypeNode type, Dummy ptr, StackInfo data)
+ {
+ return data.Pop (1);
+ }
+
+ public StackInfo LoadElement (APC pc, TypeNode type, Dummy dest, Dummy array, Dummy index, StackInfo data)
+ {
+ return data.Pop (2).Push ();
+ }
+
+ public StackInfo LoadField (APC pc, Field field, Dummy dest, Dummy obj, StackInfo data)
+ {
+ return data.Pop (1).Push ();
+ }
+
+ public StackInfo LoadFieldAddress (APC pc, Field field, Dummy dest, Dummy obj, StackInfo data)
+ {
+ return data.Pop (1).Push ();
+ }
+
+ public StackInfo LoadLength (APC pc, Dummy dest, Dummy array, StackInfo data)
+ {
+ return data.Pop (1).Push ();
+ }
+
+ public StackInfo LoadStaticField (APC pc, Field field, Dummy dest, StackInfo data)
+ {
+ return data.Push ();
+ }
+
+ public StackInfo LoadStaticFieldAddress (APC pc, Field field, Dummy dest, StackInfo data)
+ {
+ return data.Push ();
+ }
+
+ public StackInfo LoadTypeToken (APC pc, TypeNode type, Dummy dest, StackInfo data)
+ {
+ return data.Push ();
+ }
+
+ public StackInfo LoadFieldToken (APC pc, Field type, Dummy dest, StackInfo data)
+ {
+ return data.Push ();
+ }
+
+ public StackInfo LoadMethodToken (APC pc, Method type, Dummy dest, StackInfo data)
+ {
+ return data.Push ();
+ }
+
+ public StackInfo NewArray<ArgList> (APC pc, TypeNode type, Dummy dest, ArgList lengths, StackInfo data) where ArgList : IIndexable<Dummy>
+ {
+ return data.Pop (lengths.Count).Push ();
+ }
+
+ public StackInfo NewObj<ArgList> (APC pc, Method ctor, Dummy dest, ArgList args, StackInfo data) where ArgList : IIndexable<Dummy>
+ {
+ int paramsCount = MetaDataProvider.Parameters (ctor).Count;
+ return data.Pop (paramsCount).Push ();
+ }
+
+ public StackInfo MkRefAny (APC pc, TypeNode type, Dummy dest, Dummy obj, StackInfo data)
+ {
+ return data;
+ }
+
+ public StackInfo RefAnyType (APC pc, Dummy dest, Dummy source, StackInfo data)
+ {
+ return data.Pop (1).Push ();
+ }
+
+ public StackInfo RefAnyVal (APC pc, TypeNode type, Dummy dest, Dummy source, StackInfo data)
+ {
+ return data.Pop (1).Push ();
+ }
+
+ public StackInfo Rethrow (APC pc, StackInfo data)
+ {
+ return new StackInfo (0, 0);
+ }
+
+ public StackInfo StoreElement (APC pc, TypeNode type, Dummy array, Dummy index, Dummy value, StackInfo data)
+ {
+ return data.Pop (3);
+ }
+
+ public StackInfo StoreField (APC pc, Field field, Dummy obj, Dummy value, StackInfo data)
+ {
+ return data.Pop (2);
+ }
+
+ public StackInfo StoreStaticField (APC pc, Field field, Dummy value, StackInfo data)
+ {
+ return data.Pop (1);
+ }
+
+ public StackInfo Throw (APC pc, Dummy exception, StackInfo data)
+ {
+ return new StackInfo (0, 0);
+ }
+
+ public StackInfo Unbox (APC pc, TypeNode type, Dummy dest, Dummy obj, StackInfo data)
+ {
+ return data.Pop (1).Push ();
+ }
+
+ public StackInfo UnboxAny (APC pc, TypeNode type, Dummy dest, Dummy obj, StackInfo data)
+ {
+ return data.Pop (1).Push ();
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// StackInfo.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.Analysis.StackAnalysis {
+ struct StackInfo {
+ private StackInfo<object> stack;
+
+ public int Depth {
+ get { return this.stack.Depth; }
+ }
+
+ public object this [int offset] {
+ get { return this.stack [offset]; }
+ }
+
+ public StackInfo (int depth, int capacity)
+ {
+ this.stack = new StackInfo<object> (depth, capacity);
+ }
+
+ private StackInfo (StackInfo<object> copy)
+ {
+ this.stack = copy;
+ }
+
+ public StackInfo Pop (int slots)
+ {
+ return new StackInfo (this.stack.Pop (slots));
+ }
+
+ public StackInfo Push ()
+ {
+ this.stack.Push (null);
+ return this;
+ }
+
+ public StackInfo PushThis ()
+ {
+ this.stack.Push (true);
+ return this;
+ }
+
+ public StackInfo Push<T> (T target)
+ {
+ this.stack.Push (target);
+ return this;
+ }
+
+ public void Adjust (int delta)
+ {
+ if (delta == 0)
+ return;
+ if (delta < 0)
+ this.stack.Pop (-delta);
+ for (int i = 0; i < delta; ++i)
+ Push ();
+ }
+
+ public bool IsThis (int offset)
+ {
+ return As<bool> (offset);
+ }
+
+ public bool TryGet<T> (int offset, out T target)
+ {
+ object o = this [offset];
+ if (o is T) {
+ target = (T) o;
+ return true;
+ }
+ target = default(T);
+ return false;
+ }
+
+ private T As<T> (int offset)
+ {
+ T res;
+ TryGetTarget (offset, out res);
+ return res;
+ }
+
+ public StackInfo Clone ()
+ {
+ return new StackInfo (new StackInfo<object> (this.stack));
+ }
+
+ public override string ToString ()
+ {
+ return this.stack.ToString ();
+ }
+
+ public bool TryGetTarget<T> (int offset, out T target)
+ {
+ if (this [offset] is T) {
+ target = (T) this [offset];
+ return true;
+ }
+ target = default(T);
+ return false;
+ }
+ }
+}
--- /dev/null
+//
+// StackInfo`1.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.Analysis.StackAnalysis {
+ struct StackInfo<T> {
+ private readonly T[] stack;
+ private int depth;
+
+ public StackInfo (int depth, int capacity)
+ {
+ this.depth = depth;
+ this.stack = new T[capacity];
+ }
+
+ public StackInfo (StackInfo<T> that)
+ {
+ this.depth = that.depth;
+ this.stack = (T[]) that.stack.Clone ();
+ }
+
+ public int Depth {
+ get { return this.depth; }
+ }
+
+ public T this [int offset] {
+ get {
+ int index = this.depth - 1 - offset;
+ if (index >= 0 && index < this.stack.Length)
+ return this.stack [index];
+ return default(T);
+ }
+ }
+
+ public StackInfo<T> Pop (int slots)
+ {
+ for (int i = this.depth - slots; i < this.depth; ++i) {
+ if (i < this.stack.Length)
+ this.stack [i] = default(T);
+ }
+ this.depth -= slots;
+ return this;
+ }
+
+ public void Push (T info)
+ {
+ int index = this.depth;
+ if (index < this.stack.Length)
+ this.stack [index] = info;
+ ++this.depth;
+ }
+
+ public override string ToString ()
+ {
+ return this.depth.ToString ();
+ }
+ }
+}
--- /dev/null
+//
+// CodeLayer.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataFlowAnalysis;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis {
+ class CodeLayer<Expression, Variable, ContextData, EdgeData>
+ : ICodeLayer<Expression, Variable, ContextData, EdgeData>
+ where ContextData : IMethodContextProvider {
+ private readonly Lazy<ILPrinter<APC>> printer;
+
+ public CodeLayer (IILDecoder<APC, Expression, Variable, ContextData, EdgeData> ilDecoder,
+ IMetaDataProvider metadataDecoder,
+ IContractProvider contractDecoder,
+ Func<Expression, string> expressionToString,
+ Func<Variable, string> variableToString)
+ {
+ ExpressionToString = expressionToString;
+ VariableToString = variableToString;
+ ILDecoder = ilDecoder;
+ MetaDataProvider = metadataDecoder;
+ ContractProvider = contractDecoder;
+
+ this.printer = new Lazy<ILPrinter<APC>> (() => PrinterFactory.Create (ILDecoder, MetaDataProvider, ExpressionToString, VariableToString));
+ }
+
+ public CodeLayer (IILDecoder<APC, Expression, Variable, ContextData, EdgeData> ilDecoder,
+ IMetaDataProvider metadataDecoder,
+ IContractProvider contractDecoder,
+ Func<Expression, string> expressionToString,
+ Func<Variable, string> variableToString, ILPrinter<APC> printer)
+ : this (ilDecoder, metadataDecoder, contractDecoder, expressionToString, variableToString)
+ {
+ this.printer = new Lazy<ILPrinter<APC>> (() => printer);
+ }
+
+ public IILDecoder<APC, Expression, Variable, ContextData, EdgeData> ILDecoder { get; private set; }
+
+ public ILPrinter<APC> Printer
+ {
+ get { return this.printer.Value; }
+ }
+
+ public Func<Expression, string> ExpressionToString { get; private set; }
+
+ public Func<Variable, string> VariableToString { get; private set; }
+
+ public IMetaDataProvider MetaDataProvider { get; private set; }
+ public IContractProvider ContractProvider { get; private set; }
+
+ public Func<AState, IFixPointInfo<APC, AState>> CreateForward<AState> (
+ IAnalysis<APC, AState, IILVisitor<APC, Expression, Variable, AState, AState>, EdgeData> analysis)
+ {
+ ForwardAnalysis<AState, EdgeData> solver = ForwardAnalysis<AState, EdgeData>.Make (ILDecoder, analysis);
+ return (initialState) => {
+ solver.Run (initialState);
+ return solver;
+ };
+ }
+ }
+}
--- /dev/null
+//
+// CodeLayerFactory.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis {
+ static class CodeLayerFactory {
+ public static ICodeLayer<Expression, Variable, ContextData, EdgeConversionData>
+ Create<Expression, Variable, ContextData, EdgeConversionData> (
+ IILDecoder<APC, Expression, Variable, ContextData, EdgeConversionData> ilDecoder,
+ IMetaDataProvider metadataDecoder,
+ IContractProvider contractDecoder, Func<Expression, string> expressionToString, Func<Variable, string> variableToString)
+ where ContextData : IMethodContextProvider
+ {
+ return new CodeLayer<Expression, Variable, ContextData, EdgeConversionData>
+ (ilDecoder, metadataDecoder, contractDecoder, expressionToString, variableToString);
+ }
+
+ public static ICodeLayer<Expression, Variable, ContextData, EdgeConversionData>
+ Create<Expression, Variable, ContextData, EdgeConversionData> (
+ IILDecoder<APC, Expression, Variable, ContextData, EdgeConversionData> ilDecoder,
+ IMetaDataProvider metadataDecoder,
+ IContractProvider contractDecoder, Func<Expression, string> expressionToString, Func<Variable, string> variableToString, ILPrinter<APC> printer)
+ where ContextData : IMethodContextProvider
+ {
+ return new CodeLayer<Expression, Variable, ContextData, EdgeConversionData>
+ (ilDecoder, metadataDecoder, contractDecoder, expressionToString, variableToString, printer);
+ }
+ }
+}
--- /dev/null
+//
+// ICodeLayer.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataFlowAnalysis;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis {
+ interface ICodeLayer<Expression, Variable, ContextData, EdgeData> where ContextData : IMethodContextProvider {
+ IMetaDataProvider MetaDataProvider { get; }
+ IContractProvider ContractProvider { get; }
+ IILDecoder<APC, Expression, Variable, ContextData, EdgeData> ILDecoder { get; }
+
+ ILPrinter<APC> Printer { get; }
+ Func<Expression, string> ExpressionToString { get; }
+ Func<Variable, string> VariableToString { get; }
+
+ Func<AnalysisState, IFixPointInfo<APC, AnalysisState>> CreateForward<AnalysisState> (
+ IAnalysis<APC, AnalysisState, IILVisitor<APC, Expression, Variable, AnalysisState, AnalysisState>, EdgeData> analysis
+ );
+ }
+}
--- /dev/null
+//
+// IExpressionContext.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.Lattices;
+
+namespace Mono.CodeContracts.Static.Analysis {
+ interface IExpressionContext<Expression, Variable> {
+ Expression Refine (APC pc, Variable variable);
+ Variable Unrefine (Expression expression);
+
+ Result Decode<Data, Result, Visitor> (Expression expr, Visitor visitor, Data data)
+ where Visitor : ISymbolicExpressionVisitor<Expression, Expression, Variable, Data, Result>;
+
+ FlatDomain<TypeNode> GetType (Expression expr);
+
+ APC GetPC (Expression pc);
+
+ Expression For (Variable variable);
+
+ bool IsZero (Expression expression);
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// IExpressionContextProvider.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.Analysis {
+ interface IExpressionContextProvider<Expression, Variable>
+ : IValueContextProvider<Variable> {
+ IExpressionContext<Expression, Variable> ExpressionContext { get; }
+ }
+}
--- /dev/null
+//
+// ILPrinter.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+
+namespace Mono.CodeContracts.Static.Analysis {
+ delegate void ILPrinter<Label> (Label label, string prefix, TextWriter tw);
+}
\ No newline at end of file
--- /dev/null
+//
+// IMethodContext.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.ControlFlow;
+
+namespace Mono.CodeContracts.Static.Analysis {
+ interface IMethodContext
+ {
+ Method CurrentMethod { get; }
+ ICFG CFG { get; }
+ IEnumerable<Field> Modifies(Method method);
+ IEnumerable<Method> AffectedGetters(Field field);
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// IMethodContextProvider.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.Analysis {
+ interface IMethodContextProvider {
+ IMethodContext MethodContext { get; }
+ }
+}
--- /dev/null
+//
+// IStackContext.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.ControlFlow;
+
+namespace Mono.CodeContracts.Static.Analysis {
+ interface IStackContext {
+ int StackDepth (APC pc);
+ }
+}
--- /dev/null
+//
+// IStackContextProvider.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.Analysis {
+ interface IStackContextProvider : IMethodContextProvider {
+ IStackContext StackContext { get; }
+ }
+}
--- /dev/null
+//
+// IValueContext.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Lattices;
+
+namespace Mono.CodeContracts.Static.Analysis {
+ interface IValueContext<SymbolicValue> {
+ bool IsZero (APC at, SymbolicValue value);
+ bool TryLocalValue (APC at, Local local, out SymbolicValue sv);
+ bool TryParameterValue (APC at, Parameter p, out SymbolicValue sv);
+ bool IsConstant (APC readAt, SymbolicValue symbol, out TypeNode type, out object constant);
+ FlatDomain<TypeNode> GetType (APC readAt, SymbolicValue symbol);
+ LispList<PathElement> AccessPathList (APC at, SymbolicValue value, bool allowLocal, bool preferLocal);
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// IValueContextProvider.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.Analysis {
+ interface IValueContextProvider<Variable> : IStackContextProvider {
+ IValueContext<Variable> ValueContext { get; }
+ }
+}
--- /dev/null
+//
+// PrinterFactory.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.Analysis {
+ static class PrinterFactory {
+ public static ILPrinter<Label> Create<Label, Source, Dest, Context, EdgeData>
+ (IILDecoder<Label, Source, Dest, Context, EdgeData> ilDecoder,
+ IMetaDataProvider metaDataProvider,
+ Func<Source, string> sourceToString, Func<Dest, string> destToString)
+ {
+ return new Printer<Label, Source, Dest, Context, EdgeData> (ilDecoder, metaDataProvider, sourceToString, destToString).PrintCodeAt;
+ }
+
+ #region Nested type: Printer
+ private class Printer<Label, Source, Dest, Context, EdgeData> : IILVisitor<Label, Source, Dest, TextWriter, Dummy> {
+ private readonly Func<Dest, string> dest_to_string;
+ private readonly IILDecoder<Label, Source, Dest, Context, EdgeData> il_decoder;
+ private readonly IMetaDataProvider meta_data_provider;
+ private readonly Func<Source, string> source_to_string;
+ private string prefix = "";
+
+ public Printer (IILDecoder<Label, Source, Dest, Context, EdgeData> ilDecoder, IMetaDataProvider metaDataProvider,
+ Func<Source, string> sourceToString, Func<Dest, string> destToString)
+ {
+ this.il_decoder = ilDecoder;
+ this.meta_data_provider = metaDataProvider;
+ this.source_to_string = sourceToString;
+ this.dest_to_string = destToString;
+ }
+
+ #region IILVisitor<Label,Source,Dest,TextWriter,Dummy> Members
+ public Dummy Binary (Label pc, BinaryOperator op, Dest dest, Source operand1, Source operand2, TextWriter data)
+ {
+ data.WriteLine ("{0}{1} = {2} {3} {4}", this.prefix, DestName (dest), SourceName (operand1), op.ToString (), SourceName (operand2));
+ return Dummy.Value;
+ }
+
+ public Dummy Isinst (Label pc, TypeNode type, Dest dest, Source obj, TextWriter data)
+ {
+ data.WriteLine ("{0}{2} = isinst {1} {3}", this.prefix, this.meta_data_provider.FullName (type), DestName (dest), SourceName (obj));
+ return Dummy.Value;
+ }
+
+ public Dummy LoadNull (Label pc, Dest dest, TextWriter polarity)
+ {
+ polarity.WriteLine ("{0}{1} = ldnull", this.prefix, DestName (dest));
+ return Dummy.Value;
+ }
+
+ public Dummy LoadConst (Label pc, TypeNode type, object constant, Dest dest, TextWriter data)
+ {
+ data.WriteLine ("{0}{2} = ldc ({3}) '{1}'", this.prefix, constant, DestName (dest), this.meta_data_provider.FullName (type));
+ return Dummy.Value;
+ }
+
+ public Dummy Sizeof (Label pc, TypeNode type, Dest dest, TextWriter data)
+ {
+ data.WriteLine ("{0}{2} = sizeof {1}", this.prefix, this.meta_data_provider.FullName (type), DestName (dest));
+ return Dummy.Value;
+ }
+
+ public Dummy Unary (Label pc, UnaryOperator op, bool unsigned, Dest dest, Source source, TextWriter data)
+ {
+ data.WriteLine ("{0}{3} = {2}{1} {4}", this.prefix, unsigned ? "_un" : null, op, DestName (dest), SourceName (source));
+ return Dummy.Value;
+ }
+
+ public Dummy Entry (Label pc, Method method, TextWriter data)
+ {
+ data.WriteLine ("{0}method_entry {1}", this.prefix, this.meta_data_provider.FullName (method));
+ return Dummy.Value;
+ }
+
+ public Dummy Assume (Label pc, EdgeTag tag, Source condition, TextWriter data)
+ {
+ data.WriteLine ("{0}assume({1}) {2}", this.prefix, tag, SourceName (condition));
+ return Dummy.Value;
+ }
+
+ public Dummy Assert (Label pc, EdgeTag tag, Source condition, TextWriter data)
+ {
+ data.WriteLine ("{0}assert({1}) {2}", this.prefix, tag, SourceName (condition));
+ return Dummy.Value;
+ }
+
+ public Dummy BeginOld (Label pc, Label matchingEnd, TextWriter data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Dummy EndOld (Label pc, Label matchingBegin, TypeNode type, Dest dest, Source source, TextWriter data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Dummy LoadStack (Label pc, int offset, Dest dest, Source source, bool isOld, TextWriter data)
+ {
+ data.WriteLine ("{0}{1} = {4}ldstack.{2} {3}", this.prefix, DestName (dest), offset, SourceName (source), isOld ? "old." : null);
+ return Dummy.Value;
+ }
+
+ public Dummy LoadStackAddress (Label pc, int offset, Dest dest, Source source, TypeNode type, bool isOld, TextWriter data)
+ {
+ data.WriteLine ("{0}{1} = {4}ldstacka.{2} {3}", this.prefix, DestName (dest), offset, SourceName (source), isOld ? "old." : null);
+ return Dummy.Value;
+ }
+
+ public Dummy LoadResult (Label pc, TypeNode type, Dest dest, Source source, TextWriter data)
+ {
+ data.WriteLine ("{0}{1} = ldresult {2}", this.prefix, DestName (dest), SourceName (source));
+ return Dummy.Value;
+ }
+
+ public Dummy Arglist (Label pc, Dest dest, TextWriter data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Dummy Branch (Label pc, Label target, bool leavesExceptionBlock, TextWriter data)
+ {
+ data.WriteLine ("{0}branch", this.prefix);
+ return Dummy.Value;
+ }
+
+ public Dummy BranchCond (Label pc, Label target, BranchOperator bop, Source value1, Source value2, TextWriter data)
+ {
+ data.WriteLine ("{0}br.{1} {2},{3}", this.prefix, bop, SourceName (value1), SourceName (value2));
+ return Dummy.Value;
+ }
+
+ public Dummy BranchTrue (Label pc, Label target, Source cond, TextWriter data)
+ {
+ data.WriteLine ("{0}br.true {1}", this.prefix, SourceName (cond));
+ return Dummy.Value;
+ }
+
+ public Dummy BranchFalse (Label pc, Label target, Source cond, TextWriter data)
+ {
+ data.WriteLine ("{0}br.false {1}", this.prefix, SourceName (cond));
+ return Dummy.Value;
+ }
+
+ public Dummy Break (Label pc, TextWriter data)
+ {
+ data.WriteLine ("{0}break", this.prefix);
+ return Dummy.Value;
+ }
+
+ public Dummy Call<TypeList, ArgList> (Label pc, Method method, bool virt, TypeList extraVarargs, Dest dest, ArgList args, TextWriter data) where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<Source>
+ {
+ data.Write ("{0}{3} = call{2} {1}(", this.prefix, this.meta_data_provider.FullName (method), virt ? "virt" : null, DestName (dest));
+ if (args != null) {
+ for (int i = 0; i < args.Count; i++)
+ data.Write ("{0} ", SourceName (args [i]));
+ }
+ data.WriteLine (")");
+ return Dummy.Value;
+ }
+
+ public Dummy Calli<TypeList, ArgList> (Label pc, TypeNode returnType, TypeList argTypes, bool instance, Dest dest, Source functionPointer, ArgList args, TextWriter data)
+ where TypeList : IIndexable<TypeNode> where ArgList : IIndexable<Source>
+ {
+ data.Write ("{0}{1} = calli {2}(", this.prefix, DestName (dest), SourceName (functionPointer));
+ if (args != null) {
+ for (int i = 0; i < args.Count; i++)
+ data.Write ("{0} ", SourceName (args [i]));
+ }
+ data.WriteLine (")");
+ return Dummy.Value;
+ }
+
+ public Dummy CheckFinite (Label pc, Dest dest, Source source, TextWriter data)
+ {
+ data.WriteLine ("{0}{1} = chfinite {2}", this.prefix, DestName (dest), SourceName (source));
+ return Dummy.Value;
+ }
+
+ public Dummy CopyBlock (Label pc, Source destAddress, Source srcAddress, Source len, TextWriter data)
+ {
+ data.WriteLine ("{0}cpblk {1} {2} {3}", this.prefix, SourceName (destAddress), SourceName (srcAddress), SourceName (len));
+ return Dummy.Value;
+ }
+
+ public Dummy EndFilter (Label pc, Source decision, TextWriter data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Dummy EndFinally (Label pc, TextWriter data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Dummy Jmp (Label pc, Method method, TextWriter data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Dummy LoadArg (Label pc, Parameter argument, bool isOld, Dest dest, TextWriter data)
+ {
+ data.WriteLine ("{0}{2} = {3}ldarg {1}", this.prefix, this.meta_data_provider.Name (argument), DestName (dest), isOld ? "old." : null);
+ return Dummy.Value;
+ }
+
+ public Dummy LoadArgAddress (Label pc, Parameter argument, bool isOld, Dest dest, TextWriter data)
+ {
+ data.WriteLine ("{0}{2} = {3}ldarga {1}", this.prefix, this.meta_data_provider.Name (argument), DestName (dest), isOld ? "old." : null);
+ return Dummy.Value;
+ }
+
+ public Dummy LoadLocal (Label pc, Local local, Dest dest, TextWriter data)
+ {
+ data.WriteLine ("{0}{2} = ldloc {1}", this.prefix, this.meta_data_provider.Name (local), DestName (dest));
+ return Dummy.Value;
+ }
+
+ public Dummy LoadLocalAddress (Label pc, Local local, Dest dest, TextWriter data)
+ {
+ data.WriteLine ("{0}{2} = ldloca {1}", this.prefix, this.meta_data_provider.Name (local), DestName (dest));
+ return Dummy.Value;
+ }
+
+ public Dummy Nop (Label pc, TextWriter data)
+ {
+ data.WriteLine ("{0}nop", this.prefix);
+ return Dummy.Value;
+ }
+
+ public Dummy Pop (Label pc, Source source, TextWriter data)
+ {
+ data.WriteLine ("{0}pop {1}", this.prefix, SourceName (source));
+ return Dummy.Value;
+ }
+
+ public Dummy Return (Label pc, Source source, TextWriter data)
+ {
+ data.WriteLine ("{0}ret {1}", this.prefix, SourceName (source));
+ return Dummy.Value;
+ }
+
+ public Dummy StoreArg (Label pc, Parameter argument, Source source, TextWriter data)
+ {
+ data.WriteLine ("{0}starg {1} {2}", this.prefix, this.meta_data_provider.Name (argument), SourceName (source));
+ return Dummy.Value;
+ }
+
+ public Dummy StoreLocal (Label pc, Local local, Source source, TextWriter data)
+ {
+ data.WriteLine ("{0}stloc {1} {2}", this.prefix, this.meta_data_provider.Name (local), SourceName (source));
+ return Dummy.Value;
+ }
+
+ public Dummy Switch (Label pc, TypeNode type, IEnumerable<Pair<object, Label>> cases, Source value, TextWriter data)
+ {
+ data.WriteLine ("{0}switch {1}", this.prefix, SourceName (value));
+ return Dummy.Value;
+ }
+
+ public Dummy Box (Label pc, TypeNode type, Dest dest, Source source, TextWriter data)
+ {
+ data.WriteLine ("{0}{2} = box {1} {3}", this.prefix, this.meta_data_provider.FullName (type), DestName (dest), SourceName (source));
+ return Dummy.Value;
+ }
+
+ public Dummy ConstrainedCallvirt<TypeList, ArgList> (Label pc, Method method, TypeNode constraint, TypeList extraVarargs, Dest dest, ArgList args, TextWriter data)
+ where TypeList : IIndexable<TypeNode> where ArgList : IIndexable<Source>
+ {
+ data.Write ("{0}{3} = constrained({1}).callvirt {2}(", this.prefix, this.meta_data_provider.FullName (constraint), this.meta_data_provider.FullName (method), DestName (dest));
+ if (args != null) {
+ for (int i = 0; i < args.Count; i++)
+ data.Write ("{0} ", SourceName (args [i]));
+ }
+ data.WriteLine (")");
+ return Dummy.Value;
+ }
+
+ public Dummy CastClass (Label pc, TypeNode type, Dest dest, Source obj, TextWriter data)
+ {
+ data.WriteLine ("{0}{2} = castclass {1} {3}", this.prefix, this.meta_data_provider.FullName (type), DestName (dest), SourceName (obj));
+ return Dummy.Value;
+ }
+
+ public Dummy CopyObj (Label pc, TypeNode type, Source destPtr, Source sourcePtr, TextWriter data)
+ {
+ data.WriteLine ("{0}cpobj {1} {2} {3}", this.prefix, this.meta_data_provider.FullName (type), SourceName (destPtr), SourceName (sourcePtr));
+ return Dummy.Value;
+ }
+
+ public Dummy Initobj (Label pc, TypeNode type, Source ptr, TextWriter data)
+ {
+ data.WriteLine ("{0}initobj {1} {2}", this.prefix, this.meta_data_provider.FullName (type), SourceName (ptr));
+ return Dummy.Value;
+ }
+
+ public Dummy LoadElement (Label pc, TypeNode type, Dest dest, Source array, Source index, TextWriter data)
+ {
+ data.WriteLine ("{0}{2} = ldelem {1} {3}[{4}]", this.prefix, this.meta_data_provider.FullName (type), DestName (dest), SourceName (array), SourceName (index));
+ return Dummy.Value;
+ }
+
+ public Dummy LoadField (Label pc, Field field, Dest dest, Source obj, TextWriter data)
+ {
+ data.WriteLine ("{0}{2} = ldfld {1} {3}", this.prefix, this.meta_data_provider.Name (field), DestName (dest), SourceName (obj));
+ return Dummy.Value;
+ }
+
+ public Dummy LoadFieldAddress (Label pc, Field field, Dest dest, Source obj, TextWriter data)
+ {
+ data.WriteLine ("{0}{2} = ldflda {1} {3}", this.prefix, this.meta_data_provider.Name (field), DestName (dest), SourceName (obj));
+ return Dummy.Value;
+ }
+
+ public Dummy LoadLength (Label pc, Dest dest, Source array, TextWriter data)
+ {
+ data.WriteLine ("{0}{1} = ldlen {2}", this.prefix, DestName (dest), SourceName (array));
+ return Dummy.Value;
+ }
+
+ public Dummy LoadStaticField (Label pc, Field field, Dest dest, TextWriter data)
+ {
+ data.WriteLine ("{0}{2} = ldsfld {1}", this.prefix, this.meta_data_provider.Name (field), DestName (dest));
+ return Dummy.Value;
+ }
+
+ public Dummy LoadStaticFieldAddress (Label pc, Field field, Dest dest, TextWriter data)
+ {
+ data.WriteLine ("{0}{2} = ldsflda {1}", this.prefix, this.meta_data_provider.Name (field), DestName (dest));
+ return Dummy.Value;
+ }
+
+ public Dummy LoadTypeToken (Label pc, TypeNode type, Dest dest, TextWriter data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Dummy LoadFieldToken (Label pc, Field type, Dest dest, TextWriter data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Dummy LoadMethodToken (Label pc, Method type, Dest dest, TextWriter data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Dummy NewArray<ArgList> (Label pc, TypeNode type, Dest dest, ArgList lengths, TextWriter data) where ArgList : IIndexable<Source>
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Dummy NewObj<ArgList> (Label pc, Method ctor, Dest dest, ArgList args, TextWriter data) where ArgList : IIndexable<Source>
+ {
+ data.Write ("{0}{2} = newobj {1}(", this.prefix, this.meta_data_provider.FullName (ctor), DestName (dest));
+ if (args != null) {
+ for (int i = 0; i < args.Count; ++i)
+ data.Write ("{0} ", SourceName (args [i]));
+ }
+
+ data.WriteLine (")");
+ return Dummy.Value;
+ }
+
+ public Dummy MkRefAny (Label pc, TypeNode type, Dest dest, Source obj, TextWriter data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Dummy RefAnyType (Label pc, Dest dest, Source source, TextWriter data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Dummy RefAnyVal (Label pc, TypeNode type, Dest dest, Source source, TextWriter data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Dummy Rethrow (Label pc, TextWriter data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Dummy StoreElement (Label pc, TypeNode type, Source array, Source index, Source value, TextWriter data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Dummy StoreField (Label pc, Field field, Source obj, Source value, TextWriter data)
+ {
+ data.WriteLine ("{0}stfld {1} {2} {3}", this.prefix, this.meta_data_provider.Name (field), SourceName (obj), SourceName (value));
+ return Dummy.Value;
+ }
+
+ public Dummy StoreStaticField (Label pc, Field field, Source value, TextWriter data)
+ {
+ data.WriteLine ("{0}stsfld {1} {2}", this.prefix, this.meta_data_provider.Name (field), SourceName (value));
+ return Dummy.Value;
+ }
+
+ public Dummy Throw (Label pc, Source exception, TextWriter data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Dummy Unbox (Label pc, TypeNode type, Dest dest, Source obj, TextWriter data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Dummy UnboxAny (Label pc, TypeNode type, Dest dest, Source obj, TextWriter data)
+ {
+ throw new NotImplementedException ();
+ }
+ #endregion
+
+ public void PrintCodeAt (Label label, string prefix, TextWriter tw)
+ {
+ this.prefix = prefix;
+ this.il_decoder.ForwardDecode<TextWriter, Dummy, Printer<Label, Source, Dest, Context, EdgeData>> (label, this, tw);
+ }
+
+ private string SourceName (Source src)
+ {
+ return this.source_to_string != null ? this.source_to_string (src) : null;
+ }
+
+ private string DestName (Dest dest)
+ {
+ return this.dest_to_string != null ? this.dest_to_string (dest) : null;
+ }
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// ContractExtractor.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+
+namespace Mono.CodeContracts.Static.ContractExtraction {
+ class ContractExtractor : DefaultNodeVisitor {
+ private readonly AssemblyNode assembly;
+ private readonly ContractNodes contract_nodes;
+ private readonly bool verbose;
+ private readonly Dictionary<Method, Method> visited_methods;
+
+ public ContractExtractor (ContractNodes contractNodes, AssemblyNode assembly)
+ : this (contractNodes, assembly, DebugOptions.Debug)
+ {
+ }
+
+ public ContractExtractor (ContractNodes contractNodes, AssemblyNode assembly, bool verbose)
+ {
+ this.visited_methods = new Dictionary<Method, Method> ();
+ this.contract_nodes = contractNodes;
+ this.assembly = assembly;
+ this.verbose = verbose;
+ }
+
+ public override AssemblyNode VisitAssembly (AssemblyNode node)
+ {
+ if (node == null)
+ return null;
+ if (this.verbose)
+ Console.WriteLine ("Extracting from '{0}'", this.assembly.FullName);
+
+ return base.VisitAssembly (node);
+ }
+
+ public override Method VisitMethod (Method node)
+ {
+ if (node == null)
+ return null;
+
+ if (this.visited_methods.ContainsKey (node))
+ return node;
+
+ this.visited_methods.Add (node, node);
+ node.ContractProvider = ExtractContractsFromMethod;
+
+ return node;
+ }
+
+ public void ExtractContractsFromMethod (Method method)
+ {
+ MethodContract contract = method.MethodContract = new MethodContract (method);
+ List<Requires> preconditions = null;
+ List<Ensures> postconditions = null;
+
+ if (method.IsAbstract)
+ return;
+
+ if (method.Body != null && method.Body.Statements != null) {
+ if (this.verbose)
+ Console.WriteLine (method.FullName);
+
+ ExtractContractsInternal (method, ref preconditions, ref postconditions);
+
+ contract.Requires = preconditions;
+ contract.Ensures = postconditions;
+ }
+ }
+
+ private void ExtractContractsInternal (Method method, ref List<Requires> preconditions, ref List<Ensures> postconditions)
+ {
+ if (method == null)
+ return;
+ if (this.verbose)
+ Console.WriteLine ("Method: " + method.FullName);
+
+ Block body = method.Body;
+ if (body == null || body.Statements == null || body.Statements.Count <= 0)
+ return;
+
+ int lastBlockContainingContract;
+ int lastStatementContainingContract;
+
+ int begin = 0;
+ bool contractsFound = FindLastBlockWithContracts (body.Statements, begin,
+ out lastBlockContainingContract, out lastStatementContainingContract);
+ if (!contractsFound) {
+ if (this.verbose)
+ Console.WriteLine ("\tNo contracts found");
+ return;
+ }
+
+ List<Statement> contractSection = HelperMethods.ExtractContractBlocks (body.Statements, begin, 0,
+ lastBlockContainingContract, lastStatementContainingContract);
+
+ preconditions = new List<Requires> ();
+ postconditions = new List<Ensures> ();
+
+ ExtractPrePostConditionsFromContractSection (contractSection, preconditions, postconditions);
+ }
+
+ private bool ExtractPrePostConditionsFromContractSection (List<Statement> contractSection,
+ List<Requires> preconditions, List<Ensures> postconditions)
+ {
+ List<Statement> blocks = contractSection;
+ int firstBlockIndex = 0;
+ int blocksCount = blocks.Count;
+ int firstStmtIndex = HelperMethods.FindNextRealStatement (((Block) blocks [firstBlockIndex]).Statements, 0);
+
+ bool wasEndContractBlock = false;
+
+ for (int lastBlockIndex = firstBlockIndex; lastBlockIndex < blocksCount; ++lastBlockIndex) {
+ var block = (Block) blocks [lastBlockIndex];
+ if (block == null)
+ continue;
+
+ int cnt = block.Statements == null ? 0 : block.Statements.Count;
+ for (int lastStmtIndex = 0; lastStmtIndex < cnt; ++lastStmtIndex) {
+ Statement s = block.Statements [lastStmtIndex];
+ if (s == null)
+ continue;
+
+ Method calledMethod = HelperMethods.IsMethodCall (s);
+ if (!this.contract_nodes.IsContractMethod (calledMethod))
+ continue;
+
+ if (wasEndContractBlock) {
+ if (DebugOptions.Debug)
+ Console.WriteLine ("Contract call after prior ContractBlock");
+ break;
+ }
+ if (this.contract_nodes.IsEndContractBlock (calledMethod)) {
+ wasEndContractBlock = true;
+ continue;
+ }
+
+ //here we definitely know that s is ExpressionStatement of (MethodCall). see HelperMethods.IsMethodCall(s)
+ var methodCall = ((ExpressionStatement) s).Expression as MethodCall;
+ Expression assertionExpression = methodCall.Arguments [0];
+ Expression expression;
+ if (firstBlockIndex == lastBlockIndex && firstStmtIndex == lastStmtIndex)
+ expression = assertionExpression;
+ else {
+ block.Statements [lastStmtIndex] = new ExpressionStatement (assertionExpression);
+ List<Statement> contractBlocks = HelperMethods.ExtractContractBlocks (blocks, firstBlockIndex, firstStmtIndex,
+ lastBlockIndex, lastStmtIndex);
+ var b = new Block (contractBlocks);
+
+ expression = new BlockExpression (b);
+ }
+
+ MethodContractElement methodContractElement = null;
+ if (this.contract_nodes.IsPlainPrecondition (calledMethod)) {
+ var requires = new Requires (expression);
+
+ methodContractElement = requires;
+ } else if (this.contract_nodes.IsPostCondition (calledMethod))
+ methodContractElement = new Ensures (expression);
+
+ if (methodContractElement == null)
+ throw new InvalidOperationException ("Unrecognized contract method");
+
+ if (methodCall.Arguments.Count > 1) {
+ Expression userMessage = methodCall.Arguments [1];
+ methodContractElement.UserMessage = userMessage;
+ }
+
+ switch (methodContractElement.NodeType) {
+ case NodeType.Requires:
+ var requires = (Requires) methodContractElement;
+ preconditions.Add (requires);
+ break;
+ case NodeType.Ensures:
+ var ensures = (Ensures) methodContractElement;
+ postconditions.Add (ensures);
+ break;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private bool FindLastBlockWithContracts (List<Statement> statements, int beginning,
+ out int lastBlockContainingContract, out int lastStatementContainingContract)
+ {
+ lastBlockContainingContract = -1;
+ lastStatementContainingContract = -1;
+ for (int i = statements.Count - 1; i >= beginning; i--) {
+ var block = statements [i] as Block;
+ if (block == null || block.Statements == null || block.Statements.Count <= 0)
+ continue;
+
+ for (int j = block.Statements.Count - 1; j >= 0; j--) {
+ if (this.contract_nodes.IsContractCall (block.Statements [j]) == null)
+ continue;
+
+ lastBlockContainingContract = i;
+ lastStatementContainingContract = j;
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+}
--- /dev/null
+//
+// ContractNodes.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Reflection;
+using Mono.CodeContracts.Static.AST;
+
+namespace Mono.CodeContracts.Static.ContractExtraction {
+ class ContractNodes {
+ public static readonly string ContractNamespace = "System.Diagnostics.Contracts";
+ public static readonly string ContractClassName = "Contract";
+ public static readonly string RequiresName = "Requires";
+ public static readonly string EnsuresName = "Ensures";
+ public static readonly string AssertName = "Assert";
+ public static readonly string AssumeName = "Assume";
+ public static readonly string EndContractBlockName = "EndContractBlock";
+
+ [RepresentationFor ("Contract.Assert(bool)")]
+ public readonly Method AssertMethod;
+
+ [RepresentationFor ("Contract.Assert(bool, string)")]
+ public readonly Method AssertWithMessageMethod;
+
+ [RepresentationFor ("Contract.Assume(bool)")]
+ public readonly Method AssumeMethod;
+
+ [RepresentationFor ("Contract.Assume(bool, string)")]
+ public readonly Method AssumeWithMessageMethod;
+
+ [RepresentationFor ("System.Diagnostics.Contracts.Contract")]
+ public readonly Class ContractClass;
+
+ [RepresentationFor ("Contract.EndContractBlock()")]
+ public readonly Method EndContractBlock;
+
+ [RepresentationFor ("Contract.Ensures(bool)")]
+ public readonly Method EnsuresMethod;
+
+ [RepresentationFor ("Contract.Ensures(bool, string)")]
+ public readonly Method EnsuresWithMessageMethod;
+
+ [RepresentationFor ("Contract.Requires(bool)")]
+ public readonly Method RequiresMethod;
+
+ [RepresentationFor ("Contract.Requires(bool, string)")]
+ public readonly Method RequiresWithMessageMethod;
+
+ private ContractNodes (AssemblyNode assembly, Action<string> errorHandler)
+ {
+ CoreSystemTypes.ModuleDefinition = assembly.Modules.First ().Definition;
+ if (errorHandler != null)
+ ErrorFound += errorHandler;
+ this.ContractClass = assembly.GetType (ContractNamespace, ContractClassName) as Class;
+ if (this.ContractClass == null)
+ return;
+
+
+ IEnumerable<Method> methods = this.ContractClass.GetMethods (RequiresName, CoreSystemTypes.Instance.TypeBoolean);
+ foreach (Method method in methods) {
+ if (method.GenericParameters == null || method.GenericParameters.Count == 0)
+ this.RequiresMethod = method;
+ }
+
+ if (this.RequiresMethod == null) {
+ this.ContractClass = null;
+ return;
+ }
+
+ methods = this.ContractClass.GetMethods (RequiresName, CoreSystemTypes.Instance.TypeBoolean, CoreSystemTypes.Instance.TypeString);
+ foreach (Method method in methods) {
+ if (method.GenericParameters == null || method.GenericParameters.Count == 0)
+ this.RequiresWithMessageMethod = method;
+ }
+ this.EnsuresMethod = this.ContractClass.GetMethod (EnsuresName, CoreSystemTypes.Instance.TypeBoolean);
+ this.EnsuresWithMessageMethod = this.ContractClass.GetMethod (EnsuresName,
+ CoreSystemTypes.Instance.TypeBoolean, CoreSystemTypes.Instance.TypeString);
+
+ this.AssertMethod = this.ContractClass.GetMethod (AssertName, CoreSystemTypes.Instance.TypeBoolean);
+ this.AssertWithMessageMethod = this.ContractClass.GetMethod (AssertName,
+ CoreSystemTypes.Instance.TypeBoolean, CoreSystemTypes.Instance.TypeString);
+
+ this.AssumeMethod = this.ContractClass.GetMethod (AssumeName, CoreSystemTypes.Instance.TypeBoolean);
+ this.AssumeWithMessageMethod = this.ContractClass.GetMethod (AssumeName,
+ CoreSystemTypes.Instance.TypeBoolean, CoreSystemTypes.Instance.TypeString);
+
+ this.EndContractBlock = this.ContractClass.GetMethod (EndContractBlockName);
+
+ foreach (FieldInfo fieldInfo in typeof (ContractNodes).GetFields ()) {
+ if (fieldInfo.GetValue (this) != null)
+ continue;
+
+ string runtimeName = null;
+ bool isRequired = false;
+ object[] attributes = fieldInfo.GetCustomAttributes (typeof (RepresentationForAttribute), false);
+ foreach (object attribute in attributes) {
+ var representationForAttribute = attribute as RepresentationForAttribute;
+ if (representationForAttribute != null) {
+ runtimeName = representationForAttribute.RuntimeName;
+ isRequired = representationForAttribute.IsRequired;
+ break;
+ }
+ }
+ if (isRequired) {
+ string message = string.Format ("Could not find contract node for '{0}'", fieldInfo.Name);
+ if (runtimeName != null)
+ message = string.Format ("Could not find the method/type '{0}'", runtimeName);
+
+ FireErrorFound (message);
+ ClearFields ();
+ }
+ }
+ }
+
+ public static ContractNodes GetContractNodes (AssemblyNode assembly, Action<string> errorHandler)
+ {
+ var contractNodes = new ContractNodes (assembly, errorHandler);
+ if (contractNodes.ContractClass != null)
+ return contractNodes;
+ return null;
+ }
+
+ private void ClearFields ()
+ {
+ foreach (FieldInfo fieldInfo in typeof (ContractNodes).GetFields ()) {
+ object[] customAttributes = fieldInfo.GetCustomAttributes (typeof (RepresentationForAttribute), false);
+ if (customAttributes.Length == 1)
+ fieldInfo.SetValue (this, null);
+ }
+ }
+
+ public event Action<string> ErrorFound;
+
+ private void FireErrorFound (string message)
+ {
+ if (ErrorFound == null)
+ throw new InvalidOperationException (message);
+
+ ErrorFound (message);
+ }
+
+ public Method IsContractCall (Statement s)
+ {
+ Method m = HelperMethods.IsMethodCall (s);
+ if (IsContractMethod (m))
+ return m;
+
+ return null;
+ }
+
+ public bool IsContractMethod (Method method)
+ {
+ if (method == null)
+ return false;
+ if (IsPlainPrecondition (method) || IsPostCondition (method) || IsEndContractBlock (method))
+ return true;
+
+ return false;
+ }
+
+ public bool IsPostCondition (Method method)
+ {
+ TypeNode genericArgument;
+ return IsContractMethod (EnsuresName, method, out genericArgument) && genericArgument == null;
+ }
+
+ public bool IsPlainPrecondition (Method method)
+ {
+ TypeNode genericArgument;
+ return IsContractMethod (RequiresName, method, out genericArgument);
+ }
+
+ private bool IsContractMethod (string methodName, Method m, out TypeNode genericArgument)
+ {
+ genericArgument = null;
+ if (m == null)
+ return false;
+ if (m.HasGenericParameters) {
+ if (m.GenericParameters == null || m.GenericParameters.Count != 1)
+ return false;
+ genericArgument = m.GenericParameters [0];
+ }
+
+ return m.Name != null && m.Name == methodName &&
+ (m.DeclaringType.Equals (this.ContractClass)
+ || (m.Parameters != null && m.Parameters.Count == 3 && m.DeclaringType != null && m.DeclaringType.Name != ContractClassName));
+ }
+
+ public bool IsEndContractBlock (Method method)
+ {
+ TypeNode dummy;
+ return IsContractMethod (EndContractBlockName, method, out dummy);
+ }
+ }
+}
--- /dev/null
+//
+// GatherLocals.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+
+namespace Mono.CodeContracts.Static.ContractExtraction {
+ class GatherLocals : NodeInspector {
+ public HashSet<Local> Locals = new HashSet<Local> ();
+ private Local exempt_result_local;
+
+ public override void VisitLocal (Local node)
+ {
+ if (!IsLocalExempt (node) && !this.Locals.Contains (node))
+ this.Locals.Add (node);
+ base.VisitLocal (node);
+ }
+
+ public override void VisitAssignmentStatement (AssignmentStatement node)
+ {
+ if (node.Target is Local && IsResultExpression (node.Source))
+ this.exempt_result_local = (Local) node.Target;
+ base.VisitAssignmentStatement (node);
+ }
+
+ private bool IsResultExpression (Expression expression)
+ {
+ var methodCall = expression as MethodCall;
+ if (methodCall == null)
+ return false;
+
+ var memberBinding = methodCall.Callee as MemberBinding;
+ if (memberBinding == null)
+ return false;
+
+ var method = memberBinding.BoundMember as Method;
+ if (method == null)
+ return false;
+
+ return method.HasGenericParameters && method.Name == "Result" && method.DeclaringType != null && method.DeclaringType.Name == "Contract";
+ }
+
+ private bool IsLocalExempt (Local local)
+ {
+ if (local == this.exempt_result_local)
+ return true;
+ bool result = false;
+ if (local.Name != null && !local.Name.StartsWith ("local"))
+ result = true;
+ TypeNode type = local.Type;
+ if (type == null || HelperMethods.IsCompilerGenerated (type) || local.Name == "_preconditionHolds")
+ return true;
+
+ if (result)
+ return LocalNameIsExempt (local.Name);
+
+ return true;
+ }
+
+ private bool LocalNameIsExempt (string name)
+ {
+ return name.StartsWith ("CS$") || name.StartsWith ("VB$");
+ }
+ }
+}
--- /dev/null
+//
+// HelperMethods.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+
+namespace Mono.CodeContracts.Static.ContractExtraction {
+ static class HelperMethods {
+ public static Method IsMethodCall (Statement s)
+ {
+ if (s == null)
+ return null;
+
+ var expressionStatement = s as ExpressionStatement;
+ if (expressionStatement == null)
+ return null;
+
+ var methodCall = expressionStatement.Expression as MethodCall;
+ if (methodCall == null)
+ return null;
+
+ var binding = methodCall.Callee as MemberBinding;
+ if (binding == null)
+ return null;
+
+ return binding.BoundMember as Method;
+ }
+
+ public static Local ExtractPreamble (Method method, ContractNodes contractNodes, Block contractInitializer, out Block postPreamble)
+ {
+ postPreamble = null;
+ return null;
+ }
+
+ public static List<Statement> ExtractContractBlocks (List<Statement> blocks, int firstBlockIndex, int firstStmtIndex, int lastBlockIndex, int lastStmtIndex)
+ {
+ var result = new List<Statement> ();
+ var firstBlock = (Block) blocks [firstBlockIndex];
+ var block = new Block (new List<Statement> ());
+ if (firstBlock != null) {
+ int cnt = firstBlockIndex == lastBlockIndex ? lastStmtIndex + 1 : firstBlock.Statements.Count;
+ for (int i = firstStmtIndex; i < cnt; i++) {
+ Statement stmt = firstBlock.Statements [i];
+ block.Statements.Add (stmt);
+ if (stmt != null)
+ firstBlock.Statements [i] = null;
+ }
+ }
+ result.Add (block);
+ int nextIndex = firstBlockIndex + 1;
+ if (nextIndex > lastBlockIndex)
+ return result;
+ Block newLastBlock = null;
+ int lastFullBlockIndex = lastBlockIndex - 1;
+ var lastBlock = (Block) blocks [lastBlockIndex];
+ if (lastBlock != null && lastStmtIndex == lastBlock.Statements.Count - 1)
+ lastFullBlockIndex = lastBlockIndex;
+ else {
+ newLastBlock = new Block (new List<Statement> ());
+ if (block.Statements != null && block.Statements.Count > 0) {
+ var branch = block.Statements [block.Statements.Count - 1] as Branch;
+ if (branch != null && branch.Target != null && branch.Target == lastBlock)
+ branch.Target = newLastBlock;
+ }
+ }
+
+ for (; nextIndex < lastFullBlockIndex; ++nextIndex) {
+ var curBlock = (Block) blocks [nextIndex];
+ result.Add (curBlock);
+ if (curBlock != null) {
+ blocks [nextIndex] = null;
+ if (newLastBlock != null && curBlock.Statements != null && curBlock.Statements.Count > 0) {
+ var branch = curBlock.Statements [curBlock.Statements.Count - 1] as Branch;
+ if (branch != null && branch.Target != null && branch.Target == lastBlock)
+ branch.Target = newLastBlock;
+ }
+ }
+ }
+
+ if (newLastBlock != null) {
+ for (int i = 0; i < lastStmtIndex + 1; i++) {
+ newLastBlock.Statements.Add (lastBlock.Statements [i]);
+ lastBlock.Statements [i] = null;
+ }
+
+ result.Add (newLastBlock);
+ }
+ return result;
+ }
+
+ public static bool IsCompilerGenerated (TypeNode type)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public static int FindNextRealStatement (List<Statement> stmts, int beginIndex)
+ {
+ if (stmts == null || stmts.Count <= beginIndex)
+ return -1;
+ int index = beginIndex;
+ while (index < stmts.Count && (stmts [index] == null || stmts [index].NodeType == NodeType.Nop))
+ ++index;
+ return index;
+ }
+
+ public static bool IsReferenceAsVisibleAs (Member member, Member asThisMember)
+ {
+ var type = member as TypeNode;
+ if (type != null)
+ return IsTypeAsVisibleAs (type, asThisMember);
+ var method = member as Method;
+ Member member1;
+ if (method != null) {
+ if (method.HasGenericParameters)
+ throw new NotImplementedException ();
+ member1 = method;
+ } else
+ member1 = Unspecialize (member);
+
+ return IsDefinitionAsVisibleAs (member1, asThisMember);
+ }
+
+ private static bool IsDefinitionAsVisibleAs (this Member member, Member asThisMember)
+ {
+ Module memberModule = member.Module;
+ Module asThisMemberModule = asThisMember.Module;
+
+ for (Member mbr = member; mbr != null; mbr = mbr.DeclaringType) {
+ if (!mbr.IsPublic) {
+ bool visible = false;
+ for (Member mbr1 = asThisMember; mbr1 != null; mbr1 = mbr1.DeclaringType) {
+ if (mbr1.IsAssembly) {
+ if ((mbr1.IsPrivate || mbr1.IsAssembly) && memberModule == asThisMemberModule)
+ visible = true;
+ } else if (mbr1.IsFamily) {
+ if (mbr.IsPrivate) {
+ if (IsInsideOf (mbr, mbr1) || IsInsideSubclass (mbr, mbr1.DeclaringType))
+ visible = true;
+ } else if (mbr.IsFamily && (mbr.DeclaringType == mbr1.DeclaringType || IsSubclassOf (mbr.DeclaringType, mbr1.DeclaringType)))
+ visible = true;
+ } else if (mbr1.IsFamilyOrAssembly) {
+ if (mbr.IsPrivate) {
+ if (memberModule == asThisMemberModule || IsInsideSubclass (mbr, mbr1.DeclaringType))
+ visible = true;
+ } else if (mbr.IsAssembly) {
+ if (memberModule == asThisMemberModule)
+ visible = true;
+ } else if (mbr.IsFamily) {
+ if (IsSubclassOf (mbr.DeclaringType, mbr1.DeclaringType))
+ visible = true;
+ } else if (mbr.IsFamilyOrAssembly && memberModule == asThisMemberModule && IsSubclassOf (mbr.DeclaringType, mbr1.DeclaringType))
+ visible = true;
+ } else if (mbr1.IsPrivate && mbr.IsPrivate && IsInsideOf (mbr, mbr1.DeclaringType))
+ visible = true;
+ }
+ if (!visible)
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static bool IsSubclassOf (this TypeNode thisType, TypeNode thatType)
+ {
+ if (thatType == null)
+ return false;
+ return thisType.IsAssignableTo (thatType);
+ }
+
+ private static bool IsInsideSubclass (this Member member, Member thatValue)
+ {
+ var targetType = thatValue as TypeNode;
+ if (targetType == null)
+ return false;
+
+ for (TypeNode declaringType = member.DeclaringType; declaringType != null; declaringType = declaringType.DeclaringType) {
+ if (declaringType.IsAssignableTo (targetType))
+ return true;
+ }
+ return false;
+ }
+
+ private static bool IsInsideOf (this Member thisValue, Member thatValue)
+ {
+ var typeNode = thatValue as TypeNode;
+ if (typeNode == null)
+ return false;
+ for (TypeNode declaringType = thisValue.DeclaringType; declaringType != null; declaringType = declaringType.DeclaringType) {
+ if (declaringType == typeNode)
+ return true;
+ }
+ return false;
+ }
+
+ private static Member Unspecialize (Member member)
+ {
+ return member;
+ }
+
+ private static bool IsTypeAsVisibleAs (this TypeNode type, Member asThisMember)
+ {
+ if (type == null)
+ return true;
+
+ switch (type.NodeType) {
+ case NodeType.Reference:
+ return ((Reference) type).ElementType.IsTypeAsVisibleAs (asThisMember);
+ default:
+ if (type.HasGenericParameters)
+ throw new NotImplementedException ();
+
+ return IsDefinitionAsVisibleAs (type, asThisMember);
+ }
+ }
+
+ public static bool IsVisibleFrom (this TypeNode type, TypeNode from)
+ {
+ TypeNode declaringType = type.DeclaringType;
+ if (declaringType != null) {
+ if (IsContainedIn (from, declaringType) || IsInheritedFrom (from, type))
+ return true;
+ if (type.IsNestedFamily)
+ return IsInheritedFrom (from, declaringType);
+ if (type.IsNestedPublic)
+ return IsVisibleFrom (declaringType, from);
+ if (type.IsNestedInternal) {
+ if (IsInheritedFrom (from, declaringType))
+ return true;
+ if (declaringType.Module == from.Module)
+ return IsVisibleFrom (declaringType, from);
+
+ return false;
+ }
+ if (type.IsNestedFamilyAndAssembly)
+ return from.Module == declaringType.Module && IsInheritedFrom (from, declaringType);
+ if ((type.IsAssembly || type.IsNestedAssembly) && declaringType.Module == from.Module)
+ return IsVisibleFrom (declaringType, from);
+
+ return false;
+ }
+
+ return type.Module == from.Module || type.IsPublic;
+ }
+
+ public static bool IsVisibleFrom (this Member member, TypeNode from)
+ {
+ var type = member as TypeNode;
+ if (type != null)
+ return type.IsVisibleFrom (from);
+
+ TypeNode declaringType = member.DeclaringType;
+ if (from.IsContainedIn (declaringType))
+ return true;
+ if (member.IsPublic)
+ return declaringType.IsVisibleFrom (from);
+ if (member.IsFamily)
+ return from.IsInheritedFrom (declaringType);
+ if (member.IsFamilyAndAssembly)
+ return from.Module == declaringType.Module && from.IsInheritedFrom (declaringType);
+ if (member.IsFamilyOrAssembly) {
+ if (from.IsInheritedFrom (declaringType))
+ return true;
+ if (from.Module == declaringType.Module)
+ return declaringType.IsVisibleFrom (from);
+
+ return false;
+ }
+
+ return member.IsAssembly && declaringType.Module == from.Module && declaringType.IsVisibleFrom (from);
+ }
+
+ public static bool IsInheritedFrom (this TypeNode type, TypeNode from)
+ {
+ TypeNode baseClass;
+ if (type.HasBaseClass (out baseClass)) {
+ if (baseClass == from || baseClass.IsInheritedFrom (from))
+ return true;
+ }
+
+ return false;
+ }
+
+ private static bool HasBaseClass (this TypeNode type, out TypeNode baseClass)
+ {
+ var clazz = type as Class;
+ if (clazz != null && clazz.BaseType != null) {
+ baseClass = clazz.BaseType;
+ return true;
+ }
+
+ baseClass = default(TypeNode);
+ return false;
+ }
+
+ public static bool IsContainedIn (this TypeNode inner, TypeNode outer)
+ {
+ if (inner == outer)
+ return true;
+
+ if (inner.DeclaringType != null)
+ return inner.DeclaringType.IsContainedIn (outer);
+
+ return false;
+ }
+ }
+}
--- /dev/null
+//
+// RepresentationForAttribute.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.ContractExtraction {
+ [AttributeUsage (AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
+ sealed class RepresentationForAttribute : Attribute {
+ public RepresentationForAttribute (string runtimeName)
+ : this (runtimeName, true)
+ {
+ }
+
+ private RepresentationForAttribute (string runtimeName, bool isRequired)
+ {
+ RuntimeName = runtimeName;
+ IsRequired = isRequired;
+ }
+
+ public string RuntimeName { get; private set; }
+ public bool IsRequired { get; private set; }
+ }
+}
--- /dev/null
+//
+// AssumeBlock.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.ControlFlow.Subroutines;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Blocks {
+ class AssumeBlock<Label> : BlockWithLabels<Label> {
+ protected readonly Label BranchLabel;
+ protected readonly EdgeTag Tag;
+
+ public AssumeBlock (SubroutineBase<Label> subroutine, Label label, EdgeTag tag, ref int idGen)
+ : base (subroutine, ref idGen)
+ {
+ this.BranchLabel = label;
+ this.Tag = tag;
+ }
+
+ public override int Count
+ {
+ get { return 1; }
+ }
+
+ public override Result ForwardDecode<Data, Result, Visitor> (APC pc, Visitor visitor, Data data)
+ {
+ if (pc.Index == 0)
+ return visitor.Assume (pc, this.Tag, Dummy.Value, data);
+
+ return visitor.Nop (pc, data);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// BlockBase.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Blocks {
+ abstract class BlockBase : CFGBlock {
+ protected BlockBase (Subroutine subroutine, ref int idGen)
+ : base (subroutine, ref idGen)
+ {
+ }
+
+ public abstract Result ForwardDecode<Data, Result, Visitor> (APC pc, Visitor visitor, Data data)
+ where Visitor : IILVisitor<APC, Dummy, Dummy, Data, Result>;
+ }
+}
--- /dev/null
+//
+// BlockWithLabels.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.ControlFlow.Subroutines;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Blocks {
+ class BlockWithLabels<Label> : BlockBase, IEquatable<BlockWithLabels<Label>> {
+ private readonly List<Label> labels;
+
+ public BlockWithLabels (SubroutineBase<Label> subroutine, ref int idGen)
+ : base (subroutine, ref idGen)
+ {
+ this.labels = new List<Label> ();
+ }
+
+ public override int Count
+ {
+ get { return this.labels.Count; }
+ }
+
+ protected new SubroutineBase<Label> Subroutine
+ {
+ get { return (SubroutineBase<Label>) base.Subroutine; }
+ }
+
+ #region IEquatable<BlockWithLabels<Label>> Members
+ public bool Equals (BlockWithLabels<Label> other)
+ {
+ return this == other;
+ }
+ #endregion
+
+ public override int GetILOffset (APC pc)
+ {
+ Label label;
+ if (TryGetLabel (pc.Index, out label))
+ return Subroutine.GetILOffset (label);
+
+ return 0;
+ }
+
+ public void AddLabel (Label label)
+ {
+ this.labels.Add (label);
+ }
+
+ public bool TryGetLastLabel (out Label label)
+ {
+ if (this.labels.Count > 0) {
+ label = this.labels [this.labels.Count - 1];
+ return true;
+ }
+
+ label = default(Label);
+ return false;
+ }
+
+ public virtual bool TryGetLabel (int index, out Label label)
+ {
+ if (index < this.labels.Count) {
+ label = this.labels [index];
+ return true;
+ }
+
+ label = default(Label);
+ return false;
+ }
+
+ public override string ToString ()
+ {
+ return string.Format ("{0}: {1}", this.Index, GetType ().Name);
+ }
+
+ public override Result ForwardDecode<Data, Result, Visitor> (APC pc, Visitor visitor, Data data)
+ {
+ Label label;
+ if (TryGetLabel (pc.Index, out label))
+ return Subroutine.CodeProvider.Decode<LabelAdapter<Label, Data, Result, Visitor>, Data, Result> (label, new LabelAdapter<Label, Data, Result, Visitor> (visitor, pc), data);
+
+ return visitor.Nop (pc, data);
+ }
+ }
+}
--- /dev/null
+//
+// CatchFilterEntryBlock.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.ControlFlow.Subroutines;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Blocks {
+ class CatchFilterEntryBlock<Label> : BlockWithLabels<Label> {
+ public CatchFilterEntryBlock (SubroutineBase<Label> subroutine, ref int idGen)
+ : base (subroutine, ref idGen)
+ {
+ }
+ }
+}
--- /dev/null
+//
+// EnsuresBlock.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.ControlFlow.Subroutines;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Blocks {
+ class EnsuresBlock<Label> : BlockWithLabels<Label> {
+ private const uint Mask = 0xC0000000u;
+ private const uint BeginOldMask = 0x80000000u;
+ private const uint EndOldMask = 0x40000000u;
+
+ private List<uint> overridingLabels;
+
+ public EnsuresBlock (SubroutineBase<Label> subroutine, ref int idGen)
+ : base (subroutine, ref idGen)
+ {
+ }
+
+ private new EnsuresSubroutine<Label> Subroutine
+ {
+ get { return (EnsuresSubroutine<Label>) base.Subroutine; }
+ }
+
+ public override int Count
+ {
+ get
+ {
+ if (this.overridingLabels != null)
+ return this.overridingLabels.Count;
+ return base.Count;
+ }
+ }
+
+ public bool UsesOverriding
+ {
+ get { return this.overridingLabels != null; }
+ }
+
+ public override bool TryGetLabel (int index, out Label label)
+ {
+ int originalOffset;
+ if (IsOriginal (index, out originalOffset))
+ return base.TryGetLabel (originalOffset, out label);
+ label = default(Label);
+ return false;
+ }
+
+ public Result OriginalForwardDecode<Data, Result, Visitor> (int index, Visitor visitor, Data data)
+ where Visitor : IAggregateVisitor<Label, Data, Result>
+ {
+ Label label;
+ if (base.TryGetLabel (index, out label))
+ return Subroutine.CodeProvider.Decode<Visitor, Data, Result> (label, visitor, data);
+
+ throw new InvalidOperationException ("should not happen");
+ }
+
+ public override Result ForwardDecode<Data, Result, Visitor> (APC pc, Visitor visitor, Data data)
+ {
+ Label label;
+ if (TryGetLabel (pc.Index, out label))
+ return base.ForwardDecode<Data, Result, Visitor> (pc, visitor, data);
+
+ int endOldIndex;
+ if (IsBeginOld (pc.Index, out endOldIndex)) {
+ CFGBlock block = Subroutine.InferredBeginEndBijection (pc);
+ return visitor.BeginOld (pc, new APC (block, endOldIndex, pc.SubroutineContext), data);
+ }
+
+ int beginOldIndex;
+ if (IsEndOld (pc.Index, out beginOldIndex)) {
+ TypeNode endOldType;
+ CFGBlock block = Subroutine.InferredBeginEndBijection (pc, out endOldType);
+ return visitor.EndOld (pc, new APC (block, beginOldIndex, pc.SubroutineContext), endOldType, Dummy.Value, Dummy.Value, data);
+ }
+
+ return visitor.Nop (pc, data);
+ }
+
+ private bool IsEndOld (int index, out int beginOldIndex)
+ {
+ if (this.overridingLabels != null && index < this.overridingLabels.Count && (this.overridingLabels [index] & EndOldMask) != 0) {
+ beginOldIndex = (int) (this.overridingLabels [index] & (EndOldMask - 1));
+ return true;
+ }
+
+ beginOldIndex = 0;
+ return false;
+ }
+
+ private bool IsBeginOld (int index, out int endOldIndex)
+ {
+ if (this.overridingLabels != null && index < this.overridingLabels.Count && (this.overridingLabels [index] & BeginOldMask) != 0) {
+ endOldIndex = (int) (this.overridingLabels [index] & (EndOldMask - 1));
+ return true;
+ }
+
+ endOldIndex = 0;
+ return false;
+ }
+
+ private bool IsOriginal (int index, out int originalOffset)
+ {
+ if (this.overridingLabels == null) {
+ originalOffset = index;
+ return true;
+ }
+ if (index < this.overridingLabels.Count && (this.overridingLabels [index] & Mask) == 0) {
+ originalOffset = (int) (this.overridingLabels [index] & (EndOldMask - 1));
+ return true;
+ }
+
+ originalOffset = 0;
+ return false;
+ }
+
+ public void StartOverridingLabels ()
+ {
+ this.overridingLabels = new List<uint> ();
+ }
+
+ public void BeginOld (int index)
+ {
+ if (this.overridingLabels == null) {
+ StartOverridingLabels ();
+ for (int i = 0; i < index; ++i)
+ this.overridingLabels.Add ((uint) i);
+ }
+ this.overridingLabels.Add (BeginOldMask);
+ }
+
+ public void AddInstruction (int index)
+ {
+ this.overridingLabels.Add ((uint) index);
+ }
+
+ public void EndOld (int index, TypeNode nextEndOldType)
+ {
+ AddInstruction (index);
+ EndOldWithoutInstruction (nextEndOldType);
+ }
+
+ public void EndOldWithoutInstruction (TypeNode nextEndOldType)
+ {
+ int endOldIndex = this.overridingLabels.Count;
+ CFGBlock beginBlock;
+ this.overridingLabels.Add ((uint) (EndOldMask | PatchPriorBeginOld (this, endOldIndex, out beginBlock)));
+ Subroutine.AddInferredOldMap (this.Index, endOldIndex, beginBlock, nextEndOldType);
+ }
+
+ private int PatchPriorBeginOld (CFGBlock endBlock, int endOldIndex, out CFGBlock beginBlock)
+ {
+ for (int i = this == endBlock ? endOldIndex - 2 : Count - 1; i >= 0; i--) {
+ int endOldI;
+ if (IsBeginOld (i, out endOldI)) {
+ this.overridingLabels [i] = BeginOldMask | (uint)endOldIndex;
+ beginBlock = this;
+ Subroutine.AddInferredOldMap (this.Index, i, endBlock, default(TypeNode));
+ return i;
+ }
+ }
+
+ IEnumerator<CFGBlock> enumerator = Subroutine.PredecessorBlocks (this).GetEnumerator ();
+ if (!enumerator.MoveNext ())
+ throw new InvalidOperationException ("missing begin_old");
+ int result = PatchPriorBeginOld (endBlock, endOldIndex, enumerator.Current, out beginBlock);
+ enumerator.MoveNext ();
+ return result;
+ }
+
+ private int PatchPriorBeginOld (CFGBlock endBlock, int endOldIndex, CFGBlock current, out CFGBlock beginBlock)
+ {
+ var ensuresBlock = current as EnsuresBlock<Label>;
+ if (ensuresBlock != null)
+ return ensuresBlock.PatchPriorBeginOld (endBlock, endOldIndex, out beginBlock);
+ IEnumerator<CFGBlock> enumerator = current.Subroutine.PredecessorBlocks (current).GetEnumerator ();
+ if (!enumerator.MoveNext ())
+ throw new InvalidOperationException ("missing begin_old");
+
+ int result = PatchPriorBeginOld (endBlock, endOldIndex, enumerator.Current, out beginBlock);
+ enumerator.MoveNext ();
+ return result;
+ }
+ }
+}
--- /dev/null
+//
+// EntryBlock.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.ControlFlow.Subroutines;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Blocks {
+ class EntryBlock<Label> : EntryExitBlock<Label> {
+ public EntryBlock (SubroutineBase<Label> subroutine, ref int idGen)
+ : base (subroutine, ref idGen)
+ {
+ }
+
+ public override Result ForwardDecode<Data, Result, Visitor> (APC pc, Visitor visitor, Data data)
+ {
+ if (pc.Index != 0 || pc.SubroutineContext != null || !Subroutine.IsMethod)
+ return visitor.Nop (pc, data);
+
+ var methodInfo = Subroutine as IMethodInfo;
+ return visitor.Entry (pc, methodInfo.Method, data);
+ }
+ }
+}
--- /dev/null
+//
+// EntryExitBlock.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.ControlFlow.Subroutines;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Blocks {
+ class EntryExitBlock<Label> : BlockWithLabels<Label> {
+ public EntryExitBlock (SubroutineBase<Label> subroutine, ref int idGen)
+ : base (subroutine, ref idGen)
+ {
+ }
+
+ public override int Count
+ {
+ get { return 1; }
+ }
+ }
+}
--- /dev/null
+//
+// LabelAdapter.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.ControlFlow.Subroutines;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Blocks {
+ struct LabelAdapter<Label, Data, Result, Visitor> :
+ IAggregateVisitor<Label, Data, Result>
+ where Visitor : IILVisitor<APC, Dummy, Dummy, Data, Result> {
+ private readonly APC original_pc;
+ private readonly Visitor visitor;
+
+ public LabelAdapter (Visitor visitor, APC pc)
+ {
+ this.visitor = visitor;
+ this.original_pc = pc;
+ }
+
+ #region IAggregateVisitor<Label,Data,Result> Members
+ public Result Binary (Label pc, BinaryOperator op, Dummy dest, Dummy operand1, Dummy operand2, Data data)
+ {
+ return this.visitor.Binary (ConvertLabel (pc), op, dest, operand1, operand2, data);
+ }
+
+ public Result Isinst (Label pc, TypeNode type, Dummy dest, Dummy obj, Data data)
+ {
+ return this.visitor.Isinst (ConvertLabel (pc), type, dest, obj, data);
+ }
+
+ public Result LoadNull (Label pc, Dummy dest, Data polarity)
+ {
+ return this.visitor.LoadNull (ConvertLabel (pc), dest, polarity);
+ }
+
+ public Result LoadConst (Label pc, TypeNode type, object constant, Dummy dest, Data data)
+ {
+ return this.visitor.LoadConst (ConvertLabel (pc), type, constant, dest, data);
+ }
+
+ public Result Sizeof (Label pc, TypeNode type, Dummy dest, Data data)
+ {
+ return this.visitor.Sizeof (ConvertLabel (pc), type, dest, data);
+ }
+
+ public Result Unary (Label pc, UnaryOperator op, bool unsigned, Dummy dest, Dummy source, Data data)
+ {
+ return this.visitor.Unary (ConvertLabel (pc), op, unsigned, dest, source, data);
+ }
+
+ public Result Arglist (Label pc, Dummy dest, Data data)
+ {
+ return this.visitor.Arglist (ConvertLabel (pc), dest, data);
+ }
+
+ public Result Branch (Label pc, Label target, bool leavesExceptionBlock, Data data)
+ {
+ return this.visitor.Branch (ConvertLabel (pc), ConvertLabel (target), leavesExceptionBlock, data);
+ }
+
+ public Result BranchCond (Label pc, Label target, BranchOperator bop, Dummy value1, Dummy value2, Data data)
+ {
+ return this.visitor.BranchCond (ConvertLabel (pc), ConvertLabel (target), bop, value1, value2, data);
+ }
+
+ public Result BranchTrue (Label pc, Label target, Dummy cond, Data data)
+ {
+ return this.visitor.BranchTrue (ConvertLabel (pc), ConvertLabel (target), cond, data);
+ }
+
+ public Result BranchFalse (Label pc, Label target, Dummy cond, Data data)
+ {
+ return this.visitor.BranchFalse (ConvertLabel (pc), ConvertLabel (target), cond, data);
+ }
+
+ public Result Break (Label pc, Data data)
+ {
+ return this.visitor.Break (ConvertLabel (pc), data);
+ }
+
+ public Result Call<TypeList, ArgList> (Label pc, Method method, bool virt, TypeList extraVarargs, Dummy dest, ArgList args, Data data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<Dummy>
+ {
+ return this.visitor.Call (ConvertLabel (pc), method, virt, extraVarargs, dest, args, data);
+ }
+
+ public Result Calli<TypeList, ArgList> (Label pc, TypeNode returnType, TypeList argTypes, bool instance, Dummy dest, Dummy functionPointer, ArgList args, Data data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<Dummy>
+ {
+ return this.visitor.Calli (ConvertLabel (pc), returnType, argTypes, instance, dest, functionPointer, args, data);
+ }
+
+ public Result CheckFinite (Label pc, Dummy dest, Dummy source, Data data)
+ {
+ return this.visitor.CheckFinite (ConvertLabel (pc), dest, source, data);
+ }
+
+ public Result CopyBlock (Label pc, Dummy destAddress, Dummy srcAddress, Dummy len, Data data)
+ {
+ return this.visitor.CopyBlock (ConvertLabel (pc), destAddress, srcAddress, len, data);
+ }
+
+ public Result EndFilter (Label pc, Dummy decision, Data data)
+ {
+ return this.visitor.EndFilter (ConvertLabel (pc), decision, data);
+ }
+
+ public Result EndFinally (Label pc, Data data)
+ {
+ return this.visitor.EndFinally (ConvertLabel (pc), data);
+ }
+
+ public Result Jmp (Label pc, Method method, Data data)
+ {
+ return this.visitor.Jmp (ConvertLabel (pc), method, data);
+ }
+
+ public Result LoadArg (Label pc, Parameter argument, bool isOld, Dummy dest, Data data)
+ {
+ return this.visitor.LoadArg (ConvertLabel (pc), argument, isOld, dest, data);
+ }
+
+ public Result LoadArgAddress (Label pc, Parameter argument, bool isOld, Dummy dest, Data data)
+ {
+ return this.visitor.LoadArgAddress (ConvertLabel (pc), argument, isOld, dest, data);
+ }
+
+ public Result LoadLocal (Label pc, Local local, Dummy dest, Data data)
+ {
+ return this.visitor.LoadLocal (ConvertLabel (pc), local, dest, data);
+ }
+
+ public Result LoadLocalAddress (Label pc, Local local, Dummy dest, Data data)
+ {
+ return this.visitor.LoadLocalAddress (ConvertLabel (pc), local, dest, data);
+ }
+
+ public Result Nop (Label pc, Data data)
+ {
+ return this.visitor.Nop (ConvertLabel (pc), data);
+ }
+
+ public Result Pop (Label pc, Dummy source, Data data)
+ {
+ return this.visitor.Pop (ConvertLabel (pc), source, data);
+ }
+
+ public Result Return (Label pc, Dummy source, Data data)
+ {
+ return this.visitor.Return (ConvertLabel (pc), source, data);
+ }
+
+ public Result StoreArg (Label pc, Parameter argument, Dummy source, Data data)
+ {
+ return this.visitor.StoreArg (ConvertLabel (pc), argument, source, data);
+ }
+
+ public Result StoreLocal (Label pc, Local local, Dummy source, Data data)
+ {
+ return this.visitor.StoreLocal (ConvertLabel (pc), local, source, data);
+ }
+
+ public Result Switch (Label pc, TypeNode type, IEnumerable<Pair<object, Label>> cases, Dummy value, Data data)
+ {
+ return this.visitor.Nop (ConvertLabel (pc), data);
+ }
+
+ public Result Box (Label pc, TypeNode type, Dummy dest, Dummy source, Data data)
+ {
+ return this.visitor.Box (ConvertLabel (pc), type, dest, source, data);
+ }
+
+ public Result ConstrainedCallvirt<TypeList, ArgList> (Label pc, Method method, TypeNode constraint, TypeList extraVarargs, Dummy dest, ArgList args, Data data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<Dummy>
+ {
+ return this.visitor.ConstrainedCallvirt (ConvertLabel (pc), method, constraint, extraVarargs, dest, args, data);
+ }
+
+ public Result CastClass (Label pc, TypeNode type, Dummy dest, Dummy obj, Data data)
+ {
+ return this.visitor.CastClass (ConvertLabel (pc), type, dest, obj, data);
+ }
+
+ public Result CopyObj (Label pc, TypeNode type, Dummy destPtr, Dummy sourcePtr, Data data)
+ {
+ return this.visitor.CopyObj (ConvertLabel (pc), type, destPtr, sourcePtr, data);
+ }
+
+ public Result Initobj (Label pc, TypeNode type, Dummy ptr, Data data)
+ {
+ return this.visitor.Initobj (ConvertLabel (pc), type, ptr, data);
+ }
+
+ public Result LoadElement (Label pc, TypeNode type, Dummy dest, Dummy array, Dummy index, Data data)
+ {
+ return this.visitor.LoadElement (ConvertLabel (pc), type, dest, array, index, data);
+ }
+
+ public Result LoadField (Label pc, Field field, Dummy dest, Dummy obj, Data data)
+ {
+ return this.visitor.LoadField (ConvertLabel (pc), field, dest, obj, data);
+ }
+
+ public Result LoadFieldAddress (Label pc, Field field, Dummy dest, Dummy obj, Data data)
+ {
+ return this.visitor.LoadFieldAddress (ConvertLabel (pc), field, dest, obj, data);
+ }
+
+ public Result LoadLength (Label pc, Dummy dest, Dummy array, Data data)
+ {
+ return this.visitor.LoadLength (ConvertLabel (pc), dest, array, data);
+ }
+
+ public Result LoadStaticField (Label pc, Field field, Dummy dest, Data data)
+ {
+ return this.visitor.LoadStaticField (ConvertLabel (pc), field, dest, data);
+ }
+
+ public Result LoadStaticFieldAddress (Label pc, Field field, Dummy dest, Data data)
+ {
+ return this.visitor.LoadStaticFieldAddress (ConvertLabel (pc), field, dest, data);
+ }
+
+ public Result LoadTypeToken (Label pc, TypeNode type, Dummy dest, Data data)
+ {
+ return this.visitor.LoadTypeToken (ConvertLabel (pc), type, dest, data);
+ }
+
+ public Result LoadFieldToken (Label pc, Field type, Dummy dest, Data data)
+ {
+ return this.visitor.LoadFieldToken (ConvertLabel (pc), type, dest, data);
+ }
+
+ public Result LoadMethodToken (Label pc, Method type, Dummy dest, Data data)
+ {
+ return this.visitor.LoadMethodToken (ConvertLabel (pc), type, dest, data);
+ }
+
+ public Result NewArray<ArgList> (Label pc, TypeNode type, Dummy dest, ArgList lengths, Data data) where ArgList : IIndexable<Dummy>
+ {
+ return this.visitor.NewArray (ConvertLabel (pc), type, dest, lengths, data);
+ }
+
+ public Result NewObj<ArgList> (Label pc, Method ctor, Dummy dest, ArgList args, Data data) where ArgList : IIndexable<Dummy>
+ {
+ return this.visitor.NewObj (ConvertLabel (pc), ctor, dest, args, data);
+ }
+
+ public Result MkRefAny (Label pc, TypeNode type, Dummy dest, Dummy obj, Data data)
+ {
+ return this.visitor.MkRefAny (ConvertLabel (pc), type, dest, obj, data);
+ }
+
+ public Result RefAnyType (Label pc, Dummy dest, Dummy source, Data data)
+ {
+ return this.visitor.RefAnyType (ConvertLabel (pc), dest, source, data);
+ }
+
+ public Result RefAnyVal (Label pc, TypeNode type, Dummy dest, Dummy source, Data data)
+ {
+ return this.visitor.RefAnyVal (ConvertLabel (pc), type, dest, source, data);
+ }
+
+ public Result Rethrow (Label pc, Data data)
+ {
+ return this.visitor.Rethrow (ConvertLabel (pc), data);
+ }
+
+ public Result StoreElement (Label pc, TypeNode type, Dummy array, Dummy index, Dummy value, Data data)
+ {
+ return this.visitor.StoreElement (ConvertLabel (pc), type, array, index, value, data);
+ }
+
+ public Result StoreField (Label pc, Field field, Dummy obj, Dummy value, Data data)
+ {
+ return this.visitor.StoreField (ConvertLabel (pc), field, obj, value, data);
+ }
+
+ public Result StoreStaticField (Label pc, Field field, Dummy value, Data data)
+ {
+ return this.visitor.StoreStaticField (ConvertLabel (pc), field, value, data);
+ }
+
+ public Result Throw (Label pc, Dummy exception, Data data)
+ {
+ return this.visitor.Throw (ConvertLabel (pc), exception, data);
+ }
+
+ public Result Unbox (Label pc, TypeNode type, Dummy dest, Dummy obj, Data data)
+ {
+ return this.visitor.Unbox (ConvertLabel (pc), type, dest, obj, data);
+ }
+
+ public Result UnboxAny (Label pc, TypeNode type, Dummy dest, Dummy obj, Data data)
+ {
+ return this.visitor.UnboxAny (ConvertLabel (pc), type, dest, obj, data);
+ }
+
+ public Result Aggregate (Label pc, Label aggregateStart, bool canBeTargetOfBranch, Data data)
+ {
+ return this.visitor.Nop (ConvertLabel (pc), data);
+ }
+
+ public Result Entry (Label pc, Method method, Data data)
+ {
+ return this.visitor.Entry (ConvertLabel (pc), method, data);
+ }
+
+ public Result Assume (Label pc, EdgeTag tag, Dummy condition, Data data)
+ {
+ return this.visitor.Assume (ConvertLabel (pc), tag, condition, data);
+ }
+
+ public Result Assert (Label pc, EdgeTag tag, Dummy condition, Data data)
+ {
+ return this.visitor.Assert (ConvertLabel (pc), tag, condition, data);
+ }
+
+ public Result BeginOld (Label pc, Label matchingEnd, Data data)
+ {
+ if (this.original_pc.InsideOldManifestation)
+ return this.visitor.Nop (ConvertLabel (pc), data);
+
+ return this.visitor.BeginOld (ConvertLabel (pc), ConvertMatchingEndLabel (matchingEnd), data);
+ }
+
+ public Result EndOld (Label pc, Label matchingBegin, TypeNode type, Dummy dest, Dummy source, Data data)
+ {
+ return this.visitor.EndOld (ConvertLabel (pc), ConvertMatchingBeginLabel (matchingBegin), type, dest, source, data);
+ }
+
+ public Result LoadStack (Label pc, int offset, Dummy dest, Dummy source, bool isOld, Data data)
+ {
+ return this.visitor.LoadStack (ConvertLabel (pc), offset, dest, source, isOld, data);
+ }
+
+ public Result LoadStackAddress (Label pc, int offset, Dummy dest, Dummy source, TypeNode type, bool isOld, Data data)
+ {
+ return this.visitor.LoadStackAddress (ConvertLabel (pc), offset, dest, source, type, isOld, data);
+ }
+
+ public Result LoadResult (Label pc, TypeNode type, Dummy dest, Dummy source, Data data)
+ {
+ return this.visitor.LoadResult (ConvertLabel (pc), type, dest, source, data);
+ }
+ #endregion
+
+ private APC ConvertLabel (Label pc)
+ {
+ return this.original_pc;
+ }
+
+ private APC ConvertMatchingEndLabel (Label matchingEnd)
+ {
+ return ((OldValueSubroutine<Label>) this.original_pc.Block.Subroutine).EndOldAPC (this.original_pc.SubroutineContext);
+ }
+
+ private APC ConvertMatchingBeginLabel (Label matchingBegin)
+ {
+ return ((OldValueSubroutine<Label>) this.original_pc.Block.Subroutine).BeginOldAPC (this.original_pc.SubroutineContext);
+ }
+ }
+}
--- /dev/null
+//
+// MethodCallBlock.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.ControlFlow.Subroutines;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Blocks {
+ class MethodCallBlock<Label> : BlockWithLabels<Label> {
+ public MethodCallBlock (Method calledMethod, SubroutineBase<Label> subroutine, ref int idGen, int parametersCount, bool isVirtual)
+ : base (subroutine, ref idGen)
+ {
+ CalledMethod = calledMethod;
+ ParameterCount = parametersCount;
+ IsVirtual = isVirtual;
+ }
+
+ public Method CalledMethod { get; private set; }
+ public bool IsVirtual { get; private set; }
+ public int ParameterCount { get; private set; }
+
+ public virtual bool IsNewObj
+ {
+ get { return false; }
+ }
+
+ public override bool IsMethodCallBlock<TMethod> (out TMethod calledMethod, out bool isNewObj, out bool isVirtual)
+ {
+ calledMethod = default (TMethod);
+ isNewObj = false;
+ isVirtual = false;
+
+ if (!(CalledMethod is TMethod))
+ return false;
+
+ calledMethod = (TMethod) (object) CalledMethod;
+ isNewObj = IsNewObj;
+ isVirtual = IsVirtual;
+
+ return true;
+ }
+ }
+}
--- /dev/null
+//
+// NewObjCallBlock.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.ControlFlow.Subroutines;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Blocks {
+ class NewObjCallBlock<Label> : MethodCallBlock<Label> {
+ public NewObjCallBlock (Method calledMethod, int parametersCount, SubroutineBase<Label> subroutine, ref int idGen)
+ : base (calledMethod, subroutine, ref idGen, parametersCount, false)
+ {
+ }
+
+ public override bool IsNewObj
+ {
+ get { return true; }
+ }
+ }
+}
--- /dev/null
+//
+// BlockBuilder.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.ControlFlow.Blocks;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders {
+ class BlockBuilder<Label> : ILVisitorBase<Label, Dummy, Dummy, BlockWithLabels<Label>, bool>,
+ IAggregateVisitor<Label, BlockWithLabels<Label>, bool> {
+ private readonly SubroutineBuilder<Label> builder;
+ private BlockWithLabels<Label> current_block;
+
+ private BlockBuilder (SubroutineBuilder<Label> builder)
+ {
+ this.builder = builder;
+ }
+
+ private SubroutineBase<Label> CurrentSubroutine
+ {
+ get { return this.builder.CurrentSubroutine; }
+ }
+
+ #region IAggregateVisitor<Label,BlockWithLabels<Label>,bool> Members
+ public override bool Branch (Label pc, Label target, bool leavesExceptionBlock, BlockWithLabels<Label> currentBlock)
+ {
+ currentBlock.AddLabel (pc);
+ CurrentSubroutine.AddSuccessor (currentBlock, EdgeTag.Branch, CurrentSubroutine.GetTargetBlock (target));
+
+ return true;
+ }
+
+ public override bool BranchCond (Label pc, Label target, BranchOperator bop, Dummy value1, Dummy value2, BlockWithLabels<Label> currentBlock)
+ {
+ return HandleConditionalBranch (pc, target, true, currentBlock);
+ }
+
+ public override bool BranchFalse (Label pc, Label target, Dummy cond, BlockWithLabels<Label> currentBlock)
+ {
+ return HandleConditionalBranch (pc, target, false, currentBlock);
+ }
+
+ public override bool BranchTrue (Label pc, Label target, Dummy cond, BlockWithLabels<Label> currentBlock)
+ {
+ return HandleConditionalBranch (pc, target, true, currentBlock);
+ }
+
+ public override bool Throw (Label pc, Dummy exception, BlockWithLabels<Label> currentBlock)
+ {
+ currentBlock.AddLabel (pc);
+ return true;
+ }
+
+ public override bool Rethrow (Label pc, BlockWithLabels<Label> currentBlock)
+ {
+ currentBlock.AddLabel (pc);
+ return true;
+ }
+
+ public override bool EndFinally (Label pc, BlockWithLabels<Label> currentBlock)
+ {
+ currentBlock.AddLabel (pc);
+ CurrentSubroutine.AddSuccessor (currentBlock, EdgeTag.EndSubroutine, CurrentSubroutine.Exit);
+ return true;
+ }
+
+ public override bool Return (Label pc, Dummy source, BlockWithLabels<Label> currentBlock)
+ {
+ currentBlock.AddLabel (pc);
+ CurrentSubroutine.AddSuccessor (currentBlock, EdgeTag.Return, CurrentSubroutine.Exit);
+ CurrentSubroutine.AddReturnBlock (currentBlock);
+
+ return true;
+ }
+
+ public override bool Nop (Label pc, BlockWithLabels<Label> currentBlock)
+ {
+ return false;
+ }
+
+ public override bool LoadField (Label pc, Field field, Dummy dest, Dummy obj, BlockWithLabels<Label> data)
+ {
+ if (CurrentSubroutine.IsMethod) {
+ var methodInfo = (IMethodInfo) CurrentSubroutine;
+ Property property;
+ if (this.builder.MetaDataProvider.IsPropertyGetter (methodInfo.Method, out property))
+ this.builder.SubroutineFacade.AddReads (methodInfo.Method, field);
+ }
+ this.current_block.AddLabel (pc);
+ return false;
+ }
+
+ public override bool StoreField (Label pc, Field field, Dummy obj, Dummy value, BlockWithLabels<Label> data)
+ {
+ if (CurrentSubroutine.IsMethod) {
+ var methodInfo = (IMethodInfo) CurrentSubroutine;
+ Property property;
+ if (this.builder.MetaDataProvider.IsPropertySetter (methodInfo.Method, out property))
+ this.builder.SubroutineFacade.AddReads (methodInfo.Method, field);
+ }
+ this.current_block.AddLabel (pc);
+ return false;
+ }
+
+ public override bool EndOld (Label pc, Label matchingBegin, TypeNode type, Dummy dest, Dummy source, BlockWithLabels<Label> data)
+ {
+ this.current_block.AddLabel (pc);
+ CurrentSubroutine.AddSuccessor (this.current_block, EdgeTag.EndOld, CurrentSubroutine.Exit);
+ return false;
+ }
+
+ public bool Aggregate (Label pc, Label aggregateStart, bool canBeTargetOfBranch, BlockWithLabels<Label> data)
+ {
+ TraceAggregateSequentally (aggregateStart);
+ return false;
+ }
+ #endregion
+
+ public static BlockWithLabels<Label> BuildBlocks (Label entry, SubroutineBuilder<Label> subroutineBuilder)
+ {
+ var blockBuilder = new BlockBuilder<Label> (subroutineBuilder);
+ blockBuilder.TraceAggregateSequentally (entry);
+ if (blockBuilder.current_block == null)
+ return null;
+
+ SubroutineBase<Label> subroutine = blockBuilder.CurrentSubroutine;
+
+ subroutine.AddSuccessor (blockBuilder.current_block, EdgeTag.FallThroughReturn, subroutine.Exit);
+ subroutine.AddReturnBlock (blockBuilder.current_block);
+
+ return blockBuilder.current_block;
+ }
+
+ private void TraceAggregateSequentally (Label currentLabel)
+ {
+ do {
+ if (this.builder.IsBlockStart (currentLabel))
+ this.current_block = this.builder.RecordInformationForNewBlock (currentLabel, this.current_block);
+ if (this.builder.CodeProvider.Decode<BlockBuilder<Label>, BlockWithLabels<Label>, bool> (currentLabel, this, this.current_block))
+ this.current_block = null;
+ } while (this.builder.CodeProvider.Next (currentLabel, out currentLabel));
+ }
+
+ public override bool DefaultVisit (Label pc, BlockWithLabels<Label> currentBlock)
+ {
+ currentBlock.AddLabel (pc);
+ return false;
+ }
+
+ private bool HandleConditionalBranch (Label pc, Label target, bool isTrueBranch, BlockWithLabels<Label> currentBlock)
+ {
+ currentBlock.AddLabel (pc);
+ EdgeTag trueTag = isTrueBranch ? EdgeTag.True : EdgeTag.False;
+ EdgeTag falseTag = isTrueBranch ? EdgeTag.False : EdgeTag.True;
+
+ AssumeBlock<Label> trueBlock = CurrentSubroutine.NewAssumeBlock (pc, trueTag);
+ this.builder.RecordInformationSameAsOtherBlock (trueBlock, this.current_block);
+ CurrentSubroutine.AddSuccessor (currentBlock, trueTag, trueBlock);
+ CurrentSubroutine.AddSuccessor (trueBlock, EdgeTag.FallThrough, CurrentSubroutine.GetTargetBlock (target));
+
+ AssumeBlock<Label> falseBlock = CurrentSubroutine.NewAssumeBlock (pc, falseTag);
+ this.builder.RecordInformationSameAsOtherBlock (falseBlock, this.current_block);
+ CurrentSubroutine.AddSuccessor (currentBlock, falseTag, falseBlock);
+ this.current_block = falseBlock;
+
+ return false;
+ }
+ }
+}
--- /dev/null
+//
+// BlockStartGatherer.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders {
+ class BlockStartGatherer<Label> : ILVisitorBase<Label, Dummy, Dummy, Dummy, bool>,
+ IAggregateVisitor<Label, Dummy, bool> {
+ private readonly SubroutineBuilder<Label> parent;
+
+ public BlockStartGatherer (SubroutineBuilder<Label> parent)
+ {
+ this.parent = parent;
+ }
+
+ #region IAggregateVisitor<Label,Dummy,bool> Members
+ public override bool Branch (Label pc, Label target, bool leavesExceptionBlock, Dummy data)
+ {
+ AddTargetLabel (target);
+ return true;
+ }
+
+ public override bool BranchCond (Label pc, Label target, BranchOperator bop, Dummy value1, Dummy value2, Dummy data)
+ {
+ AddTargetLabel (target);
+ return true;
+ }
+
+ public override bool BranchFalse (Label pc, Label target, Dummy cond, Dummy data)
+ {
+ AddTargetLabel (target);
+ return true;
+ }
+
+ public override bool BranchTrue (Label pc, Label target, Dummy cond, Dummy data)
+ {
+ AddTargetLabel (target);
+ return true;
+ }
+
+ public override bool EndFinally (Label pc, Dummy data)
+ {
+ return true;
+ }
+
+ public override bool Return (Label pc, Dummy source, Dummy data)
+ {
+ return true;
+ }
+
+ public override bool Rethrow (Label pc, Dummy data)
+ {
+ return true;
+ }
+
+ public override bool Throw (Label pc, Dummy exception, Dummy data)
+ {
+ return true;
+ }
+
+ public override bool Call<TypeList, ArgList> (Label pc, Method method, bool virt, TypeList extraVarargs, Dummy dest, ArgList args, Dummy data)
+ {
+ return CallHelper (pc, method, false, virt);
+ }
+
+ public override bool ConstrainedCallvirt<TypeList, ArgList> (Label pc, Method method, TypeNode constraint, TypeList extraVarargs, Dummy dest, ArgList args, Dummy data)
+ {
+ return CallHelper (pc, method, false, true);
+ }
+
+ public override bool NewObj<ArgList> (Label pc, Method ctor, Dummy dest, ArgList args, Dummy data)
+ {
+ return CallHelper (pc, ctor, true, false);
+ }
+
+ public override bool BeginOld (Label pc, Label matchingEnd, Dummy data)
+ {
+ AddTargetLabel (pc);
+ this.parent.BeginOldHook (pc);
+ return false;
+ }
+
+ public override bool EndOld (Label pc, Label matchingBegin, TypeNode type, Dummy dest, Dummy source, Dummy data)
+ {
+ this.parent.EndOldHook (pc);
+ return true;
+ }
+
+ public bool Aggregate (Label pc, Label aggregateStart, bool canBeTargetOfBranch, Dummy data)
+ {
+ return TraceAggregateSequentally (aggregateStart);
+ }
+ #endregion
+
+ public override bool DefaultVisit (Label pc, Dummy data)
+ {
+ return false;
+ }
+
+ private bool CallHelper (Label pc, Method method, bool isNewObj, bool isVirtual)
+ {
+ AddBlockStart (pc);
+ if (isNewObj)
+ this.parent.AddNewObjSite (pc, method);
+ else
+ this.parent.AddMethodCallSite (pc, new Pair<Method, bool> (method, isVirtual));
+
+ return true;
+ }
+
+ public bool TraceAggregateSequentally (Label current)
+ {
+ bool isCurrentBranches;
+ bool isCurrentHasSuccessor;
+ do {
+ ICodeProvider<Label> codeProvider = this.parent.CodeProvider;
+ isCurrentBranches = codeProvider.Decode<BlockStartGatherer<Label>, Dummy, bool> (current, this, Dummy.Value);
+ isCurrentHasSuccessor = codeProvider.Next (current, out current);
+ if (isCurrentBranches && isCurrentHasSuccessor)
+ AddBlockStart (current);
+ } while (isCurrentHasSuccessor);
+
+ return isCurrentBranches;
+ }
+
+ private void AddBlockStart (Label target)
+ {
+ this.parent.AddBlockStart (target);
+ }
+
+ private void AddTargetLabel (Label target)
+ {
+ this.parent.AddTargetLabel (target);
+ }
+ }
+}
--- /dev/null
+//
+// EnsuresFactory.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders {
+ class EnsuresFactory : SubroutineFactory<Method, Pair<Method, IImmutableSet<Subroutine>>> {
+ public EnsuresFactory (SubroutineFacade subroutineFacade) : base (subroutineFacade)
+ {
+ }
+
+ #region Overrides of SubroutineFactory<Method,Pair<Method,IImmutableSet<Subroutine>>>
+ protected override Subroutine BuildNewSubroutine (Method method)
+ {
+ if (ContractProvider != null) {
+ IImmutableSet<Subroutine> inheritedEnsures = GetInheritedEnsures (method);
+ if (ContractProvider.HasEnsures (method))
+ return ContractProvider.AccessEnsures (method, this, new Pair<Method, IImmutableSet<Subroutine>> (method, inheritedEnsures));
+ if (inheritedEnsures.Count > 0) {
+ if (inheritedEnsures.Count > 1)
+ return new EnsuresSubroutine<Dummy> (this.SubroutineFacade, method, inheritedEnsures);
+ return inheritedEnsures.Any;
+ }
+ }
+ return new EnsuresSubroutine<Dummy> (this.SubroutineFacade, method, null);
+ }
+
+ private IImmutableSet<Subroutine> GetInheritedEnsures (Method method)
+ {
+ IImmutableSet<Subroutine> result = ImmutableSet<Subroutine>.Empty ();
+ if (MetaDataProvider.IsVirtual (method) && ContractProvider.CanInheritContracts (method)) {
+ foreach (Method implementedMethod in MetaDataProvider.OverridenAndImplementedMethods (method)) {
+ Subroutine subroutine = Get (MetaDataProvider.Unspecialized (implementedMethod));
+ if (subroutine != null)
+ result = result.Add (subroutine);
+ }
+ }
+ return result;
+ }
+
+ protected override Subroutine Factory<Label> (SimpleSubroutineBuilder<Label> builder, Label entry, Pair<Method, IImmutableSet<Subroutine>> data)
+ {
+ return new EnsuresSubroutine<Label> (this.SubroutineFacade, data.Key, builder, entry, data.Value);
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// RequiresFactory.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders {
+ class RequiresFactory : SubroutineFactory<Method, Pair<Method, IImmutableSet<Subroutine>>> {
+ public RequiresFactory (SubroutineFacade subroutineFacade)
+ : base (subroutineFacade)
+ {
+ }
+
+ #region Overrides of SubroutineFactory<Method,Pair<Method,IImmutableSet<Subroutine>>>
+ protected override Subroutine BuildNewSubroutine (Method method)
+ {
+ if (ContractProvider != null) {
+ IImmutableSet<Subroutine> inheritedRequires = GetInheritedRequires (method);
+ if (ContractProvider.HasRequires (method))
+ return ContractProvider.AccessRequires (method, this, new Pair<Method, IImmutableSet<Subroutine>> (method, inheritedRequires));
+ if (inheritedRequires.Count > 0) {
+ if (inheritedRequires.Count == 1)
+ return inheritedRequires.Any;
+
+ return new RequiresSubroutine<Dummy> (this.SubroutineFacade, method, inheritedRequires);
+ }
+ }
+ return null;
+ }
+
+ private IImmutableSet<Subroutine> GetInheritedRequires (Method method)
+ {
+ IImmutableSet<Subroutine> result = ImmutableSet<Subroutine>.Empty ();
+
+ if (MetaDataProvider.IsVirtual (method) && ContractProvider.CanInheritContracts (method)) {
+ Method rootMethod;
+ if (MetaDataProvider.TryGetRootMethod (method, out rootMethod)) {
+ Subroutine sub = Get (MetaDataProvider.Unspecialized (method));
+ if (sub != null)
+ result = result.Add (sub);
+ }
+ foreach (Method implMethod in MetaDataProvider.ImplementedMethods (method)) {
+ Subroutine sub = Get (MetaDataProvider.Unspecialized (implMethod));
+ if (sub != null)
+ result = result.Add (sub);
+ }
+ }
+
+ return result;
+ }
+
+ protected override Subroutine Factory<Label> (SimpleSubroutineBuilder<Label> builder, Label entry, Pair<Method, IImmutableSet<Subroutine>> data)
+ {
+ return new RequiresSubroutine<Label> (this.SubroutineFacade, data.Key, builder, entry, data.Value);
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// SimpleSubroutineBuilder.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using Mono.CodeContracts.Static.ControlFlow.Blocks;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders {
+ class SimpleSubroutineBuilder<Label> : SubroutineBuilder<Label> {
+ private readonly HashSet<Label> beginOldStart = new HashSet<Label> ();
+ private readonly HashSet<Label> endOldStart = new HashSet<Label> ();
+
+ private BlockWithLabels<Label> block_prior_to_old;
+ private OldValueSubroutine<Label> current_old_subroutine;
+ private SubroutineBase<Label> current_subroutine;
+
+ public SimpleSubroutineBuilder (ICodeProvider<Label> codeProvider,
+ SubroutineFacade subroutineFacade,
+ Label entry)
+ : base (codeProvider, subroutineFacade, entry)
+ {
+ Initialize (entry);
+ }
+
+ public override SubroutineBase<Label> CurrentSubroutine
+ {
+ get
+ {
+ if (this.current_old_subroutine != null)
+ return this.current_old_subroutine;
+ return this.current_subroutine;
+ }
+ }
+
+ public BlockWithLabels<Label> BuildBlocks (Label entry, SubroutineBase<Label> subroutine)
+ {
+ this.current_subroutine = subroutine;
+
+ return base.BuildBlocks (entry);
+ }
+
+ public override BlockWithLabels<Label> RecordInformationForNewBlock (Label currentLabel, BlockWithLabels<Label> previousBlock)
+ {
+ Label label;
+ if (previousBlock != null && previousBlock.TryGetLastLabel (out label) && this.endOldStart.Contains (label)) {
+ OldValueSubroutine<Label> oldValueSubroutine = this.current_old_subroutine;
+ oldValueSubroutine.Commit (previousBlock);
+ this.current_old_subroutine = null;
+ BlockWithLabels<Label> result = base.RecordInformationForNewBlock (currentLabel, this.block_prior_to_old);
+ CurrentSubroutine.AddEdgeSubroutine (this.block_prior_to_old, result, oldValueSubroutine, EdgeTag.Old);
+ return result;
+ }
+
+ if (!this.beginOldStart.Contains (currentLabel))
+ return base.RecordInformationForNewBlock (currentLabel, previousBlock);
+ this.current_old_subroutine = new OldValueSubroutine<Label> (this.SubroutineFacade,
+ ((MethodContractSubroutine<Label>) this.current_subroutine).Method,
+ this, currentLabel);
+ this.block_prior_to_old = previousBlock;
+ BlockWithLabels<Label> newBlock = base.RecordInformationForNewBlock (currentLabel, null);
+ this.current_old_subroutine.RegisterBeginBlock (newBlock);
+ return newBlock;
+ }
+
+ public override void BeginOldHook (Label label)
+ {
+ this.beginOldStart.Add (label);
+ }
+
+ public override void EndOldHook (Label label)
+ {
+ this.endOldStart.Add (label);
+ }
+ }
+}
--- /dev/null
+//
+// SubroutineBuilder.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.ControlFlow.Blocks;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders {
+ abstract class SubroutineBuilder<Label> {
+ public readonly SubroutineFacade SubroutineFacade;
+
+ private readonly Dictionary<Label, Pair<Method, bool>> labels_for_call_sites = new Dictionary<Label, Pair<Method, bool>> ();
+ private readonly Dictionary<Label, Method> labels_for_new_obj_sites = new Dictionary<Label, Method> ();
+ private readonly HashSet<Label> labels_starting_blocks = new HashSet<Label> ();
+ private readonly HashSet<Label> target_labels = new HashSet<Label> ();
+
+ protected SubroutineBuilder (ICodeProvider<Label> codeProvider,
+ SubroutineFacade subroutineFacade,
+ Label entry)
+ {
+ this.SubroutineFacade = subroutineFacade;
+ CodeProvider = codeProvider;
+ AddTargetLabel (entry);
+ }
+
+ public ICodeProvider<Label> CodeProvider { get; private set; }
+ public abstract SubroutineBase<Label> CurrentSubroutine { get; }
+
+ public IMetaDataProvider MetaDataProvider
+ {
+ get { return this.SubroutineFacade.MetaDataProvider; }
+ }
+
+ protected IContractProvider ContractProvider
+ {
+ get { return this.SubroutineFacade.ContractProvider; }
+ }
+
+ public void AddTargetLabel (Label target)
+ {
+ AddBlockStart (target);
+ this.target_labels.Add (target);
+ }
+
+ public void AddBlockStart (Label target)
+ {
+ this.labels_starting_blocks.Add (target);
+ }
+
+ protected void Initialize (Label entry)
+ {
+ new BlockStartGatherer<Label> (this).TraceAggregateSequentally (entry);
+ }
+
+ public bool IsBlockStart (Label label)
+ {
+ return this.labels_starting_blocks.Contains (label);
+ }
+
+ public bool IsTargetLabel (Label label)
+ {
+ return this.target_labels.Contains (label);
+ }
+
+ public bool IsMethodCallSite (Label label, out Pair<Method, bool> methodVirtPair)
+ {
+ return this.labels_for_call_sites.TryGetValue (label, out methodVirtPair);
+ }
+
+ public bool IsNewObjSite (Label label, out Method constructor)
+ {
+ return this.labels_for_new_obj_sites.TryGetValue (label, out constructor);
+ }
+
+ protected BlockWithLabels<Label> BuildBlocks (Label entry)
+ {
+ return BlockBuilder<Label>.BuildBlocks (entry, this);
+ }
+
+ public virtual void RecordInformationSameAsOtherBlock (BlockWithLabels<Label> newBlock, BlockWithLabels<Label> currentBlock)
+ {
+ }
+
+ public virtual BlockWithLabels<Label> RecordInformationForNewBlock (Label currentLabel, BlockWithLabels<Label> previousBlock)
+ {
+ BlockWithLabels<Label> block = CurrentSubroutine.GetBlock (currentLabel);
+ if (previousBlock != null) {
+ BlockWithLabels<Label> newBlock = block;
+ BlockWithLabels<Label> prevBlock = previousBlock;
+ if (block is MethodCallBlock<Label> && previousBlock is MethodCallBlock<Label>) {
+ BlockWithLabels<Label> ab = CurrentSubroutine.NewBlock ();
+ RecordInformationSameAsOtherBlock (ab, previousBlock);
+ newBlock = ab;
+ prevBlock = ab;
+ CurrentSubroutine.AddSuccessor (previousBlock, EdgeTag.FallThrough, ab);
+ CurrentSubroutine.AddSuccessor (ab, EdgeTag.FallThrough, block);
+ } else
+ CurrentSubroutine.AddSuccessor (previousBlock, EdgeTag.FallThrough, block);
+
+ InsertPostConditionEdges (previousBlock, newBlock);
+ InsertPreConditionEdges (prevBlock, block);
+ }
+ return block;
+ }
+
+ protected void InsertPreConditionEdges (BlockWithLabels<Label> previousBlock, BlockWithLabels<Label> newBlock)
+ {
+ var methodCallBlock = newBlock as MethodCallBlock<Label>;
+ if (methodCallBlock == null || CurrentSubroutine.IsContract || CurrentSubroutine.IsOldValue)
+ return;
+
+ if (CurrentSubroutine.IsMethod) {
+ var methodInfo = CurrentSubroutine as IMethodInfo;
+ Property property;
+ if (methodInfo != null && MetaDataProvider.IsConstructor (methodInfo.Method)
+ && MetaDataProvider.IsPropertySetter (methodCallBlock.CalledMethod, out property)
+ && MetaDataProvider.IsAutoPropertyMember (methodCallBlock.CalledMethod))
+ return;
+ }
+
+ EdgeTag callTag = methodCallBlock.IsNewObj ? EdgeTag.BeforeNewObj : EdgeTag.BeforeCall;
+ Subroutine requires = this.SubroutineFacade.GetRequires (methodCallBlock.CalledMethod);
+
+ CurrentSubroutine.AddEdgeSubroutine (previousBlock, newBlock, requires, callTag);
+ }
+
+ protected void InsertPostConditionEdges (BlockWithLabels<Label> previousBlock, BlockWithLabels<Label> newBlock)
+ {
+ var methodCallBlock = previousBlock as MethodCallBlock<Label>;
+ if (methodCallBlock == null)
+ return;
+
+ if (CurrentSubroutine.IsMethod) {
+ var methodInfo = CurrentSubroutine as IMethodInfo;
+ Property property;
+ if (methodInfo != null && MetaDataProvider.IsConstructor (methodInfo.Method)
+ && MetaDataProvider.IsPropertyGetter (methodCallBlock.CalledMethod, out property)
+ && MetaDataProvider.IsAutoPropertyMember (methodCallBlock.CalledMethod))
+ return;
+ }
+
+ EdgeTag callTag = methodCallBlock.IsNewObj ? EdgeTag.AfterNewObj : EdgeTag.AfterCall;
+ Subroutine ensures = this.SubroutineFacade.GetEnsures (methodCallBlock.CalledMethod);
+
+ CurrentSubroutine.AddEdgeSubroutine (previousBlock, newBlock, ensures, callTag);
+ }
+
+ public virtual void BeginOldHook (Label label)
+ {
+ }
+
+ public virtual void EndOldHook (Label label)
+ {
+ }
+
+ public void AddMethodCallSite (Label pc, Pair<Method, bool> methodVirtPair)
+ {
+ this.labels_for_call_sites [pc] = methodVirtPair;
+ }
+
+ public void AddNewObjSite (Label pc, Method method)
+ {
+ this.labels_for_new_obj_sites [pc] = method;
+ }
+ }
+}
--- /dev/null
+//
+// SubroutineFactory.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders {
+ abstract class SubroutineFactory<Key, Data> : ICodeConsumer<Data, Subroutine> {
+ protected readonly SubroutineFacade SubroutineFacade;
+ private readonly Dictionary<Key, Subroutine> cache = new Dictionary<Key, Subroutine> ();
+
+ protected SubroutineFactory (SubroutineFacade subroutineFacade)
+ {
+ this.SubroutineFacade = subroutineFacade;
+ }
+
+ protected IContractProvider ContractProvider
+ {
+ get { return this.SubroutineFacade.ContractProvider; }
+ }
+
+ protected IMetaDataProvider MetaDataProvider
+ {
+ get { return this.SubroutineFacade.MetaDataProvider; }
+ }
+
+ #region ICodeConsumer<Data,Subroutine> Members
+ public Subroutine Accept<Label> (ICodeProvider<Label> codeProvider, Label entryPoint, Data data)
+ {
+ return Factory (new SimpleSubroutineBuilder<Label> (codeProvider, this.SubroutineFacade, entryPoint), entryPoint, data);
+ }
+ #endregion
+
+ public Subroutine Get (Key key)
+ {
+ if (this.cache.ContainsKey (key))
+ return this.cache [key];
+
+ Subroutine sub = BuildNewSubroutine (key);
+ this.cache.Add (key, sub);
+ if (sub != null)
+ sub.Initialize ();
+ return sub;
+ }
+
+ protected abstract Subroutine BuildNewSubroutine (Key key);
+ protected abstract Subroutine Factory<Label> (SimpleSubroutineBuilder<Label> builder, Label entry, Data data);
+ }
+}
--- /dev/null
+//
+// SubroutineWithHandlersBuilder.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.ControlFlow.Blocks;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders {
+ class SubroutineWithHandlersBuilder<Label, Handler> : SubroutineBuilder<Label> {
+ private readonly Dictionary<Label, Handler> handler_starting_at = new Dictionary<Label, Handler> ();
+ private readonly Method method;
+ private readonly Dictionary<Label, Queue<Handler>> subroutine_handler_end_list = new Dictionary<Label, Queue<Handler>> ();
+ private readonly Dictionary<Label, Queue<Handler>> try_end_list = new Dictionary<Label, Queue<Handler>> ();
+ private readonly Dictionary<Label, Stack<Handler>> try_start_list = new Dictionary<Label, Stack<Handler>> ();
+ private LispList<SubroutineWithHandlers<Label, Handler>> subroutine_stack;
+
+ public SubroutineWithHandlersBuilder (IMethodCodeProvider<Label, Handler> codeProvider,
+ SubroutineFacade subroutineFacade,
+ Method method,
+ Label entry)
+ : base (codeProvider, subroutineFacade, entry)
+ {
+ this.method = method;
+ ComputeTryBlockStartAndEndInfo (this.method);
+ Initialize (entry);
+ }
+
+ private new IMethodCodeProvider<Label, Handler> CodeProvider
+ {
+ get { return (IMethodCodeProvider<Label, Handler>) base.CodeProvider; }
+ }
+
+ protected SubroutineWithHandlers<Label, Handler> CurrentSubroutineWithHandlers
+ {
+ get { return this.subroutine_stack.Head; }
+ }
+
+ private LispList<Handler> CurrentProtectingHanlders
+ {
+ get { return CurrentSubroutineWithHandlers.CurrentProtectingHandlers; }
+ set { CurrentSubroutineWithHandlers.CurrentProtectingHandlers = value; }
+ }
+
+ public override SubroutineBase<Label> CurrentSubroutine
+ {
+ get { return this.subroutine_stack.Head; }
+ }
+
+ private void ComputeTryBlockStartAndEndInfo (Method method)
+ {
+ foreach (Handler handler in CodeProvider.GetTryBlocks (method)) {
+ if (CodeProvider.IsFilterHandler (handler))
+ AddTargetLabel (CodeProvider.FilterExpressionStart (handler));
+ AddTargetLabel (CodeProvider.HandlerStart (handler));
+ AddTargetLabel (CodeProvider.HandlerEnd (handler));
+ AddTryStart (handler);
+ AddTryEnd (handler);
+ AddHandlerEnd (handler);
+ this.handler_starting_at.Add (CodeProvider.HandlerStart (handler), handler);
+ }
+ }
+
+ private void AddHandlerEnd (Handler handler)
+ {
+ if (!IsFaultOrFinally (handler))
+ return;
+
+ Label handlerEnd = CodeProvider.HandlerEnd (handler);
+ Queue<Handler> queue;
+ this.subroutine_handler_end_list.TryGetValue (handlerEnd, out queue);
+ if (queue == null) {
+ queue = new Queue<Handler> ();
+ this.subroutine_handler_end_list [handlerEnd] = queue;
+ }
+ queue.Enqueue (handler);
+ AddTargetLabel (handlerEnd);
+ }
+
+ private void AddTryEnd (Handler handler)
+ {
+ Label tryEnd = CodeProvider.TryEnd (handler);
+ Queue<Handler> queue;
+ this.try_end_list.TryGetValue (tryEnd, out queue);
+ if (queue == null) {
+ queue = new Queue<Handler> ();
+ this.try_end_list [tryEnd] = queue;
+ }
+ queue.Enqueue (handler);
+ AddTargetLabel (tryEnd);
+ }
+
+ private void AddTryStart (Handler handler)
+ {
+ Label tryStart = CodeProvider.TryStart (handler);
+ Stack<Handler> stack;
+ this.try_start_list.TryGetValue (tryStart, out stack);
+ if (stack == null) {
+ stack = new Stack<Handler> ();
+ this.try_start_list [tryStart] = stack;
+ }
+ stack.Push (handler);
+ AddTargetLabel (tryStart);
+ }
+
+ public CFGBlock BuildBlocks (Label entry, SubroutineWithHandlers<Label, Handler> subroutine)
+ {
+ this.subroutine_stack = LispList<SubroutineWithHandlers<Label, Handler>>.Cons (subroutine, null);
+ return base.BuildBlocks (entry);
+ }
+
+ public override void RecordInformationSameAsOtherBlock (BlockWithLabels<Label> newBlock, BlockWithLabels<Label> currentBlock)
+ {
+ LispList<Handler> list;
+ if (!CurrentSubroutineWithHandlers.ProtectingHandlers.TryGetValue (currentBlock, out list))
+ return;
+ CurrentSubroutineWithHandlers.ProtectingHandlers.Add (newBlock, list);
+ }
+
+ public override BlockWithLabels<Label> RecordInformationForNewBlock (Label currentLabel, BlockWithLabels<Label> previousBlock)
+ {
+ BlockWithLabels<Label> result = null;
+ Queue<Handler> handlerEnd = GetHandlerEnd (currentLabel);
+ if (handlerEnd != null) {
+ foreach (Handler handler in handlerEnd) {
+ this.subroutine_stack.Head.Commit ();
+ this.subroutine_stack = this.subroutine_stack.Tail;
+ previousBlock = null;
+ }
+ }
+ Queue<Handler> tryEnd = GetTryEnd (currentLabel);
+ if (tryEnd != null) {
+ foreach (Handler handler in tryEnd) {
+ if (!Equals (handler, CurrentProtectingHanlders.Head))
+ throw new InvalidOperationException ("wrong handler");
+ CurrentProtectingHanlders = CurrentProtectingHanlders.Tail;
+ }
+ }
+ Handler handler1;
+ if (IsHandlerStart (currentLabel, out handler1)) {
+ if (IsFaultOrFinally (handler1)) {
+ SubroutineWithHandlers<Label, Handler> sub = !CodeProvider.IsFaultHandler (handler1)
+ ? new FinallySubroutine<Label, Handler> (this.SubroutineFacade, currentLabel, this)
+ : (FaultFinallySubroutineBase<Label, Handler>) new FaultSubroutine<Label, Handler> (this.SubroutineFacade, currentLabel, this);
+ CurrentSubroutineWithHandlers.FaultFinallySubroutines.Add (handler1, sub);
+ this.subroutine_stack = this.subroutine_stack.Cons (sub);
+ previousBlock = null;
+ } else
+ result = CurrentSubroutineWithHandlers.CreateCatchFilterHeader (handler1, currentLabel);
+ }
+ if (result == null)
+ result = base.RecordInformationForNewBlock (currentLabel, previousBlock);
+ Stack<Handler> tryStart = GetTryStart (currentLabel);
+ if (tryStart != null) {
+ foreach (Handler handler in tryStart)
+ CurrentProtectingHanlders = CurrentProtectingHanlders.Cons (handler);
+ }
+
+ CurrentSubroutineWithHandlers.ProtectingHandlers.Add (result, CurrentProtectingHanlders);
+ return result;
+ }
+
+ private bool IsFaultOrFinally (Handler handler)
+ {
+ return CodeProvider.IsFaultHandler (handler) || CodeProvider.IsFinallyHandler (handler);
+ }
+
+ private bool IsHandlerStart (Label currentLabel, out Handler handler)
+ {
+ return this.handler_starting_at.TryGetValue (currentLabel, out handler);
+ }
+
+ private Stack<Handler> GetTryStart (Label currentLabel)
+ {
+ Stack<Handler> queue;
+ this.try_start_list.TryGetValue (currentLabel, out queue);
+ return queue;
+ }
+
+ private Queue<Handler> GetTryEnd (Label currentLabel)
+ {
+ Queue<Handler> queue;
+ this.try_end_list.TryGetValue (currentLabel, out queue);
+ return queue;
+ }
+
+ private Queue<Handler> GetHandlerEnd (Label currentLabel)
+ {
+ Queue<Handler> queue;
+ this.subroutine_handler_end_list.TryGetValue (currentLabel, out queue);
+ return queue;
+ }
+ }
+}
--- /dev/null
+//
+// EnsuresSubroutine.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.ControlFlow.Blocks;
+using Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Subroutines {
+ sealed class EnsuresSubroutine<Label> : MethodContractSubroutine<Label>, IEquatable<EnsuresSubroutine<Label>> {
+ private readonly Dictionary<int, Pair<CFGBlock, TypeNode>> inferred_old_label_reverse_map;
+
+ public EnsuresSubroutine (SubroutineFacade subroutineFacade,
+ Method method, IImmutableSet<Subroutine> inherited) : base (subroutineFacade, method)
+ {
+ this.inferred_old_label_reverse_map = new Dictionary<int, Pair<CFGBlock, TypeNode>> ();
+ AddSuccessor (Entry, EdgeTag.Entry, Exit);
+ AddBaseEnsures (Entry, Exit, inherited);
+ Commit ();
+ }
+
+ public EnsuresSubroutine (SubroutineFacade subroutineFacade,
+ Method method,
+ SimpleSubroutineBuilder<Label> builder, Label startLabel, IImmutableSet<Subroutine> inherited)
+ : base (subroutineFacade, method, builder, startLabel)
+ {
+ this.inferred_old_label_reverse_map = new Dictionary<int, Pair<CFGBlock, TypeNode>> ();
+ AddBaseEnsures (Entry, GetTargetBlock (startLabel), inherited);
+ }
+
+ public override SubroutineKind Kind
+ {
+ get { return SubroutineKind.Ensures; }
+ }
+
+ public override bool IsEnsures
+ {
+ get { return true; }
+ }
+
+ public override bool IsContract
+ {
+ get { return true; }
+ }
+
+ #region IEquatable<EnsuresSubroutine<Label>> Members
+ public bool Equals (EnsuresSubroutine<Label> other)
+ {
+ return Id == other.Id;
+ }
+ #endregion
+
+ private void AddBaseEnsures (CFGBlock from, CFGBlock to, IImmutableSet<Subroutine> inherited)
+ {
+ if (inherited == null)
+ return;
+ foreach (Subroutine subroutine in inherited.Elements)
+ AddEdgeSubroutine (from, to, subroutine, EdgeTag.Inherited);
+ }
+
+ public override void Initialize ()
+ {
+ if (Builder == null)
+ return;
+ Builder.BuildBlocks (this.StartLabel, this);
+ Commit ();
+ Builder = null;
+ }
+
+ public override BlockWithLabels<Label> NewBlock ()
+ {
+ return new EnsuresBlock<Label> (this, ref this.BlockIdGenerator);
+ }
+
+ public override void Commit ()
+ {
+ base.Commit ();
+
+ var visitor = new OldScanStateMachine<Label> (this);
+ EnsuresBlock<Label> priorBlock = null;
+
+ foreach (CFGBlock block in Blocks) {
+ var ensuresBlock = block as EnsuresBlock<Label>;
+ if (ensuresBlock != null) {
+ priorBlock = ensuresBlock;
+ int count = ensuresBlock.Count;
+ visitor.StartBlock (ensuresBlock);
+
+ for (int i = 0; i < count; i++) {
+ if (ensuresBlock.OriginalForwardDecode<int, Boolean, OldScanStateMachine<Label>> (i, visitor, i))
+ ensuresBlock.AddInstruction (i);
+ }
+ } else
+ visitor.HandlePotentialCallBlock (block as MethodCallBlock<Label>, priorBlock);
+ foreach (CFGBlock succ in SuccessorBlocks (block))
+ visitor.SetStartState (succ);
+ }
+ }
+
+ public void AddInferredOldMap (int blockIndex, int instructionIndex, CFGBlock otherBlock, TypeNode endOldType)
+ {
+ this.inferred_old_label_reverse_map.Add (OverlayInstructionKey (blockIndex, instructionIndex), new Pair<CFGBlock, TypeNode> (otherBlock, endOldType));
+ }
+
+ private static int OverlayInstructionKey (int blockIndex, int instructionIndex)
+ {
+ return (instructionIndex << 16) + blockIndex;
+ }
+
+ public CFGBlock InferredBeginEndBijection (APC pc)
+ {
+ TypeNode endOldType;
+ return InferredBeginEndBijection (pc, out endOldType);
+ }
+
+ public CFGBlock InferredBeginEndBijection (APC pc, out TypeNode endOldType)
+ {
+ Pair<CFGBlock, TypeNode> pair;
+ if (!this.inferred_old_label_reverse_map.TryGetValue (OverlayInstructionKey (pc.Block.Index, pc.Index), out pair))
+ throw new InvalidOperationException ("Fatal bug in ensures CFG begin/end old map");
+ endOldType = pair.Value;
+ return pair.Key;
+ }
+ }
+}
--- /dev/null
+//
+// FaultFinallySubroutineBase.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Subroutines {
+ abstract class FaultFinallySubroutineBase<Label, Handler> : SubroutineWithHandlers<Label, Handler> {
+ protected FaultFinallySubroutineBase (SubroutineFacade subroutineFacade, Label startLabel, SubroutineBuilder<Label> builder)
+ : base (subroutineFacade, startLabel, builder)
+ {
+ }
+
+ public override bool HasContextDependentStackDepth
+ {
+ get { return false; }
+ }
+
+ public override bool IsFaultFinally
+ {
+ get { return true; }
+ }
+
+ public override void Initialize ()
+ {
+ }
+ }
+}
--- /dev/null
+//
+// FaultSubroutine.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Subroutines {
+ class FaultSubroutine<Label, Handler> : FaultFinallySubroutineBase<Label, Handler> {
+ public FaultSubroutine (SubroutineFacade subroutineFacade, Label startLabel,
+ SubroutineBuilder<Label> builder) : base (subroutineFacade, startLabel, builder)
+ {
+ }
+
+ public override SubroutineKind Kind
+ {
+ get { return SubroutineKind.Fault; }
+ }
+ }
+}
--- /dev/null
+//
+// FinallySubroutine.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Subroutines {
+ class FinallySubroutine<Label, Handler> : FaultFinallySubroutineBase<Label, Handler> {
+ public FinallySubroutine (SubroutineFacade subroutineFacade, Label startLabel, SubroutineBuilder<Label> builder)
+ : base (subroutineFacade, startLabel, builder)
+ {
+ }
+
+ public override SubroutineKind Kind
+ {
+ get { return SubroutineKind.Finally; }
+ }
+ }
+}
--- /dev/null
+//
+// MethodContractSubroutine.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Subroutines {
+ abstract class MethodContractSubroutine<Label> : SubroutineBase<Label>, IMethodInfo {
+ private readonly Method method;
+
+ protected MethodContractSubroutine (SubroutineFacade subroutineFacade,
+ Method method) : base (subroutineFacade)
+ {
+ this.method = method;
+ }
+
+ protected MethodContractSubroutine (SubroutineFacade subroutineFacade,
+ Method method,
+ SimpleSubroutineBuilder<Label> builder,
+ Label startLabel) : base (subroutineFacade, startLabel, builder)
+ {
+ this.method = method;
+ }
+
+ protected new SimpleSubroutineBuilder<Label> Builder
+ {
+ get { return (SimpleSubroutineBuilder<Label>) base.Builder; }
+ set { base.Builder = value; }
+ }
+
+ #region IMethodInfo Members
+ public Method Method
+ {
+ get { return this.method; }
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// MethodSubroutine.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.ControlFlow.Blocks;
+using Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Subroutines {
+ class MethodSubroutine<Label, Handler> : SubroutineWithHandlers<Label, Handler>, IMethodInfo {
+ private readonly Method method;
+ private HashSet<BlockWithLabels<Label>> blocks_ending_in_return_point;
+
+ public MethodSubroutine (SubroutineFacade subroutineFacade, Method method)
+ : base (subroutineFacade)
+ {
+ this.method = method;
+ }
+
+ public MethodSubroutine (SubroutineFacade SubroutineFacade,
+ Method method, Label startLabel,
+ SubroutineWithHandlersBuilder<Label, Handler> builder) : base (SubroutineFacade, startLabel, builder)
+ {
+ this.method = method;
+ IMetaDataProvider metaDataProvider = this.SubroutineFacade.MetaDataProvider;
+ builder.BuildBlocks (startLabel, this);
+ BlockWithLabels<Label> targetBlock = GetTargetBlock (startLabel);
+ Commit ();
+
+ TypeNode type = metaDataProvider.DeclaringType (method);
+ Subroutine invariant = this.SubroutineFacade.GetInvariant (type);
+ if (invariant != null && !metaDataProvider.IsConstructor (method) && !metaDataProvider.IsStatic (method)) {
+ AddEdgeSubroutine (Entry, targetBlock, invariant, EdgeTag.Entry);
+ Subroutine requires = this.SubroutineFacade.GetRequires (method);
+ if (requires != null)
+ AddEdgeSubroutine (Entry, targetBlock, requires, EdgeTag.Entry);
+ } else
+ AddEdgeSubroutine (Entry, targetBlock, this.SubroutineFacade.GetRequires (method), EdgeTag.Entry);
+
+ if (this.blocks_ending_in_return_point == null)
+ return;
+
+ Subroutine ensures = this.SubroutineFacade.GetEnsures (method);
+ bool putInvariantAfterExit = !metaDataProvider.IsStatic (method)
+ && !metaDataProvider.IsFinalizer (method) && !metaDataProvider.IsDispose (method);
+ foreach (var block in this.blocks_ending_in_return_point) {
+ if (putInvariantAfterExit)
+ AddEdgeSubroutine (block, Exit, invariant, EdgeTag.Exit);
+ AddEdgeSubroutine (block, Exit, ensures, EdgeTag.Exit);
+ }
+
+ if (ensures != null) {
+ throw new NotImplementedException();
+ }
+
+ this.blocks_ending_in_return_point = null;
+ }
+
+ #region Overrides of Subroutine
+ public override void Initialize ()
+ {
+ }
+ #endregion
+
+ #region Overrides of SubroutineBase<Label>
+ public override void AddReturnBlock (BlockWithLabels<Label> block)
+ {
+ if (this.blocks_ending_in_return_point == null)
+ this.blocks_ending_in_return_point = new HashSet<BlockWithLabels<Label>> ();
+
+ this.blocks_ending_in_return_point.Add (block);
+
+ base.AddReturnBlock (block);
+ }
+ #endregion
+
+ #region Implementation of IMethodInfo<Method>
+ public Method Method
+ {
+ get { return this.method; }
+ }
+ #endregion
+
+ public override SubroutineKind Kind
+ {
+ get { return SubroutineKind.Method; }
+ }
+
+ public override bool HasReturnValue
+ {
+ get { return !this.SubroutineFacade.MetaDataProvider.IsVoidMethod (this.method); }
+ }
+
+ public override bool IsMethod
+ {
+ get { return true; }
+ }
+
+ public override bool IsConstructor
+ {
+ get { return this.SubroutineFacade.MetaDataProvider.IsConstructor (this.method); }
+ }
+
+ public override string Name
+ {
+ get { return this.SubroutineFacade.MetaDataProvider.FullName (this.method); }
+ }
+ }
+}
--- /dev/null
+//
+// OldScanStateMachine.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.ControlFlow.Blocks;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Subroutines {
+ class OldScanStateMachine<Label> : ILVisitorBase<Label, Dummy, Dummy, int, bool>,
+ IAggregateVisitor<Label, int, bool> {
+ private readonly Dictionary<CFGBlock, ScanState> block_start_state = new Dictionary<CFGBlock, ScanState> ();
+ private readonly EnsuresSubroutine<Label> subroutine;
+ private EnsuresBlock<Label> current_block;
+ private TypeNode next_end_old_type;
+ private ScanState state;
+
+ public OldScanStateMachine (EnsuresSubroutine<Label> ensuresSubroutine)
+ {
+ this.subroutine = ensuresSubroutine;
+ this.state = ScanState.OutsideOld;
+ }
+
+ #region Overrides of ILVisitorBase<Label,Local,Parameter,Method,Field,Type,Dummy,Dummy,int,bool>
+ public override bool DefaultVisit (Label pc, int index)
+ {
+ if (this.state != ScanState.InsertingOld)
+ return this.current_block.UsesOverriding;
+
+ this.state = ScanState.OutsideOld;
+ this.current_block.EndOldWithoutInstruction (this.subroutine.SubroutineFacade.MetaDataProvider.ManagedPointer (this.next_end_old_type));
+ return true;
+ }
+ #endregion
+
+ #region Implementation of ICodeQuery<Label,Local,Parameter,Method,Field,Type,int,bool>
+ public bool Aggregate (Label pc, Label aggregateStart, bool canBeTargetOfBranch, int data)
+ {
+ return Nop (pc, data);
+ }
+ #endregion
+
+ #region IAggregateVisitor<Label,int,bool> Members
+ public override bool Nop (Label pc, int data)
+ {
+ return this.current_block.UsesOverriding;
+ }
+
+ public override bool BeginOld (Label pc, Label matchingEnd, int data)
+ {
+ this.state = ScanState.InsideOld;
+ return this.current_block.UsesOverriding;
+ }
+
+ public override bool EndOld (Label pc, Label matchingEnd, TypeNode type, Dummy dest, Dummy source, int data)
+ {
+ this.state = ScanState.OutsideOld;
+ return this.current_block.UsesOverriding;
+ }
+
+ public override bool LoadField (Label pc, Field field, Dummy dest, Dummy obj, int data)
+ {
+ if (this.state != ScanState.InsertingOld)
+ return this.current_block.UsesOverriding;
+
+ this.state = ScanState.OutsideOld;
+ this.current_block.EndOld (data, this.subroutine.SubroutineFacade.MetaDataProvider.FieldType (field));
+ return false;
+ }
+
+ public override bool LoadFieldAddress (Label pc, Field field, Dummy dest, Dummy obj, int data)
+ {
+ if (this.state == ScanState.InsertingOld)
+ this.next_end_old_type = this.subroutine.SubroutineFacade.MetaDataProvider.FieldType (field);
+ return this.current_block.UsesOverriding;
+ }
+
+ public override bool Call<TypeList, ArgList> (Label pc, Method method, bool virt, TypeList extraVarargs, Dummy dest, ArgList args, int data)
+ {
+ return false;
+ }
+ #endregion
+
+ public void HandlePotentialCallBlock (MethodCallBlock<Label> block, EnsuresBlock<Label> priorBlock)
+ {
+ if (block == null || this.state != ScanState.InsertingOld)
+ return;
+
+ int count = this.subroutine.SubroutineFacade.MetaDataProvider.Parameters (block.CalledMethod).Count;
+ if (!this.subroutine.SubroutineFacade.MetaDataProvider.IsStatic (block.CalledMethod))
+ ++count;
+ if (count > 1) {
+ this.state = ScanState.OutsideOld;
+ TypeNode mp = this.subroutine.SubroutineFacade.MetaDataProvider.ManagedPointer (this.next_end_old_type);
+ priorBlock.EndOldWithoutInstruction (mp);
+ } else {
+ this.state = ScanState.InsertingOldAfterCall;
+ this.next_end_old_type = this.subroutine.SubroutineFacade.MetaDataProvider.ReturnType (block.CalledMethod);
+ }
+ }
+
+ public void StartBlock (EnsuresBlock<Label> block)
+ {
+ if (!this.block_start_state.TryGetValue (block, out this.state)) {
+ this.state = ScanState.OutsideOld;
+ this.block_start_state.Add (block, this.state);
+ }
+ if (this.state == ScanState.InsertingOld)
+ block.StartOverridingLabels ();
+ if (this.state == ScanState.InsertingOldAfterCall) {
+ block.StartOverridingLabels ();
+ block.EndOldWithoutInstruction (this.next_end_old_type);
+ this.state = ScanState.OutsideOld;
+ }
+ this.current_block = block;
+ }
+
+ public void SetStartState (CFGBlock succ)
+ {
+ ScanState sstate;
+ if (!this.block_start_state.TryGetValue (succ, out sstate))
+ this.block_start_state.Add (succ, this.state);
+ }
+
+ #region Nested type: ScanState
+ private enum ScanState {
+ OutsideOld,
+ InsideOld,
+ InsertingOld,
+ InsertingOldAfterCall
+ }
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// OldValueSubroutine.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.ControlFlow.Blocks;
+using Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Subroutines {
+ class OldValueSubroutine<Label> : MethodContractSubroutine<Label> {
+ private BlockWithLabels<Label> begin_old_block;
+ private BlockWithLabels<Label> end_old_block;
+
+ public OldValueSubroutine (SubroutineFacade subroutineFacade, Method method,
+ SimpleSubroutineBuilder<Label> builder, Label startLabel)
+ : base (subroutineFacade, method, builder, startLabel)
+ {
+ }
+
+ public override SubroutineKind Kind
+ {
+ get { return SubroutineKind.Old; }
+ }
+
+ public override int StackDelta
+ {
+ get { return 1; }
+ }
+
+ public override bool IsOldValue
+ {
+ get { return true; }
+ }
+
+ public override void Initialize ()
+ {
+ }
+
+ public void Commit (BlockWithLabels<Label> endOldBlock)
+ {
+ this.end_old_block = endOldBlock;
+ base.Commit ();
+ }
+
+ public void RegisterBeginBlock (BlockWithLabels<Label> beginOldBlock)
+ {
+ this.begin_old_block = beginOldBlock;
+ }
+
+ public APC BeginOldAPC (LispList<Edge<CFGBlock, EdgeTag>> context)
+ {
+ return new APC (this.begin_old_block, 0, context);
+ }
+
+ public APC EndOldAPC (LispList<Edge<CFGBlock, EdgeTag>> context)
+ {
+ return new APC (this.end_old_block, this.end_old_block.Count - 1, context);
+ }
+ }
+}
--- /dev/null
+//
+// RequiresSubroutine.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Subroutines {
+ sealed class RequiresSubroutine<Label> : MethodContractSubroutine<Label>, IEquatable<RequiresSubroutine<Label>>
+ {
+ public override SubroutineKind Kind { get { return SubroutineKind.Requires; } }
+
+ public override bool IsContract { get { return true; } }
+
+ public override bool IsRequires { get { return true; } }
+
+ public RequiresSubroutine(SubroutineFacade subroutineFacade,
+ Method method,
+ IImmutableSet<Subroutine> inherited)
+ : base(subroutineFacade, method)
+ {
+ AddSuccessor(Entry, EdgeTag.Entry, Exit);
+ AddBaseRequires(Exit, inherited);
+ Commit();
+ }
+
+ public RequiresSubroutine(SubroutineFacade subroutineFacade,
+ Method method,
+ SimpleSubroutineBuilder<Label> builder,
+ Label entryLabel,
+ IImmutableSet<Subroutine> inheritedRequires)
+ : base(subroutineFacade, method, builder, entryLabel)
+ {
+ AddBaseRequires(this.GetTargetBlock(entryLabel), inheritedRequires);
+ }
+
+ public override void Initialize()
+ {
+ if (this.Builder == null)
+ return;
+
+ this.Builder.BuildBlocks(this.StartLabel, this);
+ this.Commit();
+
+ this.Builder = null;
+ }
+
+ private void AddBaseRequires(CFGBlock targetOfEntry, IImmutableSet<Subroutine> inherited)
+ {
+ foreach (var subroutine in inherited.Elements)
+ this.AddEdgeSubroutine(this.Entry, targetOfEntry, subroutine, EdgeTag.Inherited);
+ }
+
+ public bool Equals(RequiresSubroutine<Label> that)
+ {
+ return this.Id == that.Id;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// SimpleSubroutine.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Subroutines {
+ class SimpleSubroutine<Label> : SubroutineBase<Label> {
+ private readonly int stack_delta;
+
+ public SimpleSubroutine (int stackDelta, SubroutineFacade subroutineFacade,
+ Label startLabel, SimpleSubroutineBuilder<Label> builder)
+ : base (subroutineFacade, startLabel, builder)
+ {
+ this.stack_delta = stackDelta;
+ builder.BuildBlocks (startLabel, this);
+ Commit ();
+ }
+
+ public override int StackDelta
+ {
+ get { return this.stack_delta; }
+ }
+
+ public override SubroutineKind Kind
+ {
+ get { return SubroutineKind.Simple; }
+ }
+
+ public override void Initialize ()
+ {
+ }
+ }
+}
--- /dev/null
+//
+// SubroutineBase.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+using System.Linq;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.Analysis;
+using Mono.CodeContracts.Static.ControlFlow.Blocks;
+using Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Subroutines {
+ abstract class SubroutineBase<Label> : Subroutine, IGraph<CFGBlock, Dummy>, IStackInfo, IEdgeSubroutineAdaptor {
+ private const int UnusedBlockIndex = Int32.MaxValue - 1;
+ protected readonly Label StartLabel;
+ public readonly SubroutineFacade SubroutineFacade;
+
+ private readonly Dictionary<Pair<CFGBlock, CFGBlock>, LispList<Pair<EdgeTag, Subroutine>>> edge_subroutines
+ = new Dictionary<Pair<CFGBlock, CFGBlock>, LispList<Pair<EdgeTag, Subroutine>>> ();
+
+ private readonly BlockWithLabels<Label> entry;
+ private readonly BlockWithLabels<Label> entry_after_requires;
+ private readonly BlockWithLabels<Label> exception_exit;
+ private readonly BlockWithLabels<Label> exit;
+
+ private readonly List<Edge<CFGBlock, EdgeTag>> successors = new List<Edge<CFGBlock, EdgeTag>> ();
+ protected int BlockIdGenerator;
+ protected Dictionary<Label, BlockWithLabels<Label>> LabelsThatStartBlocks = new Dictionary<Label, BlockWithLabels<Label>> ();
+
+ private CFGBlock[] blocks;
+ private DepthFirst.Visitor<CFGBlock, Dummy> edge_info;
+ private EdgeMap<EdgeTag> predecessor_edges;
+ private EdgeMap<EdgeTag> successor_edges;
+
+ protected SubroutineBase (SubroutineFacade subroutineFacade)
+ {
+ this.SubroutineFacade = subroutineFacade;
+ this.entry = new EntryBlock<Label> (this, ref this.BlockIdGenerator);
+ this.exit = new EntryExitBlock<Label> (this, ref this.BlockIdGenerator);
+ this.exception_exit = new CatchFilterEntryBlock<Label> (this, ref this.BlockIdGenerator);
+ }
+
+ protected SubroutineBase (SubroutineFacade SubroutineFacade,
+ Label startLabel, SubroutineBuilder<Label> builder)
+ : this (SubroutineFacade)
+ {
+ this.StartLabel = startLabel;
+ Builder = builder;
+ CodeProvider = builder.CodeProvider;
+ this.entry_after_requires = GetTargetBlock (startLabel);
+
+ AddSuccessor (this.entry, EdgeTag.Entry, this.entry_after_requires);
+ }
+
+ public override bool HasContextDependentStackDepth
+ {
+ get { return true; }
+ }
+
+ public override bool HasReturnValue
+ {
+ get { return false; }
+ }
+
+ public override int StackDelta
+ {
+ get { return 0; }
+ }
+
+ protected SubroutineBuilder<Label> Builder { get; set; }
+
+ public override DepthFirst.Visitor<CFGBlock, Dummy> EdgeInfo
+ {
+ get { return this.edge_info; }
+ }
+
+ public ICodeProvider<Label> CodeProvider { get; private set; }
+
+ public override int BlockCount
+ {
+ get { return this.blocks.Length; }
+ }
+
+ public override IEnumerable<CFGBlock> Blocks
+ {
+ get { return this.blocks; }
+ }
+
+ public override string Name
+ {
+ get { return "SR" + Id; }
+ }
+
+ public override EdgeMap<EdgeTag> SuccessorEdges
+ {
+ get { return this.successor_edges; }
+ }
+
+ public override EdgeMap<EdgeTag> PredecessorEdges
+ {
+ get
+ {
+ if (this.predecessor_edges == null)
+ this.predecessor_edges = this.successor_edges.Reverse ();
+ return this.predecessor_edges;
+ }
+ }
+
+ #region Main Blocks
+ public override CFGBlock Entry
+ {
+ get { return this.entry; }
+ }
+
+ public override CFGBlock EntryAfterRequires
+ {
+ get
+ {
+ if (this.entry_after_requires != null)
+ return this.entry_after_requires;
+ return Entry;
+ }
+ }
+
+ public override CFGBlock Exit
+ {
+ get { return this.exit; }
+ }
+
+ public override CFGBlock ExceptionExit
+ {
+ get { return this.exception_exit; }
+ }
+ #endregion
+
+ #region IEdgeSubroutineAdaptor Members
+ public LispList<Pair<EdgeTag, Subroutine>> GetOrdinaryEdgeSubroutinesInternal (CFGBlock from, CFGBlock to, LispList<Edge<CFGBlock, EdgeTag>> context)
+ {
+ LispList<Pair<EdgeTag, Subroutine>> list;
+ this.edge_subroutines.TryGetValue (new Pair<CFGBlock, CFGBlock> (from, to), out list);
+ if (list != null && context != null)
+ list = list.Where (FilterRecursiveContracts (to, context));
+ return list;
+ }
+ #endregion
+
+ #region IGraph<CFGBlock,Dummy> Members
+ public IEnumerable<CFGBlock> Nodes
+ {
+ get { return this.blocks; }
+ }
+
+ public virtual IEnumerable<Pair<Dummy, CFGBlock>> Successors (CFGBlock node)
+ {
+ foreach (var pair in this.successor_edges [node])
+ yield return new Pair<Dummy, CFGBlock> (Dummy.Value, pair.Value);
+
+ if (node != this.exception_exit)
+ yield return new Pair<Dummy, CFGBlock> (Dummy.Value, this.exception_exit);
+ }
+ #endregion
+
+ #region IStackInfo Members
+ bool IStackInfo.IsCallOnThis (APC apc)
+ {
+ return false;
+ }
+ #endregion
+
+ public override IEnumerable<CFGBlock> SuccessorBlocks (CFGBlock block)
+ {
+ return SuccessorEdges [block].Select (it => it.Value);
+ }
+
+ public override bool HasSingleSuccessor (APC point, out APC ifFound)
+ {
+ if (point.Index < point.Block.Count) {
+ ifFound = new APC (point.Block, point.Index + 1, point.SubroutineContext);
+ return true;
+ }
+
+ if (IsSubroutineEnd (point.Block)) {
+ if (point.SubroutineContext == null) {
+ ifFound = APC.Dummy;
+ return false;
+ }
+
+ ifFound = ComputeSubroutineContinuation (point);
+ return true;
+ }
+
+ BlockWithLabels<Label> onlyOne = null;
+ foreach (BlockWithLabels<Label> successor in point.Block.Subroutine.SuccessorBlocks (point.Block)) {
+ if (onlyOne == null)
+ onlyOne = successor;
+ else {
+ ifFound = APC.Dummy;
+ return false;
+ }
+ }
+
+ if (onlyOne != null) {
+ ifFound = ComputeTargetFinallyContext (point, onlyOne);
+ return true;
+ }
+
+ ifFound = APC.Dummy;
+ return false;
+ }
+
+ public override bool HasSinglePredecessor (APC point, out APC ifFound)
+ {
+ if (point.Index > 0) {
+ ifFound = new APC (point.Block, point.Index - 1, point.SubroutineContext);
+ return true;
+ }
+
+ if (IsSubroutineStart (point.Block)) {
+ if (point.SubroutineContext == null) {
+ ifFound = APC.Dummy;
+ return false;
+ }
+
+ bool hasSinglePredecessor;
+ ifFound = ComputeSubroutinePreContinuation (point, out hasSinglePredecessor);
+ return hasSinglePredecessor;
+ }
+
+
+ CFGBlock onlyOne = null;
+ foreach (CFGBlock predecessor in point.Block.Subroutine.PredecessorBlocks (point.Block)) {
+ if (onlyOne != null) {
+ ifFound = APC.Dummy;
+ return false;
+ }
+ onlyOne = predecessor;
+ }
+ if (onlyOne == null) {
+ ifFound = APC.Dummy;
+ return false;
+ }
+
+ LispList<Pair<EdgeTag, Subroutine>> list = EdgeSubroutinesOuterToInner (onlyOne, point.Block, point.SubroutineContext);
+ if (list.IsEmpty ()) {
+ ifFound = APC.ForEnd (onlyOne, point.SubroutineContext);
+ return true;
+ }
+
+ var edge = new Edge<CFGBlock, EdgeTag> (onlyOne, point.Block, list.Head.Key);
+ Subroutine sub = list.Head.Value;
+ ifFound = APC.ForEnd (sub.Exit, point.SubroutineContext.Cons (edge));
+ return true;
+ }
+
+ private APC ComputeSubroutinePreContinuation (APC point, out bool hasSinglePredecessor)
+ {
+ Edge<CFGBlock, EdgeTag> head = point.SubroutineContext.Head;
+ bool isExceptionHandlerEdge;
+ LispList<Edge<CFGBlock, EdgeTag>> tail = point.SubroutineContext.Tail;
+ LispList<Pair<EdgeTag, Subroutine>> flist = EdgeSubroutinesOuterToInner (head.From, head.To, out isExceptionHandlerEdge, tail);
+ while (flist.Head.Value != this)
+ flist = flist.Tail;
+ if (flist.Tail.IsEmpty ()) {
+ if (isExceptionHandlerEdge && head.From.Count > 1) {
+ hasSinglePredecessor = false;
+ return APC.Dummy;
+ }
+
+ hasSinglePredecessor = true;
+ return APC.ForEnd (head.From, tail);
+ }
+ Pair<EdgeTag, Subroutine> first = flist.Tail.Head;
+ Subroutine sub = first.Value;
+ hasSinglePredecessor = true;
+
+ return APC.ForEnd (sub.Exit, point.SubroutineContext.Cons (new Edge<CFGBlock, EdgeTag> (head.From, head.To, first.Key)));
+ }
+
+ private APC ComputeSubroutineContinuation (APC point)
+ {
+ Edge<CFGBlock, EdgeTag> head = point.SubroutineContext.Head;
+ LispList<Edge<CFGBlock, EdgeTag>> tail = point.SubroutineContext.Tail;
+ LispList<Pair<EdgeTag, Subroutine>> outerToInner = EdgeSubroutinesOuterToInner (head.From, head.To, tail);
+ if (outerToInner.Head.Value == this)
+ return new APC (head.To, 0, tail);
+
+ while (outerToInner.Tail.Head.Value != this)
+ outerToInner = outerToInner.Tail;
+
+ return new APC (outerToInner.Head.Value.Entry, 0, tail.Cons (new Edge<CFGBlock, EdgeTag> (head.From, head.To, outerToInner.Head.Key)));
+ }
+
+ public override IEnumerable<CFGBlock> PredecessorBlocks (CFGBlock block)
+ {
+ return PredecessorEdges [block].Select (it => it.Value);
+ }
+
+ public override bool IsJoinPoint (CFGBlock block)
+ {
+ if (IsCatchFilterHeader (block) || IsSubroutineStart (block) || IsSubroutineEnd (block))
+ return true;
+
+ return PredecessorEdges [block].Count > 1;
+ }
+
+ public override bool IsSubroutineEnd (CFGBlock block)
+ {
+ return block == this.exit || block == this.exception_exit;
+ }
+
+ public override bool IsSubroutineStart (CFGBlock block)
+ {
+ return block == this.entry;
+ }
+
+ public override bool IsSplitPoint (CFGBlock block)
+ {
+ if (IsSubroutineStart (block) || IsSubroutineEnd (block))
+ return true;
+
+ return SuccessorEdges [block].Count > 1;
+ }
+
+ public override bool IsCatchFilterHeader (CFGBlock block)
+ {
+ return block is CatchFilterEntryBlock<Label>;
+ }
+
+ public void AddSuccessor (CFGBlock from, EdgeTag tag, CFGBlock to)
+ {
+ AddNormalControlFlowEdge (this.successors, from, tag, to);
+ }
+
+ private void AddNormalControlFlowEdge (List<Edge<CFGBlock, EdgeTag>> succs, CFGBlock from, EdgeTag tag, CFGBlock to)
+ {
+ succs.Add (new Edge<CFGBlock, EdgeTag> (from, to, tag));
+ }
+
+ public virtual void AddReturnBlock (BlockWithLabels<Label> block)
+ {
+ }
+
+ public BlockWithLabels<Label> GetTargetBlock (Label label)
+ {
+ return GetBlock (label);
+ }
+
+ public BlockWithLabels<Label> GetBlock (Label label)
+ {
+ IMetaDataProvider metadataDecoder = this.SubroutineFacade.MetaDataProvider;
+
+ BlockWithLabels<Label> block;
+ if (!this.LabelsThatStartBlocks.TryGetValue (label, out block)) {
+ Pair<Method, bool> methodVirtualPair;
+ Method constructor;
+
+ if (Builder == null)
+ throw new InvalidOperationException ("Builder must be not null");
+
+ if (Builder.IsMethodCallSite (label, out methodVirtualPair)) {
+ int parametersCount = metadataDecoder.Parameters (methodVirtualPair.Key).Count;
+ block = new MethodCallBlock<Label> (methodVirtualPair.Key, this, ref this.BlockIdGenerator, parametersCount, methodVirtualPair.Value);
+ } else if (Builder.IsNewObjSite (label, out constructor)) {
+ int parametersCount = metadataDecoder.Parameters (constructor).Count;
+ block = new NewObjCallBlock<Label> (constructor, parametersCount, this, ref this.BlockIdGenerator);
+ } else
+ block = NewBlock ();
+
+ if (Builder.IsTargetLabel (label))
+ this.LabelsThatStartBlocks.Add (label, block);
+ }
+ return block;
+ }
+
+ public virtual BlockWithLabels<Label> NewBlock ()
+ {
+ return new BlockWithLabels<Label> (this, ref this.BlockIdGenerator);
+ }
+
+ public AssumeBlock<Label> NewAssumeBlock (Label pc, EdgeTag tag)
+ {
+ return new AssumeBlock<Label> (this, pc, tag, ref this.BlockIdGenerator);
+ }
+
+ public override sealed void AddEdgeSubroutine (CFGBlock from, CFGBlock to, Subroutine subroutine, EdgeTag tag)
+ {
+ if (subroutine == null)
+ return;
+
+ var key = new Pair<CFGBlock, CFGBlock> (from, to);
+ LispList<Pair<EdgeTag, Subroutine>> list;
+ var item = new Pair<EdgeTag, Subroutine> (tag, subroutine);
+
+ this.edge_subroutines.TryGetValue (key, out list);
+ this.edge_subroutines [key] = list.Cons (item);
+ }
+
+ public override IEnumerable<APC> Successors (APC pc)
+ {
+ APC singleNext;
+ if (HasSingleSuccessor (pc, out singleNext))
+ yield return singleNext;
+ else {
+ foreach (CFGBlock block in pc.Block.Subroutine.SuccessorBlocks (pc.Block))
+ yield return pc.Block.Subroutine.ComputeTargetFinallyContext (pc, block);
+ }
+ }
+
+ public override IEnumerable<APC> Predecessors (APC pc)
+ {
+ if (pc.Index > 0)
+ yield return new APC (pc.Block, pc.Index - 1, pc.SubroutineContext);
+
+ else if (IsSubroutineStart (pc.Block)) {
+ if (!pc.SubroutineContext.IsEmpty ()) {
+ foreach (APC apc in ComputeSubroutinePreContinuation (pc))
+ yield return apc;
+ }
+ } else {
+ foreach (CFGBlock block in pc.Block.Subroutine.PredecessorBlocks (pc.Block)) {
+ LispList<Pair<EdgeTag, Subroutine>> diffs = EdgeSubroutinesOuterToInner (block, pc.Block, pc.SubroutineContext);
+ if (diffs.IsEmpty ())
+ yield return APC.ForEnd (block, pc.SubroutineContext);
+ else {
+ Subroutine sub = diffs.Head.Value;
+ var edge = new Edge<CFGBlock, EdgeTag> (block, pc.Block, diffs.Head.Key);
+ yield return APC.ForEnd (sub.Exit, pc.SubroutineContext.Cons (edge));
+ }
+ }
+ }
+ }
+
+ private IEnumerable<APC> ComputeSubroutinePreContinuation (APC point)
+ {
+ Edge<CFGBlock, EdgeTag> edge = point.SubroutineContext.Head;
+ LispList<Edge<CFGBlock, EdgeTag>> tail = point.SubroutineContext.Tail;
+
+ bool isHandlerEdge;
+ LispList<Pair<EdgeTag, Subroutine>> diffs = EdgeSubroutinesOuterToInner (edge.From, edge.To, out isHandlerEdge, tail);
+ while (diffs.Head.Value != this)
+ diffs = diffs.Tail;
+
+ if (diffs.Tail == null) {
+ if (isHandlerEdge) {
+ for (int i = 0; i < edge.From.Count; i++)
+ yield return new APC (edge.From, i, tail);
+ } else
+ yield return APC.ForEnd (edge.From, tail);
+ } else {
+ Pair<EdgeTag, Subroutine> first = diffs.Tail.Head;
+ Subroutine nextSubroutine = first.Value;
+ yield return APC.ForEnd (nextSubroutine.Exit, point.SubroutineContext.Cons (new Edge<CFGBlock, EdgeTag> (edge.From, edge.To, first.Key)));
+ }
+ }
+
+ public override APC ComputeTargetFinallyContext (APC pc, CFGBlock succ)
+ {
+ LispList<Pair<EdgeTag, Subroutine>> list = EdgeSubroutinesOuterToInner (pc.Block, succ, pc.SubroutineContext);
+ if (list.IsEmpty ())
+ return new APC (succ, 0, pc.SubroutineContext);
+
+ Pair<EdgeTag, Subroutine> last = list.Last ();
+ return new APC (last.Value.Entry, 0, pc.SubroutineContext.Cons (new Edge<CFGBlock, EdgeTag> (pc.Block, succ, last.Key)));
+ }
+
+ private LispList<Pair<EdgeTag, Subroutine>> EdgeSubroutinesOuterToInner (CFGBlock from, CFGBlock succ, LispList<Edge<CFGBlock, EdgeTag>> subroutineContext)
+ {
+ bool isExceptionHandlerEdge;
+ return EdgeSubroutinesOuterToInner (from, succ, out isExceptionHandlerEdge, subroutineContext);
+ }
+
+ public override LispList<Pair<EdgeTag, Subroutine>> EdgeSubroutinesOuterToInner (CFGBlock from, CFGBlock succ, out bool isExceptionHandlerEdge, LispList<Edge<CFGBlock, EdgeTag>> context)
+ {
+ if (from.Subroutine != this)
+ return from.Subroutine.EdgeSubroutinesOuterToInner (from, succ, out isExceptionHandlerEdge, context);
+
+ isExceptionHandlerEdge = IsCatchFilterHeader (succ);
+ return GetOrdinaryEdgeSubroutines (from, succ, context);
+ }
+
+ public override LispList<Pair<EdgeTag, Subroutine>> GetOrdinaryEdgeSubroutines (CFGBlock from, CFGBlock to, LispList<Edge<CFGBlock, EdgeTag>> context)
+ {
+ IMetaDataProvider metadataDecoder = this.SubroutineFacade.MetaDataProvider;
+ var apc = new APC (to, 0, context);
+
+ DecoratorHelper.Push (this);
+ try {
+ LispList<Pair<EdgeTag, Subroutine>> list = DecoratorHelper.Dispatch<IEdgeSubroutineAdaptor> (this).GetOrdinaryEdgeSubroutinesInternal (from, to, context);
+ if (apc.InsideContract) {
+ if (context != null && !list.IsEmpty ()) {
+ Method calledMethod;
+ bool isNewObj;
+ bool isVirtual;
+ if (@from.IsMethodCallBlock (out calledMethod, out isNewObj, out isVirtual) && isVirtual && ((IStackInfo) this).IsCallOnThis (new APC (@from, 0, null))) {
+ TypeNode type = metadataDecoder.DeclaringType (calledMethod);
+ do {
+ if (context.Head.Tag.Is (EdgeTag.InheritedMask) || context.Head.Tag.Is (EdgeTag.ExtraMask) || context.Head.Tag.Is (EdgeTag.OldMask))
+ context = context.Tail;
+ else {
+ Method calledMethod2;
+ bool isNewObj2;
+ bool isVirtual2;
+ if (context.Head.Tag.Is (EdgeTag.AfterMask) && context.Head.From.IsMethodCallBlock (out calledMethod2, out isNewObj2, out isVirtual2)) {
+ TypeNode sub = metadataDecoder.DeclaringType (calledMethod2);
+ if (metadataDecoder.DerivesFrom (sub, type))
+ type = sub;
+ if (!DecoratorHelper.Dispatch<IStackInfo> (this).IsCallOnThis (new APC (context.Head.From, 0, null)))
+ break;
+ } else if (context.Head.Tag.Is (EdgeTag.BeforeMask) && context.Head.To.IsMethodCallBlock (out calledMethod2, out isNewObj2, out isVirtual2)) {
+ TypeNode sub = metadataDecoder.DeclaringType (calledMethod2);
+ if (metadataDecoder.DerivesFrom (sub, type))
+ type = sub;
+ if (!DecoratorHelper.Dispatch<IStackInfo> (this).IsCallOnThis (new APC (context.Head.To, 0, null)))
+ break;
+ } else if (context.Head.Tag == EdgeTag.Exit) {
+ var methodInfo = context.Head.From.Subroutine as IMethodInfo;
+ if (methodInfo != null) {
+ TypeNode sub = metadataDecoder.DeclaringType (methodInfo.Method);
+ if (metadataDecoder.DerivesFrom (sub, type))
+ type = sub;
+ }
+ break;
+ } else {
+ if (context.Head.Tag != EdgeTag.Entry)
+ return list;
+ var methodInfo = context.Head.From.Subroutine as IMethodInfo;
+ if (methodInfo != null) {
+ TypeNode sub = metadataDecoder.DeclaringType (methodInfo.Method);
+ if (metadataDecoder.DerivesFrom (sub, type))
+ type = sub;
+ }
+ break;
+ }
+ context = context.Tail;
+ }
+ } while (!context.IsEmpty ());
+ Method implementingMethod;
+ if (!metadataDecoder.Equal (type, metadataDecoder.DeclaringType (calledMethod)) &&
+ metadataDecoder.TryGetImplementingMethod (type, calledMethod, out implementingMethod))
+ list = SpecializedEnsures (list, this.SubroutineFacade.GetEnsures (calledMethod), this.SubroutineFacade.GetEnsures (implementingMethod));
+ }
+ }
+ } else {
+ Method calledMethod;
+ bool isNewObj;
+ bool isVirtual;
+ if (@from.IsMethodCallBlock (out calledMethod, out isNewObj, out isVirtual)) {
+ if (DecoratorHelper.Dispatch<IStackInfo> (this).IsCallOnThis (new APC (@from, 0, null))) {
+ var methodInfo = @from.Subroutine as IMethodInfo;
+ if (methodInfo != null) {
+ TypeNode bestType = metadataDecoder.DeclaringType (methodInfo.Method);
+ Method implementingMethod;
+ if (isVirtual && metadataDecoder.TryGetImplementingMethod (bestType, calledMethod, out implementingMethod))
+ list = SpecializedEnsures (list, this.SubroutineFacade.GetEnsures (calledMethod), this.SubroutineFacade.GetEnsures (implementingMethod));
+ list = InsertInvariant (@from, list, calledMethod, ref bestType, context);
+ }
+ }
+ }
+ }
+ return list;
+ } finally {
+ DecoratorHelper.Pop ();
+ }
+ }
+
+ private LispList<Pair<EdgeTag, Subroutine>> InsertInvariant (CFGBlock from, LispList<Pair<EdgeTag, Subroutine>> list,
+ Method calledMethod, ref TypeNode type,
+ LispList<Edge<CFGBlock, EdgeTag>> context)
+ {
+ IMetaDataProvider metadataDecoder = this.SubroutineFacade.MetaDataProvider;
+
+ Property property;
+ if (metadataDecoder.IsPropertySetter (calledMethod, out property)
+ && (metadataDecoder.IsAutoPropertyMember (calledMethod) || WithinConstructor (from, context)))
+ return list;
+
+ if (metadataDecoder.IsConstructor (calledMethod))
+ type = metadataDecoder.DeclaringType (calledMethod);
+
+ Subroutine invariant = this.SubroutineFacade.GetInvariant (type);
+ if (invariant != null) {
+ var methodCallBlock = from as MethodCallBlock<Label>;
+ if (methodCallBlock != null) {
+ EdgeTag first = methodCallBlock.IsNewObj ? EdgeTag.AfterNewObj : EdgeTag.AfterCall;
+ return list.Cons (new Pair<EdgeTag, Subroutine> (first, invariant));
+ }
+ }
+
+ return list;
+ }
+
+ private bool WithinConstructor (CFGBlock current, LispList<Edge<CFGBlock, EdgeTag>> context)
+ {
+ return new APC (current, 0, context).InsideConstructor;
+ }
+
+ private LispList<Pair<EdgeTag, Subroutine>> SpecializedEnsures (LispList<Pair<EdgeTag, Subroutine>> subroutines,
+ Subroutine toReplace, Subroutine specializedEnsures)
+ {
+ return subroutines.Select (pair => new Pair<EdgeTag, Subroutine> (pair.Key, pair.Value == toReplace ? specializedEnsures : pair.Value));
+ }
+
+ private static Predicate<Pair<EdgeTag, Subroutine>> FilterRecursiveContracts (CFGBlock from, LispList<Edge<CFGBlock, EdgeTag>> context)
+ {
+ return (candidate) => {
+ Subroutine sub = candidate.Value;
+ if (!sub.IsContract)
+ return true;
+ if (sub == @from.Subroutine)
+ return false;
+ if (context.Any (ctx => sub == ctx.From.Subroutine))
+ return false;
+ return true;
+ };
+ }
+
+ public abstract override void Initialize ();
+
+ public virtual void Commit ()
+ {
+ PostProcessBlocks ();
+ }
+
+ protected void PostProcessBlocks ()
+ {
+ var blockStack = new Stack<CFGBlock> ();
+ this.successor_edges = new EdgeMap<EdgeTag> (this.successors);
+ this.edge_info = new DepthFirst.Visitor<CFGBlock, Dummy> (this, null, (block) => blockStack.Push (block), null);
+ this.edge_info.VisitSubGraphNonRecursive (this.exception_exit);
+ this.edge_info.VisitSubGraphNonRecursive (this.exit);
+ this.edge_info.VisitSubGraphNonRecursive (this.entry);
+
+ foreach (var successorEdge in this.successor_edges) {
+ int idGen = UnusedBlockIndex;
+ successorEdge.From.Renumber (ref idGen);
+ }
+ int idGen1 = 0;
+ foreach (CFGBlock cfgBlock in blockStack)
+ cfgBlock.Renumber (ref idGen1);
+
+ SuccessorEdges.Filter ((e) => e.From.Index != UnusedBlockIndex);
+ this.predecessor_edges = this.successor_edges.Reverse ();
+ int finishTime = 0;
+ var visitor = new DepthFirst.Visitor<CFGBlock, EdgeTag> (this.predecessor_edges, null, block => block.ReversePostOrderIndex = finishTime++, null);
+ visitor.VisitSubGraphNonRecursive (this.exit);
+ foreach (CFGBlock node in blockStack)
+ visitor.VisitSubGraphNonRecursive (node);
+
+ SuccessorEdges.Resort ();
+ this.blocks = blockStack.ToArray ();
+ this.LabelsThatStartBlocks = null;
+ Builder = null;
+ }
+
+ public override IEnumerable<Subroutine> UsedSubroutines (HashSet<int> alreadySeen)
+ {
+ foreach (var list in this.edge_subroutines.Values) {
+ foreach (var pair in list.AsEnumerable ()) {
+ Subroutine sub = pair.Value;
+ if (!alreadySeen.Contains (sub.Id)) {
+ alreadySeen.Add (sub.Id);
+ yield return sub;
+ }
+ }
+ }
+ }
+
+ public override IEnumerable<CFGBlock> ExceptionHandlers<Data, TType> (CFGBlock block, Subroutine innerSubroutine,
+ Data data, IHandlerFilter<Data> handlerPredicate)
+ {
+ yield return this.exception_exit;
+ }
+
+
+ public override void Print (TextWriter tw, ILPrinter<APC> printer, Func<CFGBlock,
+ IEnumerable<LispList<Edge<CFGBlock, EdgeTag>>>> contextLookup,
+ LispList<Edge<CFGBlock, EdgeTag>> context,
+ HashSet<Pair<Subroutine, LispList<Edge<CFGBlock, EdgeTag>>>> printed)
+ {
+ var element = new Pair<Subroutine, LispList<Edge<CFGBlock, EdgeTag>>> (this, context);
+ if (printed.Contains (element))
+ return;
+ printed.Add (element);
+ var subs = new HashSet<Subroutine> ();
+ var methodInfo = this as IMethodInfo;
+ string method = (methodInfo != null) ? String.Format ("({0})", this.SubroutineFacade.MetaDataProvider.FullName (methodInfo.Method)) : null;
+
+ tw.WriteLine ("Subroutine SR{0} {1} {2}", Id, Kind, method);
+ tw.WriteLine ("-------------");
+ foreach (BlockWithLabels<Label> block in this.blocks) {
+ tw.Write ("Block {0} ({1})", block.Index, block.ReversePostOrderIndex);
+ if (this.edge_info.DepthFirstInfo (block).TargetOfBackEdge)
+ tw.WriteLine (" (target of backedge)");
+ else if (IsJoinPoint (block))
+ tw.WriteLine (" (join point)");
+ else
+ tw.WriteLine ();
+
+ tw.Write (" Predecessors: ");
+ foreach (var edge in block.Subroutine.PredecessorEdges [block])
+ tw.Write ("({0}, {1}) ", edge.Key, edge.Value.Index);
+ tw.WriteLine ();
+ PrintHandlers (tw, block);
+
+ tw.WriteLine (" Code:");
+ foreach (APC apc in block.APCs ())
+ printer (apc, " ", tw);
+
+ tw.Write (" Successors: ");
+ foreach (var edge in block.Subroutine.SuccessorEdges [block]) {
+ tw.Write ("({0}, {1}", edge.Key, edge.Value.Index);
+ if (this.edge_info.IsBackEdge (block, Dummy.Value, edge.Value))
+ tw.Write (" BE");
+
+ for (LispList<Pair<EdgeTag, Subroutine>> list = GetOrdinaryEdgeSubroutines (block, edge.Value, context); list != null; list = list.Tail) {
+ subs.Add (list.Head.Value);
+ tw.Write (" SR{0}({1})", list.Head.Value.Id, list.Head.Key);
+ }
+ tw.Write (") ");
+ }
+ tw.WriteLine ();
+ }
+ PrintReferencedSubroutines (tw, subs, printer, contextLookup, context, printed);
+ }
+
+ protected virtual void PrintReferencedSubroutines (TextWriter tw, HashSet<Subroutine> subs, ILPrinter<APC> printer,
+ Func<CFGBlock, IEnumerable<LispList<Edge<CFGBlock, EdgeTag>>>> contextLookup,
+ LispList<Edge<CFGBlock, EdgeTag>> context,
+ HashSet<Pair<Subroutine, LispList<Edge<CFGBlock, EdgeTag>>>> printed)
+ {
+ foreach (Subroutine subroutine in subs) {
+ if (contextLookup == null)
+ subroutine.Print (tw, printer, contextLookup, context, printed);
+ else {
+ foreach (var ctx in contextLookup (subroutine.Entry))
+ subroutine.Print (tw, printer, contextLookup, ctx, printed);
+ }
+ }
+ }
+
+ protected virtual void PrintHandlers (TextWriter tw, BlockWithLabels<Label> block)
+ {
+ tw.Write (" Handlers: ");
+ if (block != ExceptionExit)
+ tw.Write ("{0} ", ExceptionExit.Index);
+ tw.WriteLine ();
+ }
+
+ public int GetILOffset (Label label)
+ {
+ return CodeProvider.GetILOffset (label);
+ }
+ }
+}
--- /dev/null
+//
+// SubroutineFacade.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.ControlFlow.Blocks;
+using Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Subroutines {
+ class SubroutineFacade : IMethodCodeConsumer<Dummy, Subroutine> {
+ public readonly IContractProvider ContractProvider;
+ public readonly IMetaDataProvider MetaDataProvider;
+
+// private readonly EnsuresFactory ensures_factory;
+ private readonly Dictionary<Method, ICFG> method_cache = new Dictionary<Method, ICFG> ();
+ private readonly RequiresFactory requires_factory;
+
+ public SubroutineFacade (IMetaDataProvider metaDataProvider,
+ IContractProvider contractProvider)
+ {
+ this.MetaDataProvider = metaDataProvider;
+ this.ContractProvider = contractProvider;
+ this.requires_factory = new RequiresFactory (this);
+// this.ensures_factory = new EnsuresFactory (this);
+ }
+
+ #region IMethodCodeConsumer<Dummy,Subroutine> Members
+ Subroutine IMethodCodeConsumer<Dummy, Subroutine>.Accept<Label, Handler> (
+ IMethodCodeProvider<Label, Handler> codeProvider,
+ Label entry,
+ Method method,
+ Dummy data)
+ {
+ var builder = new SubroutineWithHandlersBuilder<Label, Handler> (codeProvider, this, method, entry);
+ return new MethodSubroutine<Label, Handler> (this, method, entry, builder);
+ }
+ #endregion
+
+ public Result ForwardDecode<Data, Result, Visitor> (APC pc, Visitor visitor, Data data)
+ where Visitor : IILVisitor<APC, Dummy, Dummy, Data, Result>
+ {
+ var block = pc.Block as BlockBase;
+ if (block != null)
+ return block.ForwardDecode<Data, Result, Visitor> (pc, visitor, data);
+
+ return visitor.Nop (pc, data);
+ }
+
+ public Subroutine GetRequires (Method method)
+ {
+ method = this.MetaDataProvider.Unspecialized (method);
+ return this.requires_factory.Get (method);
+ }
+
+ public Subroutine GetEnsures (Method method)
+ {
+ return null;
+ //todo: implement handling this in MethodSubroutine and uncomment lines below
+
+// method = this.MetaDataProvider.Unspecialized (method);
+// return this.ensures_factory.Get (method);
+ }
+
+ public Subroutine GetInvariant (TypeNode type)
+ {
+ //todo: implement this
+ return null;
+ }
+
+ public ICFG GetControlFlowGraph (Method method)
+ {
+ if (this.method_cache.ContainsKey (method))
+ return this.method_cache [method];
+
+ if (!this.MetaDataProvider.HasBody (method))
+ throw new InvalidOperationException ("Method has no body");
+
+ return new ControlFlowGraph (this.MetaDataProvider.AccessMethodBody (method, this, Dummy.Value), this);
+ }
+
+
+ public void AddReads (Method method, Field field)
+ {
+ throw new NotImplementedException ();
+ }
+
+
+ public IEnumerable<Method> GetAffectedGetters (Field field)
+ {
+ //todo: implement this
+
+ return new Method[0];
+ }
+
+ public IEnumerable<Field> GetModifies (Method method)
+ {
+ //todo: implement this
+ return new Field[0];
+ }
+ }
+}
--- /dev/null
+//
+// SubroutineWithHandlers.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+using System.Linq;
+using Mono.CodeContracts.Static.Analysis;
+using Mono.CodeContracts.Static.ControlFlow.Blocks;
+using Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.ControlFlow.Subroutines {
+ abstract class SubroutineWithHandlers<Label, Handler> : SubroutineBase<Label> {
+ protected readonly Dictionary<Handler, BlockWithLabels<Label>> CatchFilterHeaders = new Dictionary<Handler, BlockWithLabels<Label>> ();
+
+ public readonly Dictionary<Handler, Subroutine> FaultFinallySubroutines = new Dictionary<Handler, Subroutine> ();
+ protected readonly Dictionary<Handler, BlockWithLabels<Label>> FilterCodeBlocks = new Dictionary<Handler, BlockWithLabels<Label>> ();
+ public readonly Dictionary<CFGBlock, LispList<Handler>> ProtectingHandlers = new Dictionary<CFGBlock, LispList<Handler>> ();
+ public LispList<Handler> CurrentProtectingHandlers = LispList<Handler>.Empty;
+
+ protected SubroutineWithHandlers (SubroutineFacade subroutineFacade)
+ : base (subroutineFacade)
+ {
+ }
+
+ protected SubroutineWithHandlers (SubroutineFacade subroutineFacade,
+ Label startLabel,
+ SubroutineBuilder<Label> builder)
+ : base (subroutineFacade, startLabel, builder)
+ {
+ }
+
+ protected new IMethodCodeProvider<Label, Handler> CodeProvider
+ {
+ get { return (IMethodCodeProvider<Label, Handler>) base.CodeProvider; }
+ }
+
+ private bool IsFault (Handler handler)
+ {
+ return CodeProvider.IsFaultHandler (handler);
+ }
+
+ private LispList<Handler> ProtectingHandlerList (CFGBlock block)
+ {
+ LispList<Handler> list;
+ this.ProtectingHandlers.TryGetValue (block, out list);
+ return list;
+ }
+
+ public BlockWithLabels<Label> CreateCatchFilterHeader (Handler handler, Label label)
+ {
+ BlockWithLabels<Label> block;
+ if (!this.LabelsThatStartBlocks.TryGetValue (label, out block)) {
+ block = new CatchFilterEntryBlock<Label> (this, ref this.BlockIdGenerator);
+
+ this.CatchFilterHeaders.Add (handler, block);
+ this.LabelsThatStartBlocks.Add (label, block);
+ if (CodeProvider.IsFilterHandler (handler)) {
+ BlockWithLabels<Label> targetBlock = GetTargetBlock (CodeProvider.FilterExpressionStart (handler));
+ this.FilterCodeBlocks.Add (handler, targetBlock);
+ }
+ }
+ return block;
+ }
+
+ public override IEnumerable<Subroutine> UsedSubroutines (HashSet<int> alreadySeen)
+ {
+ return this.FaultFinallySubroutines.Values.Concat (base.UsedSubroutines (alreadySeen));
+ }
+
+ public override LispList<Pair<EdgeTag, Subroutine>> EdgeSubroutinesOuterToInner (CFGBlock current, CFGBlock succ,
+ out bool isExceptionHandlerEdge, LispList<Edge<CFGBlock, EdgeTag>> context)
+ {
+ if (current.Subroutine != this)
+ return current.Subroutine.EdgeSubroutinesOuterToInner (current, succ, out isExceptionHandlerEdge, context);
+
+ LispList<Handler> l1 = ProtectingHandlerList (current);
+ LispList<Handler> l2 = ProtectingHandlerList (succ);
+ isExceptionHandlerEdge = IsCatchFilterHeader (succ);
+
+ LispList<Pair<EdgeTag, Subroutine>> result = GetOrdinaryEdgeSubroutines (current, succ, context);
+
+ while (l1 != l2) {
+ if (l1.Length () >= l2.Length ()) {
+ Handler head = l1.Head;
+ if (IsFaultOrFinally (head) && (!IsFault (head) || isExceptionHandlerEdge))
+ result = result.Cons (new Pair<EdgeTag, Subroutine> (EdgeTag.Finally, this.FaultFinallySubroutines [head]));
+ l1 = l1.Tail;
+ } else
+ l2 = l2.Tail;
+ }
+
+ return result;
+ }
+
+ private bool IsFaultOrFinally (Handler handler)
+ {
+ return CodeProvider.IsFaultHandler (handler) || CodeProvider.IsFinallyHandler (handler);
+ }
+
+ public override IEnumerable<Pair<Dummy, CFGBlock>> Successors (CFGBlock node)
+ {
+ foreach (var pair in SuccessorEdges [node])
+ yield return new Pair<Dummy, CFGBlock> (Dummy.Value, pair.Value);
+
+ foreach (Handler handler in ProtectingHandlerList (node).AsEnumerable ()) {
+ if (!IsFaultOrFinally (handler))
+ yield return new Pair<Dummy, CFGBlock> (Dummy.Value, this.CatchFilterHeaders [handler]);
+ }
+ if (node != ExceptionExit)
+ yield return new Pair<Dummy, CFGBlock> (Dummy.Value, ExceptionExit);
+ }
+
+ public override IEnumerable<CFGBlock> ExceptionHandlers<Data, TType> (CFGBlock block, Subroutine innerSubroutine,
+ Data data, IHandlerFilter<Data> handlerPredicate)
+ {
+ IHandlerFilter<Data> handleFilter = handlerPredicate;
+ LispList<Handler> protectingHandlers = ProtectingHandlerList (block);
+ if (innerSubroutine != null && innerSubroutine.IsFaultFinally) {
+ for (; protectingHandlers != null; protectingHandlers = protectingHandlers.Tail) {
+ if (IsFaultOrFinally (protectingHandlers.Head) && this.FaultFinallySubroutines [protectingHandlers.Head] == innerSubroutine) {
+ protectingHandlers = protectingHandlers.Tail;
+ break;
+ }
+ }
+ }
+
+ for (; protectingHandlers != null; protectingHandlers = protectingHandlers.Tail) {
+ Handler handler = protectingHandlers.Head;
+ if (!IsFaultOrFinally (handler)) {
+ if (handleFilter != null) {
+ bool stopPropagation;
+ if (CodeProvider.IsCatchHandler (handler)) {
+ if (handleFilter.Catch (data, CodeProvider.CatchType (handler), out stopPropagation))
+ yield return this.CatchFilterHeaders [handler];
+ } else if (handleFilter.Filter (data, new APC (this.FilterCodeBlocks [handler], 0, null), out stopPropagation))
+ yield return this.CatchFilterHeaders [handler];
+ if (stopPropagation)
+ yield break;
+ } else
+ yield return this.CatchFilterHeaders [handler];
+
+ if (CodeProvider.IsCatchAllHandler (handler))
+ yield break;
+ }
+ }
+ yield return ExceptionExit;
+ }
+
+ protected override void PrintReferencedSubroutines (TextWriter tw, HashSet<Subroutine> subs, ILPrinter<APC> printer,
+ Func<CFGBlock, IEnumerable<LispList<Edge<CFGBlock, EdgeTag>>>> contextLookup,
+ LispList<Edge<CFGBlock, EdgeTag>> context,
+ HashSet<Pair<Subroutine, LispList<Edge<CFGBlock, EdgeTag>>>> printed)
+ {
+ foreach (Subroutine sub in this.FaultFinallySubroutines.Values) {
+ if (contextLookup == null)
+ sub.Print (tw, printer, contextLookup, context, printed);
+ else {
+ foreach (var ctx in contextLookup (sub.Entry))
+ sub.Print (tw, printer, contextLookup, ctx, printed);
+ }
+ }
+
+ base.PrintReferencedSubroutines (tw, subs, printer, contextLookup, context, printed);
+ }
+
+ protected override void PrintHandlers (TextWriter tw, BlockWithLabels<Label> block)
+ {
+ tw.Write (" Handlers: ");
+ foreach (Handler handler in ProtectingHandlerList (block).AsEnumerable ()) {
+ if (IsFaultOrFinally (handler))
+ tw.Write ("SR{0} ", this.FaultFinallySubroutines [handler].Id);
+ else
+ tw.Write ("{0} ", this.CatchFilterHeaders [handler].Index);
+ }
+ if (block != ExceptionExit)
+ tw.Write ("{0} ", ExceptionExit.Index);
+ tw.WriteLine ();
+ }
+ }
+}
--- /dev/null
+//
+// APC.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Text;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.ControlFlow {
+ struct APC : IEquatable<APC> {
+ public static readonly APC Dummy = new APC (null, 0, null);
+
+ public readonly CFGBlock Block;
+ public readonly int Index;
+ public readonly LispList<Edge<CFGBlock, EdgeTag>> SubroutineContext;
+
+ public APC (CFGBlock block, int index, LispList<Edge<CFGBlock, EdgeTag>> subroutineContext)
+ {
+ this.Block = block;
+ this.Index = index;
+ this.SubroutineContext = subroutineContext;
+ }
+
+ public IEnumerable<APC> Successors
+ {
+ get { return this.Block.Subroutine.Successors (this); }
+ }
+
+ public bool InsideContract
+ {
+ get
+ {
+ Subroutine sub = this.Block.Subroutine;
+ return sub.IsContract || sub.IsOldValue;
+ }
+ }
+
+ public bool InsideConstructor
+ {
+ get
+ {
+ LispList<Edge<CFGBlock, EdgeTag>> ctx = this.SubroutineContext;
+ CFGBlock block = this.Block;
+ while (block != null) {
+ Subroutine subroutine = block.Subroutine;
+ if (subroutine.IsConstructor)
+ return true;
+ if (subroutine.IsMethod)
+ return false;
+ if (ctx != null) {
+ block = ctx.Head.From;
+ ctx = ctx.Tail;
+ } else
+ block = null;
+ }
+ return false;
+ }
+ }
+
+ public bool InsideEnsuresInMethod
+ {
+ get
+ {
+ if (!this.Block.Subroutine.IsEnsuresOrOldValue || this.SubroutineContext == null)
+ return false;
+ foreach (var edge in this.SubroutineContext.AsEnumerable ()) {
+ if (edge.Tag == EdgeTag.Exit || edge.Tag == EdgeTag.Entry || edge.Tag.Is (EdgeTag.AfterMask))
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ public bool InsideRequiresAtCall
+ {
+ get
+ {
+ if (!this.Block.Subroutine.IsRequires || this.SubroutineContext == null)
+ return false;
+
+ foreach (var edge in this.SubroutineContext.AsEnumerable ()) {
+ if (edge.Tag == EdgeTag.Entry)
+ return false;
+ if (edge.Tag.Is (EdgeTag.BeforeMask))
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ public bool InsideEnsuresAtCall
+ {
+ get
+ {
+ if (!this.Block.Subroutine.IsRequires || this.SubroutineContext == null)
+ return false;
+
+ foreach (var edge in this.SubroutineContext.AsEnumerable ()) {
+ if (edge.Tag == EdgeTag.Exit)
+ return false;
+ if (edge.Tag.Is (EdgeTag.BeforeMask))
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ public bool InsideInvariantOnExit
+ {
+ get
+ {
+ if (!this.Block.Subroutine.IsInvariant || this.SubroutineContext == null)
+ return false;
+ foreach (var edge in this.SubroutineContext.AsEnumerable ()) {
+ if (edge.Tag == EdgeTag.Exit)
+ return true;
+ if (edge.Tag == EdgeTag.Entry || edge.Tag.Is (EdgeTag.AfterMask))
+ return false;
+ }
+
+ return false;
+ }
+ }
+
+ public bool InsideInvariantInMethod
+ {
+ get
+ {
+ if (!this.Block.Subroutine.IsInvariant || this.SubroutineContext == null)
+ return false;
+
+ foreach (var edge in this.SubroutineContext.AsEnumerable ()) {
+ if (edge.Tag == EdgeTag.Exit || edge.Tag == EdgeTag.Entry || edge.Tag.Is (EdgeTag.AfterMask))
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ public bool InsideInvariantAtCall
+ {
+ get
+ {
+ if (!this.Block.Subroutine.IsInvariant || this.SubroutineContext == null)
+ return false;
+ foreach (var edge in this.SubroutineContext.AsEnumerable ()) {
+ if (edge.Tag == EdgeTag.Exit || edge.Tag == EdgeTag.Entry)
+ return false;
+ if (edge.Tag.Is (EdgeTag.AfterMask))
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ public bool InsideOldManifestation
+ {
+ get { throw new NotImplementedException (); }
+ }
+
+ public bool InsideRequiresAtCallInsideContract
+ {
+ get
+ {
+ if (!this.Block.Subroutine.IsRequires || this.SubroutineContext == null)
+ return false;
+ for (LispList<Edge<CFGBlock, EdgeTag>> list = this.SubroutineContext; list != null; list = list.Tail) {
+ if (list.Head.Tag == EdgeTag.Entry)
+ return false;
+ if (list.Head.Tag.Is (EdgeTag.BeforeMask)) {
+ Subroutine sub = list.Head.From.Subroutine;
+ return sub.IsEnsuresOrOldValue || sub.IsRequires || sub.IsInvariant;
+ }
+ }
+ throw new InvalidOperationException ("Should not happen");
+ }
+ }
+
+ #region IEquatable<APC> Members
+ public bool Equals (APC other)
+ {
+ return (this.Block == other.Block && this.Index == other.Index && this.SubroutineContext == other.SubroutineContext);
+ }
+ #endregion
+
+ public APC Next ()
+ {
+ if (this.Index < this.Block.Count)
+ return new APC (this.Block, this.Index + 1, this.SubroutineContext);
+
+ return this;
+ }
+
+ public static APC ForEnd (CFGBlock block, LispList<Edge<CFGBlock, EdgeTag>> subroutineContext)
+ {
+ return new APC (block, block.Count, subroutineContext);
+ }
+
+ public static APC ForStart (CFGBlock block, LispList<Edge<CFGBlock, EdgeTag>> subroutineContext)
+ {
+ return new APC (block, 0, subroutineContext);
+ }
+
+ public APC LastInBlock ()
+ {
+ return ForEnd (this.Block, this.SubroutineContext);
+ }
+
+ public bool TryGetContainingMethod (out Method method)
+ {
+ LispList<Edge<CFGBlock, EdgeTag>> list = this.SubroutineContext;
+ CFGBlock block = this.Block;
+ while (block != null) {
+ var mi = block.Subroutine as IMethodInfo;
+ if (mi != null) {
+ method = mi.Method;
+ return true;
+ }
+
+ if (list != null) {
+ block = list.Head.From;
+ list = list.Tail;
+ } else
+ block = null;
+ }
+ method = default(Method);
+ return false;
+ }
+
+ public static void ToString (StringBuilder sb, LispList<Edge<CFGBlock, EdgeTag>> context)
+ {
+ bool wasFirst = false;
+ for (; context != null; context = context.Tail) {
+ if (!wasFirst) {
+ sb.Append ("{");
+ wasFirst = true;
+ } else
+ sb.Append (",");
+ Edge<CFGBlock, EdgeTag> head = context.Head;
+ sb.AppendFormat ("(SR{2} {0},{1}) [{3}]", head.From.Index, head.To.Index, head.From.Subroutine.Id, head.Tag);
+ }
+ if (!wasFirst)
+ return;
+ sb.Append ("}");
+ }
+
+ public override string ToString ()
+ {
+ var sb = new StringBuilder ();
+ sb.Append ("[");
+ sb.AppendFormat ("SR{2} {0},{1}", this.Block.Index, this.Index, this.Block.Subroutine.Id);
+ ToString (sb, this.SubroutineContext);
+ sb.Append ("]");
+
+ return sb.ToString ();
+ }
+ }
+}
--- /dev/null
+//
+// APCDecoder.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.Analysis;
+using Mono.CodeContracts.Static.ControlFlow.Subroutines;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.ControlFlow {
+ class APCDecoder : IILDecoder<APC, Dummy, Dummy, IMethodContextProvider, Dummy>, IMethodContextProvider, IMethodContext {
+ private readonly SubroutineFacade subroutine_facade;
+ private readonly ControlFlowGraph cfg;
+ private readonly IMetaDataProvider meta_data_provider;
+
+ public APCDecoder (ControlFlowGraph underlyingCFG,
+ IMetaDataProvider metaDataProvider,
+ SubroutineFacade subroutineFacade)
+ {
+ this.cfg = underlyingCFG;
+ this.meta_data_provider = metaDataProvider;
+ this.subroutine_facade = subroutineFacade;
+ }
+
+ #region IILDecoder<APC,Dummy,Dummy,IMethodContextProvider,Dummy> Members
+ public IMethodContextProvider ContextProvider
+ {
+ get { return this; }
+ }
+
+ public Result ForwardDecode<Data, Result, Visitor> (APC pc, Visitor visitor, Data data)
+ where Visitor : IILVisitor<APC, Dummy, Dummy, Data, Result>
+ {
+ return this.subroutine_facade.ForwardDecode<Data, Result, RemoveBranchDelegator<Data, Result, Visitor>>
+ (pc, new RemoveBranchDelegator<Data, Result, Visitor> (visitor, this.meta_data_provider), data);
+ }
+
+ public bool IsUnreachable (APC pc)
+ {
+ return false;
+ }
+
+ public Dummy EdgeData (APC @from, APC to)
+ {
+ return Dummy.Value;
+ }
+ #endregion
+
+ #region IMethodContextProvider Members
+ public IMethodContext MethodContext
+ {
+ get { return this; }
+ }
+ #endregion
+
+ #region IMethodContext Members
+ public Method CurrentMethod
+ {
+ get { return this.cfg.CFGMethod; }
+ }
+
+ public ICFG CFG
+ {
+ get { return this.cfg; }
+ }
+
+ public IEnumerable<Field> Modifies (Method method)
+ {
+ return this.subroutine_facade.GetModifies (method);
+ }
+
+ public IEnumerable<Method> AffectedGetters (Field field)
+ {
+ return this.subroutine_facade.GetAffectedGetters (field);
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// CFGBlock.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.ControlFlow {
+ abstract class CFGBlock {
+ public int Index;
+
+ protected CFGBlock (Subroutine subroutine, ref int idGen)
+ {
+ this.Index = idGen++;
+ Subroutine = subroutine;
+ }
+
+ public abstract int Count { get; }
+ public Subroutine Subroutine { get; private set; }
+ public int ReversePostOrderIndex { get; set; }
+
+ public APC First
+ {
+ get { return APC.ForStart (this, null); }
+ }
+
+ public APC Last
+ {
+ get { return APC.ForEnd (this, null); }
+ }
+
+ public virtual bool IsMethodCallBlock<TMethod> (out TMethod calledMethod, out bool isNewObj, out bool isVirtual)
+ {
+ calledMethod = default(TMethod);
+ isNewObj = false;
+ isVirtual = false;
+
+ return false;
+ }
+
+ public void Renumber (ref int idGen)
+ {
+ this.Index = idGen++;
+ }
+
+ public abstract int GetILOffset (APC pc);
+
+ public IEnumerable<APC> APCs ()
+ {
+ return APCs (null);
+ }
+
+ private IEnumerable<APC> APCs (LispList<Edge<CFGBlock, EdgeTag>> context)
+ {
+ for (int i = 0; i < Count; i++)
+ yield return new APC (this, i, context);
+ }
+ }
+}
--- /dev/null
+//
+// ContractFilteredCFG.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+using Mono.CodeContracts.Static.Analysis;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.ControlFlow {
+ class ContractFilteredCFG : ICFG, IEdgeSubroutineAdaptor {
+ private readonly ICFG underlying;
+
+ public ContractFilteredCFG (ICFG cfg)
+ {
+ this.underlying = cfg;
+ }
+
+ #region ICFG Members
+ public APC Entry
+ {
+ get { return this.underlying.Entry; }
+ }
+
+ public APC EntryAfterRequires
+ {
+ get { return this.underlying.EntryAfterRequires; }
+ }
+
+ public APC NormalExit
+ {
+ get { return this.underlying.NormalExit; }
+ }
+
+ public APC ExceptionExit
+ {
+ get { return this.underlying.ExceptionExit; }
+ }
+
+ public Subroutine Subroutine
+ {
+ get { return this.underlying.Subroutine; }
+ }
+
+ public APC Next (APC pc)
+ {
+ return this.underlying.Next (pc);
+ }
+
+ public bool HasSingleSuccessor (APC pc, out APC ifFound)
+ {
+ DecoratorHelper.Push<IEdgeSubroutineAdaptor> (this);
+ try {
+ return this.underlying.HasSingleSuccessor (pc, out ifFound);
+ } finally {
+ DecoratorHelper.Pop ();
+ }
+ }
+
+ public IEnumerable<APC> Successors (APC pc)
+ {
+ DecoratorHelper.Push<IEdgeSubroutineAdaptor> (this);
+ try {
+ return this.underlying.Successors (pc);
+ } finally {
+ DecoratorHelper.Pop ();
+ }
+ }
+
+ public bool HasSinglePredecessor (APC pc, out APC ifFound)
+ {
+ DecoratorHelper.Push<IEdgeSubroutineAdaptor> (this);
+ try {
+ return this.underlying.HasSinglePredecessor (pc, out ifFound);
+ } finally {
+ DecoratorHelper.Pop ();
+ }
+ }
+
+ public IEnumerable<APC> Predecessors (APC pc)
+ {
+ DecoratorHelper.Push<IEdgeSubroutineAdaptor> (this);
+ try {
+ return this.underlying.Predecessors (pc);
+ } finally {
+ DecoratorHelper.Pop ();
+ }
+ }
+
+ public bool IsJoinPoint (APC pc)
+ {
+ return this.underlying.IsJoinPoint (pc);
+ }
+
+ public bool IsSplitPoint (APC pc)
+ {
+ return this.underlying.IsSplitPoint (pc);
+ }
+
+ public bool IsBlockStart (APC pc)
+ {
+ return this.underlying.IsBlockStart (pc);
+ }
+
+ public bool IsBlockEnd (APC pc)
+ {
+ return this.underlying.IsBlockEnd (pc);
+ }
+
+ public IILDecoder<APC, Dummy, Dummy, IMethodContextProvider, Dummy> GetDecoder (IMetaDataProvider metaDataProvider)
+ {
+ return this.underlying.GetDecoder (metaDataProvider);
+ }
+
+ public void Print (TextWriter tw, ILPrinter<APC> printer,
+ Func<CFGBlock, IEnumerable<LispList<Edge<CFGBlock, EdgeTag>>>> contextLookup,
+ LispList<Edge<CFGBlock, EdgeTag>> context)
+ {
+ DecoratorHelper.Push<IEdgeSubroutineAdaptor> (this);
+ try {
+ this.underlying.Print (tw, printer, contextLookup, context);
+ } finally {
+ DecoratorHelper.Pop ();
+ }
+ }
+ #endregion
+
+ #region Implementation of IEdgeSubroutineAdaptor
+ LispList<Pair<EdgeTag, Subroutine>> IEdgeSubroutineAdaptor.GetOrdinaryEdgeSubroutinesInternal (CFGBlock @from, CFGBlock to,
+ LispList<Edge<CFGBlock, EdgeTag>> context)
+ {
+ return DecoratorHelper.Inner<IEdgeSubroutineAdaptor> (this)
+ .GetOrdinaryEdgeSubroutinesInternal (from, to, context).Where ((pair) => !pair.Value.IsContract && !pair.Value.IsOldValue);
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// ControlFlowGraph.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.Analysis;
+using Mono.CodeContracts.Static.ControlFlow.Subroutines;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.ControlFlow {
+ class ControlFlowGraph : ICFG {
+ private readonly object method_repository;
+ private readonly Subroutine method_subroutine;
+
+ public ControlFlowGraph (Subroutine subroutine, object methodRepository)
+ {
+ this.method_subroutine = subroutine;
+ this.method_repository = methodRepository;
+ }
+
+ private CFGBlock EntryBlock
+ {
+ get { return this.method_subroutine.Entry; }
+ }
+
+ private CFGBlock ExitBlock
+ {
+ get { return this.method_subroutine.Exit; }
+ }
+
+ private CFGBlock ExceptionExitBlock
+ {
+ get { return this.method_subroutine.ExceptionExit; }
+ }
+
+ public Method CFGMethod
+ {
+ get
+ {
+ var methodInfo = this.method_subroutine as IMethodInfo;
+ if (methodInfo != null)
+ return methodInfo.Method;
+ throw new InvalidOperationException ("CFG has bad subroutine that is not a method");
+ }
+ }
+
+ #region ICFG Members
+ public APC Entry
+ {
+ get { return new APC (EntryBlock, 0, null); }
+ }
+
+ public APC EntryAfterRequires
+ {
+ get { return new APC (this.method_subroutine.EntryAfterRequires, 0, null); }
+ }
+
+ public APC NormalExit
+ {
+ get { return new APC (ExitBlock, 0, null); }
+ }
+
+ public APC ExceptionExit
+ {
+ get { return new APC (ExceptionExitBlock, 0, null); }
+ }
+
+ public Subroutine Subroutine
+ {
+ get { return this.method_subroutine; }
+ }
+
+ public APC Next (APC pc)
+ {
+ APC next;
+
+ if (HasSingleSuccessor (pc, out next))
+ return next;
+
+ return pc;
+ }
+
+ public bool HasSingleSuccessor (APC pc, out APC ifFound)
+ {
+ return pc.Block.Subroutine.HasSingleSuccessor (pc, out ifFound);
+ }
+
+ public IEnumerable<APC> Successors (APC pc)
+ {
+ return pc.Block.Subroutine.Successors (pc);
+ }
+
+ public bool HasSinglePredecessor (APC pc, out APC ifFound)
+ {
+ return pc.Block.Subroutine.HasSinglePredecessor (pc, out ifFound);
+ }
+
+ public IEnumerable<APC> Predecessors (APC pc)
+ {
+ return pc.Block.Subroutine.Predecessors (pc);
+ }
+
+ public bool IsJoinPoint (APC pc)
+ {
+ if (pc.Index != 0)
+ return false;
+
+ return IsJoinPoint (pc.Block);
+ }
+
+ public bool IsSplitPoint (APC pc)
+ {
+ if (pc.Index != pc.Block.Count)
+ return false;
+
+ return IsSplitPoint (pc.Block);
+ }
+
+ public bool IsBlockStart (APC pc)
+ {
+ return pc.Index == 0;
+ }
+
+ public bool IsBlockEnd (APC pc)
+ {
+ return pc.Index == pc.Block.Count;
+ }
+
+ public IILDecoder<APC, Dummy, Dummy, IMethodContextProvider, Dummy> GetDecoder (IMetaDataProvider metaDataProvider)
+ {
+ var methodRepository = this.method_repository as SubroutineFacade;
+ return new APCDecoder (this, metaDataProvider, methodRepository);
+ }
+
+ public void Print (TextWriter tw, ILPrinter<APC> printer,
+ Func<CFGBlock, IEnumerable<LispList<Edge<CFGBlock, EdgeTag>>>> contextLookup,
+ LispList<Edge<CFGBlock, EdgeTag>> context)
+ {
+ var set = new HashSet<Pair<Subroutine, LispList<Edge<CFGBlock, EdgeTag>>>> ();
+ this.method_subroutine.Print (tw, printer, contextLookup, context, set);
+ }
+ #endregion
+
+ private bool IsJoinPoint (CFGBlock block)
+ {
+ return block.Subroutine.IsJoinPoint (block);
+ }
+
+ private bool IsSplitPoint (CFGBlock block)
+ {
+ return block.Subroutine.IsSplitPoint (block);
+ }
+
+ public IGraph<APC, Dummy> AsForwardGraph ()
+ {
+ return new GraphWrapper<APC, Dummy> (new APC[0], (pc) => SuccessorsEdges (pc));
+ }
+
+ private IEnumerable<Pair<Dummy, APC>> SuccessorsEdges (APC pc)
+ {
+ APC last = pc.LastInBlock ();
+ foreach (APC succ in Successors (last))
+ yield return new Pair<Dummy, APC> (Dummy.Value, succ);
+ }
+ }
+}
--- /dev/null
+//
+// Edge.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.ControlFlow {
+ struct Edge<TNode, TTag> {
+ public TNode From;
+ public TTag Tag;
+ public TNode To;
+
+ public Edge (TNode from, TNode to, TTag tag)
+ {
+ this.From = from;
+ this.To = to;
+ this.Tag = tag;
+ }
+
+ public override string ToString ()
+ {
+ return string.Format ("({0} --'{1}'--> {2})", this.From, this.Tag, this.To);
+ }
+
+ public Edge<TNode, TTag> Reversed ()
+ {
+ return new Edge<TNode, TTag> (this.To, this.From, this.Tag);
+ }
+ }
+}
--- /dev/null
+//
+// EdgeMap.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+using System.Collections.Generic;
+using System.Linq;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.ControlFlow {
+ class EdgeMap<Tag> : IEnumerable<Edge<CFGBlock, Tag>>, IGraph<CFGBlock, Tag> {
+ private readonly List<Edge<CFGBlock, Tag>> edges;
+
+ public EdgeMap (List<Edge<CFGBlock, Tag>> edges)
+ {
+ this.edges = edges;
+ Resort ();
+ }
+
+ public ICollection<Pair<Tag, CFGBlock>> this [CFGBlock node]
+ {
+ get { return new Successors (this, FindStartIndex (node)); }
+ }
+
+ #region IEnumerable<Edge<CFGBlock,Tag>> Members
+ public IEnumerator<Edge<CFGBlock, Tag>> GetEnumerator ()
+ {
+ return this.edges.GetEnumerator ();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator ()
+ {
+ return GetEnumerator ();
+ }
+ #endregion
+
+ #region IGraph<CFGBlock,Tag> Members
+ IEnumerable<CFGBlock> IGraph<CFGBlock, Tag>.Nodes
+ {
+ get { throw new InvalidOperationException(); }
+ }
+
+ IEnumerable<Pair<Tag, CFGBlock>> IGraph<CFGBlock, Tag>.Successors (CFGBlock node)
+ {
+ return this [node];
+ }
+ #endregion
+
+ public EdgeMap<Tag> Reverse ()
+ {
+ var newEdges = new List<Edge<CFGBlock, Tag>> (this.edges.Count);
+
+ newEdges.AddRange (this.edges.Select (edge => edge.Reversed ()));
+
+ return new EdgeMap<Tag> (newEdges);
+ }
+
+ private static int CompareFirstBlockIndex (Edge<CFGBlock, Tag> edge1, Edge<CFGBlock, Tag> edge2)
+ {
+ int cmp = edge1.From.Index - edge2.From.Index;
+ if (cmp == 0)
+ cmp = edge1.To.Index - edge2.To.Index;
+
+ return cmp;
+ }
+
+ private int FindStartIndex (CFGBlock from)
+ {
+ //binary search
+ int l = 0;
+ int r = this.edges.Count;
+ while (l < r) {
+ int median = (l + r)/2;
+ int medianBlockIndex = this.edges [median].From.Index;
+
+ if (medianBlockIndex == from.Index) {
+ while (median > 0 && this.edges [median - 1].From.Index == medianBlockIndex)
+ --median;
+ return median;
+ }
+
+ if (medianBlockIndex < from.Index)
+ l = median + 1;
+ else
+ r = median;
+ }
+
+ return this.edges.Count;
+ }
+
+ public void Filter (Predicate<Edge<CFGBlock, Tag>> keep)
+ {
+ var notKeepEdges = new List<int> ();
+ for (int i = 0; i < this.edges.Count; i++) {
+ if (!keep (this.edges [i]))
+ notKeepEdges.Add (i);
+ }
+
+ if (notKeepEdges.Count == 0)
+ return;
+
+ int ix = 0;
+ foreach (int i in notKeepEdges) {
+ this.edges.RemoveAt (i - ix);
+ ix++;
+ }
+ }
+
+ public void Resort ()
+ {
+ this.edges.Sort (CompareFirstBlockIndex);
+ }
+
+ #region Nested type: Successors
+ private struct Successors : ICollection<Pair<Tag, CFGBlock>> {
+ private readonly int start_index;
+ private readonly EdgeMap<Tag> underlying;
+
+ public Successors (EdgeMap<Tag> underlying, int startIndex)
+ {
+ this.underlying = underlying;
+ this.start_index = startIndex;
+ }
+
+ #region ICollection<Pair<Tag,CFGBlock>> Members
+ public IEnumerator<Pair<Tag, CFGBlock>> GetEnumerator ()
+ {
+ List<Edge<CFGBlock, Tag>> edges = this.underlying.edges;
+ if (this.start_index < edges.Count) {
+ int index = this.start_index;
+ int blockIndex = edges [index].From.Index;
+ do {
+ yield return new Pair<Tag, CFGBlock> (edges [index].Tag, edges [index].To);
+ ++index;
+ } while (index < edges.Count && edges [index].From.Index == blockIndex);
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator ()
+ {
+ return GetEnumerator ();
+ }
+
+ public void Add (Pair<Tag, CFGBlock> item)
+ {
+ throw new InvalidOperationException ();
+ }
+
+ public void Clear ()
+ {
+ throw new InvalidOperationException ();
+ }
+
+ public bool Contains (Pair<Tag, CFGBlock> item)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public void CopyTo (Pair<Tag, CFGBlock>[] array, int arrayIndex)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public bool Remove (Pair<Tag, CFGBlock> item)
+ {
+ throw new InvalidOperationException ();
+ }
+
+ public int Count
+ {
+ get
+ {
+ int index = this.start_index;
+ List<Edge<CFGBlock, Tag>> edges = this.underlying.edges;
+ if (index >= edges.Count)
+ return 0;
+ int blockIndex = edges [index].From.Index;
+
+ int count = 0;
+ do {
+ ++count;
+ ++index;
+ } while (index < edges.Count && edges [index].From.Index == blockIndex);
+
+ return count;
+ }
+ }
+
+ public bool IsReadOnly
+ {
+ get { return true; }
+ }
+ #endregion
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// EdgeTag.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.ControlFlow {
+ [Flags]
+ enum EdgeTag : uint {
+ None = 0,
+ FallThroughReturn = 1,
+ Branch = 1 << 1,
+ Return = 1 << 2,
+ EndSubroutine = 1 << 3,
+ True = 1 << 4,
+ False = 1 << 5,
+ FallThrough = 1 << 6,
+ Entry = 1 << 7,
+ AfterNewObj = 1 << 8 | AfterMask,
+ AfterCall = 1 << 9 | AfterMask,
+ Exit = 1 << 10,
+ Finally = 1 << 11,
+ Inherited = 1 << 12 | InheritedMask,
+ BeforeCall = 1 << 13 | BeforeMask,
+ BeforeNewObj = 1 << 14 | BeforeMask,
+ Requires = 1 << 15,
+ Assume = 1 << 16,
+ Assert = 1 << 17,
+ Invariant = 1 << 18,
+ OldManifest = 1 << 19 | OldMask,
+ Old = 1 << 20 | OldMask,
+ EndOld = 1 << 21,
+
+ BeforeMask = 1 << 22,
+ AfterMask = 1 << 23,
+ InheritedMask = 1 << 24,
+ ExtraMask = 1 << 25,
+ OldMask = 1 << 26,
+ }
+}
--- /dev/null
+//
+// EdgeTagExtensions.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.ControlFlow {
+ static class EdgeTagExtensions {
+ public static bool Is (this EdgeTag current, EdgeTag mask)
+ {
+ return (current & mask) != EdgeTag.None;
+ }
+ }
+}
--- /dev/null
+//
+// EdgeVisitor.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.ControlFlow
+{
+ delegate void EdgeVisitor<Node, Info>(Node source, Info info, Node target);
+}
\ No newline at end of file
--- /dev/null
+//
+// ICFG.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+using Mono.CodeContracts.Static.Analysis;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.ControlFlow {
+ interface ICFG {
+ APC Entry { get; }
+ APC EntryAfterRequires { get; }
+ APC NormalExit { get; }
+ APC ExceptionExit { get; }
+ Subroutine Subroutine { get; }
+
+ APC Next (APC pc);
+
+ IEnumerable<APC> Successors (APC pc);
+ bool HasSingleSuccessor (APC pc, out APC ifFound);
+
+ IEnumerable<APC> Predecessors (APC pc);
+ bool HasSinglePredecessor (APC pc, out APC ifFound);
+
+ bool IsJoinPoint (APC pc);
+ bool IsSplitPoint (APC pc);
+
+ bool IsBlockStart (APC pc);
+ bool IsBlockEnd (APC pc);
+
+ IILDecoder<APC, Dummy, Dummy, IMethodContextProvider, Dummy> GetDecoder (IMetaDataProvider metaDataProvider);
+
+ void Print (TextWriter tw, ILPrinter<APC> printer,
+ Func<CFGBlock, IEnumerable<LispList<Edge<CFGBlock, EdgeTag>>>> contextLookup,
+ LispList<Edge<CFGBlock, EdgeTag>> context);
+ }
+}
--- /dev/null
+//
+// IConstantInfo.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.ControlFlow {
+ interface IEdgeSubroutineAdaptor {
+ LispList<Pair<EdgeTag, Subroutine>> GetOrdinaryEdgeSubroutinesInternal (CFGBlock @from, CFGBlock to, LispList<Edge<CFGBlock, EdgeTag>> context);
+ }
+}
--- /dev/null
+//
+// IHandlerFilter.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+
+namespace Mono.CodeContracts.Static.ControlFlow {
+ interface IHandlerFilter<Data> {
+ bool Catch (Data data, TypeNode exception, out bool stopPropagation);
+ bool Filter (Data data, APC filterCode, out bool stopPropagation);
+ }
+}
--- /dev/null
+//
+// IMethodInfo.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+
+namespace Mono.CodeContracts.Static.ControlFlow {
+ interface IMethodInfo {
+ Method Method { get; }
+ }
+}
--- /dev/null
+//
+// IStackInfo.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.ControlFlow {
+ interface IStackInfo {
+ bool IsCallOnThis (APC pc);
+ }
+}
--- /dev/null
+//
+// RemoveBranchDelegator.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.ControlFlow {
+ /// <summary>
+ /// This class wraps underlying visitor.
+ /// Replaces: branches to nop; branchCond to binary.
+ ///
+ /// EdgeTag.Requires: (inside method) => assume, (outside method) => assert
+ /// EdgeTag.Ensures: (inside method) => assert, (outside method) => assume
+ /// </summary>
+ struct RemoveBranchDelegator<Data, Result, Visitor> : IILVisitor<APC, Dummy, Dummy, Data, Result>
+ where Visitor : IILVisitor<APC, Dummy, Dummy, Data, Result> {
+ private readonly IMetaDataProvider meta_data_provider;
+ private readonly Visitor visitor;
+
+ public RemoveBranchDelegator (Visitor visitor,
+ IMetaDataProvider metaDataProvider)
+ {
+ this.visitor = visitor;
+ this.meta_data_provider = metaDataProvider;
+ }
+
+ #region IILVisitor<APC,Dummy,Dummy,Data,Result> Members
+ public Result Binary (APC pc, BinaryOperator op, Dummy dest, Dummy operand1, Dummy operand2, Data data)
+ {
+ return this.visitor.Binary (pc, op, dest, operand1, operand2, data);
+ }
+
+ public Result Isinst (APC pc, TypeNode type, Dummy dest, Dummy obj, Data data)
+ {
+ return this.visitor.Isinst (pc, type, dest, obj, data);
+ }
+
+ public Result LoadNull (APC pc, Dummy dest, Data polarity)
+ {
+ return this.visitor.LoadNull (pc, dest, polarity);
+ }
+
+ public Result LoadConst (APC pc, TypeNode type, object constant, Dummy dest, Data data)
+ {
+ return this.visitor.LoadConst (pc, type, constant, dest, data);
+ }
+
+ public Result Sizeof (APC pc, TypeNode type, Dummy dest, Data data)
+ {
+ return this.visitor.Sizeof (pc, type, dest, data);
+ }
+
+ public Result Unary (APC pc, UnaryOperator op, bool unsigned, Dummy dest, Dummy source, Data data)
+ {
+ return this.visitor.Unary (pc, op, unsigned, dest, source, data);
+ }
+
+ public Result Entry (APC pc, Method method, Data data)
+ {
+ return this.visitor.Entry (pc, method, data);
+ }
+
+ public Result Assume (APC pc, EdgeTag tag, Dummy condition, Data data)
+ {
+ if (tag == EdgeTag.Requires && pc.InsideRequiresAtCall || tag == EdgeTag.Invariant && pc.InsideInvariantOnExit)
+ return this.visitor.Assert (pc, tag, condition, data);
+
+ return this.visitor.Assume (pc, tag, condition, data);
+ }
+
+ public Result Assert (APC pc, EdgeTag tag, Dummy condition, Data data)
+ {
+ if (pc.InsideEnsuresAtCall)
+ return this.visitor.Assume (pc, tag, condition, data);
+
+ return this.visitor.Assert (pc, tag, condition, data);
+ }
+
+ public Result BeginOld (APC pc, APC matchingEnd, Data data)
+ {
+ return this.visitor.BeginOld (pc, matchingEnd, data);
+ }
+
+ public Result EndOld (APC pc, APC matchingBegin, TypeNode type, Dummy dest, Dummy source, Data data)
+ {
+ return this.visitor.EndOld (pc, matchingBegin, type, dest, source, data);
+ }
+
+ public Result LoadStack (APC pc, int offset, Dummy dest, Dummy source, bool isOld, Data data)
+ {
+ return this.visitor.LoadStack (pc, offset, dest, source, isOld, data);
+ }
+
+ public Result LoadStackAddress (APC pc, int offset, Dummy dest, Dummy source, TypeNode type, bool isOld, Data data)
+ {
+ return this.visitor.LoadStackAddress (pc, offset, dest, source, type, isOld, data);
+ }
+
+ public Result LoadResult (APC pc, TypeNode type, Dummy dest, Dummy source, Data data)
+ {
+ return this.visitor.LoadResult (pc, type, dest, source, data);
+ }
+
+ public Result Arglist (APC pc, Dummy dest, Data data)
+ {
+ return this.visitor.Arglist (pc, dest, data);
+ }
+
+ public Result Branch (APC pc, APC target, bool leavesExceptionBlock, Data data)
+ {
+ return this.visitor.Nop (pc, data);
+ }
+
+ public Result BranchCond (APC pc, APC target, BranchOperator bop, Dummy value1, Dummy value2, Data data)
+ {
+ Dummy dest = Dummy.Value;
+ switch (bop) {
+ case BranchOperator.Beq:
+ return this.visitor.Binary (pc, BinaryOperator.Ceq, dest, value1, value2, data);
+ case BranchOperator.Bge:
+ return this.visitor.Binary (pc, BinaryOperator.Cge, dest, value1, value2, data);
+ case BranchOperator.Bge_Un:
+ return this.visitor.Binary (pc, BinaryOperator.Cge_Un, dest, value1, value2, data);
+ case BranchOperator.Bgt:
+ return this.visitor.Binary (pc, BinaryOperator.Cgt, dest, value1, value2, data);
+ case BranchOperator.Bgt_Un:
+ return this.visitor.Binary (pc, BinaryOperator.Cgt_Un, dest, value1, value2, data);
+ case BranchOperator.Ble:
+ return this.visitor.Binary (pc, BinaryOperator.Cle, dest, value1, value2, data);
+ case BranchOperator.Ble_Un:
+ return this.visitor.Binary (pc, BinaryOperator.Cle_Un, dest, value1, value2, data);
+ case BranchOperator.Blt:
+ return this.visitor.Binary (pc, BinaryOperator.Clt, dest, value1, value2, data);
+ case BranchOperator.Blt_Un:
+ return this.visitor.Binary (pc, BinaryOperator.Clt_Un, dest, value1, value2, data);
+ case BranchOperator.Bne_un:
+ return this.visitor.Binary (pc, BinaryOperator.Cne_Un, dest, value1, value2, data);
+ default:
+ return this.visitor.Nop (pc, data);
+ }
+ }
+
+ public Result BranchTrue (APC pc, APC target, Dummy cond, Data data)
+ {
+ return this.visitor.Nop (pc, data);
+ }
+
+ public Result BranchFalse (APC pc, APC target, Dummy cond, Data data)
+ {
+ return this.visitor.Nop (pc, data);
+ }
+
+ public Result Break (APC pc, Data data)
+ {
+ return this.visitor.Break (pc, data);
+ }
+
+ public Result Call<TypeList, ArgList> (APC pc, Method method, bool virt, TypeList extraVarargs, Dummy dest, ArgList args, Data data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<Dummy>
+ {
+ TypeNode declaringType = this.meta_data_provider.DeclaringType (method);
+ if (MethodIsReferenceEquals (method, args, declaringType))
+ return this.visitor.Binary (pc, BinaryOperator.Ceq, dest, args [0], args [1], data);
+
+ return this.visitor.Call (pc, method, virt, extraVarargs, dest, args, data);
+ }
+
+ public Result Calli<TypeList, ArgList> (APC pc, TypeNode returnType, TypeList argTypes, bool instance, Dummy dest, Dummy functionPointer, ArgList args, Data data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<Dummy>
+ {
+ return this.visitor.Calli (pc, returnType, argTypes, instance, dest, functionPointer, args, data);
+ }
+
+ public Result CheckFinite (APC pc, Dummy dest, Dummy source, Data data)
+ {
+ return this.visitor.CheckFinite (pc, dest, source, data);
+ }
+
+ public Result CopyBlock (APC pc, Dummy destAddress, Dummy srcAddress, Dummy len, Data data)
+ {
+ return this.visitor.CopyBlock (pc, destAddress, srcAddress, len, data);
+ }
+
+ public Result EndFilter (APC pc, Dummy decision, Data data)
+ {
+ return this.visitor.EndFilter (pc, decision, data);
+ }
+
+ public Result EndFinally (APC pc, Data data)
+ {
+ return this.visitor.EndFinally (pc, data);
+ }
+
+ public Result Jmp (APC pc, Method method, Data data)
+ {
+ return this.visitor.Jmp (pc, method, data);
+ }
+
+ public Result LoadArg (APC pc, Parameter argument, bool isOld, Dummy dest, Data data)
+ {
+ return this.visitor.LoadArg (pc, argument, isOld, dest, data);
+ }
+
+ public Result LoadArgAddress (APC pc, Parameter argument, bool isOld, Dummy dest, Data data)
+ {
+ return this.visitor.LoadArgAddress (pc, argument, isOld, dest, data);
+ }
+
+ public Result LoadLocal (APC pc, Local local, Dummy dest, Data data)
+ {
+ return this.visitor.LoadLocal (pc, local, dest, data);
+ }
+
+ public Result LoadLocalAddress (APC pc, Local local, Dummy dest, Data data)
+ {
+ return this.visitor.LoadLocalAddress (pc, local, dest, data);
+ }
+
+ public Result LoadElement (APC pc, TypeNode type, Dummy dest, Dummy array, Dummy index, Data data)
+ {
+ return this.visitor.LoadElement (pc, type, dest, array, index, data);
+ }
+
+ public Result LoadField (APC pc, Field field, Dummy dest, Dummy obj, Data data)
+ {
+ return this.visitor.LoadField (pc, field, dest, obj, data);
+ }
+
+ public Result LoadFieldAddress (APC pc, Field field, Dummy dest, Dummy obj, Data data)
+ {
+ return this.visitor.LoadFieldAddress (pc, field, dest, obj, data);
+ }
+
+ public Result LoadLength (APC pc, Dummy dest, Dummy array, Data data)
+ {
+ return this.visitor.LoadLength (pc, dest, array, data);
+ }
+
+ public Result LoadStaticField (APC pc, Field field, Dummy dest, Data data)
+ {
+ return this.visitor.LoadStaticField (pc, field, dest, data);
+ }
+
+ public Result LoadStaticFieldAddress (APC pc, Field field, Dummy dest, Data data)
+ {
+ return this.visitor.LoadStaticFieldAddress (pc, field, dest, data);
+ }
+
+ public Result LoadTypeToken (APC pc, TypeNode type, Dummy dest, Data data)
+ {
+ return this.visitor.LoadTypeToken (pc, type, dest, data);
+ }
+
+ public Result LoadFieldToken (APC pc, Field type, Dummy dest, Data data)
+ {
+ return this.visitor.LoadFieldToken (pc, type, dest, data);
+ }
+
+ public Result LoadMethodToken (APC pc, Method type, Dummy dest, Data data)
+ {
+ return this.visitor.LoadMethodToken (pc, type, dest, data);
+ }
+
+ public Result Nop (APC pc, Data data)
+ {
+ return this.visitor.Nop (pc, data);
+ }
+
+ public Result Pop (APC pc, Dummy source, Data data)
+ {
+ return this.visitor.Pop (pc, source, data);
+ }
+
+ public Result Return (APC pc, Dummy source, Data data)
+ {
+ return this.visitor.Return (pc, source, data);
+ }
+
+ public Result StoreArg (APC pc, Parameter argument, Dummy source, Data data)
+ {
+ return this.visitor.StoreArg (pc, argument, source, data);
+ }
+
+ public Result StoreLocal (APC pc, Local local, Dummy source, Data data)
+ {
+ return this.visitor.StoreLocal (pc, local, source, data);
+ }
+
+ public Result StoreElement (APC pc, TypeNode type, Dummy array, Dummy index, Dummy value, Data data)
+ {
+ return this.visitor.StoreElement (pc, type, array, index, value, data);
+ }
+
+ public Result StoreField (APC pc, Field field, Dummy obj, Dummy value, Data data)
+ {
+ return this.visitor.StoreField (pc, field, obj, value, data);
+ }
+
+ public Result StoreStaticField (APC pc, Field field, Dummy value, Data data)
+ {
+ return this.visitor.StoreStaticField (pc, field, value, data);
+ }
+
+ public Result Switch (APC pc, TypeNode type, IEnumerable<Pair<object, APC>> cases, Dummy value, Data data)
+ {
+ return this.visitor.Nop (pc, data);
+ }
+
+ public Result Box (APC pc, TypeNode type, Dummy dest, Dummy source, Data data)
+ {
+ return this.visitor.Box (pc, type, dest, source, data);
+ }
+
+ public Result ConstrainedCallvirt<TypeList, ArgList> (APC pc, Method method, TypeNode constraint, TypeList extraVarargs, Dummy dest, ArgList args, Data data)
+ where TypeList : IIndexable<TypeNode>
+ where ArgList : IIndexable<Dummy>
+ {
+ return this.visitor.ConstrainedCallvirt (pc, method, constraint, extraVarargs, dest, args, data);
+ }
+
+ public Result CastClass (APC pc, TypeNode type, Dummy dest, Dummy obj, Data data)
+ {
+ return this.visitor.CastClass (pc, type, dest, obj, data);
+ }
+
+ public Result CopyObj (APC pc, TypeNode type, Dummy destPtr, Dummy sourcePtr, Data data)
+ {
+ return this.visitor.CopyObj (pc, type, destPtr, sourcePtr, data);
+ }
+
+ public Result Initobj (APC pc, TypeNode type, Dummy ptr, Data data)
+ {
+ return this.visitor.Initobj (pc, type, ptr, data);
+ }
+
+ public Result NewArray<ArgList> (APC pc, TypeNode type, Dummy dest, ArgList lengths, Data data) where ArgList : IIndexable<Dummy>
+ {
+ return this.visitor.NewArray (pc, type, dest, lengths, data);
+ }
+
+ public Result NewObj<ArgList> (APC pc, Method ctor, Dummy dest, ArgList args, Data data) where ArgList : IIndexable<Dummy>
+ {
+ return this.visitor.NewObj (pc, ctor, dest, args, data);
+ }
+
+ public Result MkRefAny (APC pc, TypeNode type, Dummy dest, Dummy obj, Data data)
+ {
+ return this.visitor.MkRefAny (pc, type, dest, obj, data);
+ }
+
+ public Result RefAnyType (APC pc, Dummy dest, Dummy source, Data data)
+ {
+ return this.visitor.RefAnyType (pc, dest, source, data);
+ }
+
+ public Result RefAnyVal (APC pc, TypeNode type, Dummy dest, Dummy source, Data data)
+ {
+ return this.visitor.RefAnyVal (pc, type, dest, source, data);
+ }
+
+ public Result Rethrow (APC pc, Data data)
+ {
+ return this.visitor.Rethrow (pc, data);
+ }
+
+ public Result Throw (APC pc, Dummy exception, Data data)
+ {
+ return this.visitor.Throw (pc, exception, data);
+ }
+
+ public Result Unbox (APC pc, TypeNode type, Dummy dest, Dummy obj, Data data)
+ {
+ return this.visitor.Unbox (pc, type, dest, obj, data);
+ }
+
+ public Result UnboxAny (APC pc, TypeNode type, Dummy dest, Dummy obj, Data data)
+ {
+ return this.visitor.UnboxAny (pc, type, dest, obj, data);
+ }
+ #endregion
+
+ private bool MethodIsReferenceEquals<ArgList> (Method method, ArgList args, TypeNode declaringType)
+ where ArgList : IIndexable<Dummy>
+ {
+ return args.Count == 2 && this.meta_data_provider.IsStatic (method)
+ && this.meta_data_provider.Equal (declaringType, this.meta_data_provider.System_Object)
+ && this.meta_data_provider.Name (method) == "ReferenceEquals";
+ }
+ }
+}
--- /dev/null
+//
+// Subroutine.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+using Mono.CodeContracts.Static.Analysis;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.ControlFlow {
+ abstract class Subroutine : ITypedProperties, IEquatable<Subroutine> {
+ private static int _subroutineIdGenerator;
+ private readonly TypedProperties properties = new TypedProperties ();
+ private readonly int subroutine_id = _subroutineIdGenerator++;
+
+ public virtual SubroutineKind Kind
+ {
+ get { return SubroutineKind.Unknown; }
+ }
+
+ public int Id
+ {
+ get { return this.subroutine_id; }
+ }
+
+ public abstract CFGBlock Entry { get; }
+ public abstract CFGBlock EntryAfterRequires { get; }
+ public abstract CFGBlock Exit { get; }
+ public abstract CFGBlock ExceptionExit { get; }
+ public abstract string Name { get; }
+ public abstract int BlockCount { get; }
+ public abstract IEnumerable<CFGBlock> Blocks { get; }
+
+ public virtual bool IsRequires
+ {
+ get { return false; }
+ }
+
+ public virtual bool IsEnsures
+ {
+ get { return false; }
+ }
+
+ public virtual bool IsOldValue
+ {
+ get { return false; }
+ }
+
+ public virtual bool IsMethod
+ {
+ get { return false; }
+ }
+
+ public virtual bool IsConstructor
+ {
+ get { return false; }
+ }
+
+ public virtual bool IsInvariant
+ {
+ get { return false; }
+ }
+
+ public virtual bool IsContract
+ {
+ get { return false; }
+ }
+
+ public bool IsEnsuresOrOldValue
+ {
+ get { return IsEnsures || IsOldValue; }
+ }
+
+ public abstract EdgeMap<EdgeTag> SuccessorEdges { get; }
+ public abstract EdgeMap<EdgeTag> PredecessorEdges { get; }
+ public abstract DepthFirst.Visitor<CFGBlock, Dummy> EdgeInfo { get; }
+
+ public virtual bool IsFaultFinally
+ {
+ get { return false; }
+ }
+
+ public abstract bool HasReturnValue { get; }
+ public abstract bool HasContextDependentStackDepth { get; }
+
+ public abstract int StackDelta { get; }
+
+ #region ITypedProperties Members
+ public bool TryGetValue<T> (TypedKey key, out T value)
+ {
+ return this.properties.TryGetValue (key, out value);
+ }
+ #endregion
+
+ #region Implementation of ITypedProperties
+ public bool Contains (TypedKey key)
+ {
+ return this.properties.Contains (key);
+ }
+
+ public void Add<T> (TypedKey key, T value)
+ {
+ this.properties.Add (key, value);
+ }
+ #endregion
+
+ public override string ToString ()
+ {
+ return string.Format ("SR {0}: BlockCount:{1}, Kind:{2}", Id, BlockCount, Kind);
+ }
+
+ public abstract IEnumerable<CFGBlock> SuccessorBlocks (CFGBlock block);
+
+ public IEnumerable<Pair<EdgeTag, CFGBlock>> SuccessorEdgesFor (CFGBlock block)
+ {
+ return SuccessorEdges [block];
+ }
+
+ public abstract IEnumerable<CFGBlock> PredecessorBlocks (CFGBlock block);
+
+ public abstract bool IsJoinPoint (CFGBlock block);
+ public abstract bool IsSplitPoint (CFGBlock block);
+ public abstract bool HasSingleSuccessor (APC point, out APC ifFound);
+ public abstract bool HasSinglePredecessor (APC point, out APC ifFound);
+
+ public abstract void AddEdgeSubroutine (CFGBlock from, CFGBlock to, Subroutine subroutine, EdgeTag tag);
+
+ public abstract IEnumerable<APC> Successors (APC pc);
+ public abstract IEnumerable<APC> Predecessors (APC pc);
+
+ public abstract bool IsSubroutineEnd (CFGBlock block);
+ public abstract bool IsSubroutineStart (CFGBlock block);
+ public abstract bool IsCatchFilterHeader (CFGBlock block);
+
+ public abstract APC ComputeTargetFinallyContext (APC pc, CFGBlock succ);
+ public abstract LispList<Pair<EdgeTag, Subroutine>> EdgeSubroutinesOuterToInner (CFGBlock current, CFGBlock succ, out bool isExceptionHandlerEdge, LispList<Edge<CFGBlock, EdgeTag>> context);
+ public abstract LispList<Pair<EdgeTag, Subroutine>> GetOrdinaryEdgeSubroutines (CFGBlock current, CFGBlock succ, LispList<Edge<CFGBlock, EdgeTag>> context);
+ public abstract void Initialize ();
+ public abstract IEnumerable<Subroutine> UsedSubroutines (HashSet<int> alreadySeen);
+
+ public IEnumerable<Subroutine> UsedSubroutines ()
+ {
+ return UsedSubroutines (new HashSet<int> ());
+ }
+
+ public abstract IEnumerable<CFGBlock> ExceptionHandlers<Data, Type> (CFGBlock block, Subroutine innerSubroutine,
+ Data data, IHandlerFilter<Data> handlerPredicate);
+
+ public abstract void Print (TextWriter tw, ILPrinter<APC> printer,
+ Func<CFGBlock, IEnumerable<LispList<Edge<CFGBlock, EdgeTag>>>> contextLookup,
+ LispList<Edge<CFGBlock, EdgeTag>> context,
+ HashSet<Pair<Subroutine, LispList<Edge<CFGBlock, EdgeTag>>>> set);
+
+ #region Implementation of IEquatable<Subroutine>
+ public bool Equals (Subroutine other)
+ {
+ return Id == other.Id;
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// SubroutineKind.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.ControlFlow {
+ enum SubroutineKind {
+ Unknown,
+ Requires,
+ Ensures,
+ Method,
+ Entry,
+ Fault,
+ Finally,
+ Simple,
+ Old
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// DataFlowAnalysisBase.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.DataFlowAnalysis {
+ abstract class DataFlowAnalysisBase<AState> :
+ IEqualityComparer<APC> {
+ protected ICFG CFG;
+ protected Dictionary<APC, AState> JoinState;
+ protected PriorityQueue<APC> pending;
+ private IWidenStrategy widen_strategy;
+
+ protected DataFlowAnalysisBase (ICFG cfg)
+ {
+ this.CFG = cfg;
+ this.pending = new PriorityQueue<APC> (WorkingListComparer);
+ this.JoinState = new Dictionary<APC, AState> (this);
+ this.widen_strategy = null;
+ }
+
+ #region IEqualityComparer<APC> Members
+ bool IEqualityComparer<APC>.Equals (APC x, APC y)
+ {
+ return x.Equals (y);
+ }
+
+ int IEqualityComparer<APC>.GetHashCode (APC obj)
+ {
+ return obj.GetHashCode ();
+ }
+ #endregion
+
+ public void Initialize (APC entryPoint, AState state)
+ {
+ this.JoinState.Add (entryPoint, state);
+ this.pending.Enqueue (entryPoint);
+ }
+
+ public virtual void ComputeFixPoint ()
+ {
+ this.widen_strategy = new EdgeBasedWidening (20);
+
+ while (this.pending.Count > 0) {
+ APC next = this.pending.Dequeue ();
+ AState state = MutableVersion (this.JoinState [next], next);
+
+ APC cur;
+ bool repeatOuter = false;
+ do {
+ cur = next;
+ if (!IsBottom (cur, state)) {
+ state = Transfer (cur, state);
+ } else {
+ repeatOuter = true;
+ break;
+ }
+ } while (HasSingleSuccessor (cur, out next) && !RequiresJoining (next));
+
+ if (repeatOuter)
+ continue;
+
+ foreach (APC successorAPC in Successors (cur)) {
+ if (!IsBottom (successorAPC, state))
+ PushState (cur, successorAPC, state);
+ }
+ }
+ }
+
+ protected virtual void Dump (AState state)
+ {
+ }
+
+ public IEnumerable<KeyValuePair<APC, AState>> States ()
+ {
+ return this.JoinState;
+ }
+
+ protected abstract IEnumerable<APC> Successors (APC pc);
+
+ protected virtual void PushState (APC current, APC next, AState state)
+ {
+ state = ImmutableVersion (state, next);
+ if (RequiresJoining (next)) {
+ if (!JoinStateAtBlock (new Pair<APC, APC> (current, next), state))
+ return;
+ this.pending.Enqueue (next);
+ } else {
+ this.JoinState [next] = state;
+ this.pending.Enqueue (next);
+ }
+ }
+
+ private bool JoinStateAtBlock (Pair<APC, APC> edge, AState state)
+ {
+ AState existingState;
+ if (this.JoinState.TryGetValue (edge.Value, out existingState)) {
+ bool widen = this.widen_strategy.WantToWiden (edge.Key, edge.Value, IsBackEdge (edge.Key, edge.Value));
+ AState joinedState;
+ bool result = Join (edge, state, existingState, out joinedState, widen);
+ if (result)
+ this.JoinState [edge.Value] = ImmutableVersion (joinedState, edge.Value);
+ return result;
+ }
+
+ this.JoinState.Add (edge.Value, state);
+ return true;
+ }
+
+ protected abstract bool IsBackEdge (APC from, APC to);
+
+ protected abstract int WorkingListComparer (APC a, APC b);
+
+ protected abstract bool Join (Pair<APC, APC> edge, AState newState, AState existingState, out AState joinedState, bool widen);
+
+ protected abstract bool RequiresJoining (APC pc);
+
+ protected abstract bool HasSingleSuccessor (APC pc, out APC next);
+
+ protected abstract bool IsBottom (APC pc, AState state);
+
+ protected abstract AState Transfer (APC pc, AState state);
+
+ protected abstract AState MutableVersion (AState state, APC at);
+ protected abstract AState ImmutableVersion (AState state, APC at);
+
+ public void PrintStatesAtJoinPoints (TextWriter tw)
+ {
+ foreach (APC apc in this.JoinState.Keys) {
+ string str = this.JoinState [apc].ToString ().Replace (Environment.NewLine, Environment.NewLine + " ");
+ tw.WriteLine ("Block {0}, PC {1}: {2}", apc.Block, apc.Index, str);
+ }
+ }
+ }
+}
--- /dev/null
+//
+// EdgeBasedWidening.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.DataFlowAnalysis {
+ class EdgeBasedWidening : StepWidening<Pair<APC, APC>> {
+ public EdgeBasedWidening (int n)
+ : base (n)
+ {
+ }
+
+ #region Overrides of StepWidening<Pair<APC,APC>>
+ protected override Pair<APC, APC> MakeIndex (APC from, APC to)
+ {
+ return new Pair<APC, APC> (from, to);
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// EdgeConverter.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.DataFlowAnalysis {
+ delegate AbstractState EdgeConverter<Label, AbstractState, EdgeData> (Label from, Label to, bool isJoinPoint, EdgeData data, AbstractState newState);
+}
--- /dev/null
+//
+// ForwardAnalysis.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.Analysis;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+using Mono.CodeContracts.Static.Providers;
+
+namespace Mono.CodeContracts.Static.DataFlowAnalysis {
+ class ForwardAnalysis<AState, EdgeData> :
+ ForwardDataFlowAnalysisBase<AState>,
+ IFixPointInfo<APC, AState> {
+ private readonly Action<Pair<AState, TextWriter>> dumper;
+ private readonly EdgeConverter<APC, AState, EdgeData> edge_converter;
+ private readonly Func<APC, APC, EdgeData> edge_data_getter;
+ private readonly Func<AState, AState> immutable_version;
+ private readonly Func<APC, AState, bool> is_bottom;
+ private readonly Joiner<APC, AState> joiner;
+ private readonly Func<AState, AState> mutable_version;
+ private readonly Func<APC, AState, AState> transfer;
+
+ public ForwardAnalysis (ICFG cfg,
+ Func<APC, AState, AState> transfer,
+ Joiner<APC, AState> joiner,
+ Func<AState, AState> immutableVersion,
+ Func<AState, AState> mutableVersion,
+ EdgeConverter<APC, AState, EdgeData> edgeConverter,
+ Func<APC, APC, EdgeData> edgeDataGetter,
+ Func<APC, AState, bool> isBottom,
+ Action<Pair<AState, TextWriter>> dumper) : base (cfg)
+ {
+ this.transfer = transfer;
+ this.joiner = joiner;
+ this.immutable_version = immutableVersion;
+ this.mutable_version = mutableVersion;
+ this.edge_converter = edgeConverter;
+ this.edge_data_getter = edgeDataGetter;
+ this.is_bottom = isBottom;
+ this.dumper = dumper;
+ }
+
+ #region IFixPointInfo<APC,AbstractState> Members
+ public bool PreStateLookup (APC pc, out AState state)
+ {
+ return GetPreState (pc, out state);
+ }
+
+ public bool PostStateLookup (APC pc, out AState state)
+ {
+ return GetPostState (pc, out state);
+ }
+ #endregion
+
+ public static ForwardAnalysis<AState, EdgeData> Make<Source, Dest, Context> (
+ IILDecoder<APC, Source, Dest, Context, EdgeData> decoder,
+ IAnalysis<APC, AState, IILVisitor<APC, Source, Dest, AState, AState>, EdgeData> analysis)
+ where Context : IMethodContextProvider
+ {
+ IILVisitor<APC, Source, Dest, AState, AState> visitor = analysis.GetVisitor ();
+ var forwardAnalysisSolver = new ForwardAnalysis<AState, EdgeData> (
+ decoder.ContextProvider.MethodContext.CFG,
+ (pc, state) => decoder.ForwardDecode<AState, AState, IILVisitor<APC, Source, Dest, AState, AState>> (pc, visitor, state),
+ analysis.Join,
+ analysis.ImmutableVersion,
+ analysis.MutableVersion,
+ analysis.EdgeConversion,
+ decoder.EdgeData,
+ (pc, state) => {
+ if (!decoder.IsUnreachable (pc))
+ return analysis.IsBottom (pc, state);
+
+ return true;
+ },
+ analysis.Dump
+ );
+
+ analysis.SaveFixPointInfo (forwardAnalysisSolver);
+ return forwardAnalysisSolver;
+ }
+
+ protected override void Dump (AState state)
+ {
+ this.dumper (new Pair<AState, TextWriter> (state, Console.Out));
+ }
+
+ protected override void PushState (APC from, APC next, AState state)
+ {
+ EdgeData data = this.edge_data_getter (from, next);
+ AState pushState = this.edge_converter (from, next, RequiresJoining (next), data, state);
+ base.PushState (from, next, pushState);
+ }
+
+ protected override bool Join (Pair<APC, APC> edge, AState newState, AState existingState, out AState joinedState, bool widen)
+ {
+ bool weaker;
+ joinedState = this.joiner (edge, newState, existingState, out weaker, widen);
+
+ return weaker;
+ }
+
+ protected override bool IsBottom (APC pc, AState state)
+ {
+ return this.is_bottom (pc, state);
+ }
+
+ protected override AState Transfer (APC pc, AState state)
+ {
+ AState resultState = this.transfer (pc, state);
+
+ return resultState;
+ }
+
+ protected override AState MutableVersion (AState state, APC at)
+ {
+ return this.mutable_version (state);
+ }
+
+ protected override AState ImmutableVersion (AState state, APC at)
+ {
+ return this.immutable_version (state);
+ }
+ }
+}
--- /dev/null
+//
+// ForwardDataFlowAnalysisBase.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.DataFlowAnalysis {
+ abstract class ForwardDataFlowAnalysisBase<AState> : DataFlowAnalysisBase<AState> {
+ private readonly Dictionary<APC, AState> post_state = new Dictionary<APC, AState> ();
+
+ protected ForwardDataFlowAnalysisBase (ICFG cfg) : base (cfg)
+ {
+ }
+
+ public bool GetPreState (APC pc, out AState state)
+ {
+ bool noInfo;
+ state = GetPreState (pc, default(AState), out noInfo);
+ return !noInfo;
+ }
+
+ public AState GetPreStateWithDefault (APC apc, AState ifMissing)
+ {
+ bool noInfo;
+ AState preState = GetPreState (apc, default(AState), out noInfo);
+ return noInfo ? ifMissing : preState;
+ }
+
+ private AState GetPreState (APC apc, AState ifMissing, out bool noInfo)
+ {
+ LispList<APC> rest = null;
+ APC tmp = apc;
+ APC singlePredecessor;
+ AState state;
+ bool weHaveState;
+ while (!(weHaveState = this.JoinState.TryGetValue (tmp, out state)) &&
+ !RequiresJoining (tmp) && this.CFG.HasSinglePredecessor (tmp, out singlePredecessor)) {
+ tmp = singlePredecessor;
+
+ rest = rest.Cons (tmp);
+ }
+
+ if (!weHaveState) {
+ noInfo = true;
+ return ifMissing;
+ }
+
+ bool listWasNotEmpty = rest != null;
+ while (rest != null) {
+ if (IsBottom (rest.Head, state)) {
+ noInfo = false;
+ return state;
+ }
+ state = MutableVersion (state, rest.Head);
+ state = Transfer (rest.Head, state);
+ if (IsBottom (rest.Head, state)) {
+ noInfo = false;
+ return state;
+ }
+
+ rest = rest.Tail;
+ if (rest != null)
+ this.JoinState.Add (rest.Head, ImmutableVersion (state, rest.Head));
+ }
+
+ if (listWasNotEmpty)
+ this.JoinState.Add (apc, ImmutableVersion (state, apc));
+
+ noInfo = false;
+ return state;
+ }
+
+ public bool GetPostState (APC apc, out AState result)
+ {
+ if (this.post_state.TryGetValue (apc, out result))
+ return true;
+
+ APC singleSuccessor;
+ if (apc.Block.Count <= apc.Index)
+ return GetPreState (apc, out result);
+
+ if (this.CFG.HasSingleSuccessor (apc, out singleSuccessor) && !RequiresJoining (singleSuccessor))
+ return GetPreState (singleSuccessor, out result);
+
+ AState ifFound;
+ if (!GetPreState (apc, out ifFound))
+ return false;
+
+ result = MutableVersion (ifFound, apc);
+ result = Transfer (apc, result);
+
+ this.post_state.Add (apc, result);
+ return true;
+ }
+
+ public void Run (AState startState)
+ {
+ Initialize (this.CFG.Entry, startState);
+ ComputeFixPoint ();
+ }
+
+ protected override int WorkingListComparer (APC a, APC b)
+ {
+ return b.Block.ReversePostOrderIndex - a.Block.ReversePostOrderIndex;
+ }
+
+ protected override bool RequiresJoining (APC pc)
+ {
+ return this.CFG.IsJoinPoint (pc);
+ }
+
+ protected override bool HasSingleSuccessor (APC pc, out APC next)
+ {
+ return this.CFG.HasSingleSuccessor (pc, out next);
+ }
+
+ protected override IEnumerable<APC> Successors (APC pc)
+ {
+ return this.CFG.Successors (pc);
+ }
+
+ protected override bool IsBackEdge (APC from, APC to)
+ {
+ //todo: implement this
+ //can't be false, because back edges means having cycles, so we definitely have to widen
+ return true;
+ }
+ }
+}
--- /dev/null
+//
+// IAnalysis.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.DataFlowAnalysis {
+ interface IAnalysis<Label, AbstractState, Visitor, EdgeData> {
+ Visitor GetVisitor ();
+ AbstractState Join (Pair<Label, Label> edge, AbstractState newstate, AbstractState prevstate, out bool weaker, bool widen);
+ AbstractState ImmutableVersion (AbstractState arg);
+ AbstractState MutableVersion (AbstractState arg);
+ AbstractState EdgeConversion (APC from, APC to, bool isJoinPoint, EdgeData data, AbstractState state);
+ bool IsBottom (Label pc, AbstractState state);
+ Predicate<Label> SaveFixPointInfo (IFixPointInfo<Label, AbstractState> fixPointInfo);
+ void Dump (Pair<AbstractState, TextWriter> pair);
+ }
+}
--- /dev/null
+//
+// IFixPointInfo.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.DataFlowAnalysis {
+ interface IFixPointInfo<Label, AState> {
+ bool PreStateLookup (Label pc, out AState state);
+ bool PostStateLookup (Label pc, out AState state);
+ }
+}
--- /dev/null
+//
+// IWidenStrategy.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.ControlFlow;
+
+namespace Mono.CodeContracts.Static.DataFlowAnalysis {
+ interface IWidenStrategy {
+ bool WantToWiden (APC from, APC to, bool isBackEdge);
+ }
+}
--- /dev/null
+//
+// Joiner.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.DataFlowAnalysis {
+ delegate AbstractState Joiner<Label, AbstractState> (Pair<Label, Label> edge, AbstractState newState, AbstractState prevState, out bool weaker, bool widen);
+}
--- /dev/null
+//
+// StepWidening.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using Mono.CodeContracts.Static.ControlFlow;
+
+namespace Mono.CodeContracts.Static.DataFlowAnalysis {
+ abstract class StepWidening<Index> : IWidenStrategy {
+ private readonly int N;
+ private readonly Dictionary<Index, int> widenCounter;
+
+ protected StepWidening (int n)
+ {
+ this.widenCounter = new Dictionary<Index, int> ();
+ this.N = n;
+ }
+
+ protected abstract Index MakeIndex (APC from, APC to);
+
+ #region Implementation of IWidenStrategy
+ public bool WantToWiden (APC from, APC to, bool isBackEdge)
+ {
+ if (!isBackEdge)
+ return false;
+
+ Index key = MakeIndex (from, to);
+ if (this.widenCounter.ContainsKey (key))
+ this.widenCounter [key] = this.widenCounter [key] + 1;
+ else
+ this.widenCounter [key] = 1;
+ return this.N < this.widenCounter [key];
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// AbstractWorkList.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ abstract class AbstractWorkList<T> : IWorkList<T> {
+ protected HashSet<T> Elements = new HashSet<T> ();
+ protected abstract IEnumerable<T> Collection { get; }
+
+ public int Count
+ {
+ get { return this.Elements.Count; }
+ }
+
+ protected abstract void AddToCollection (T o);
+
+ #region Implementation of IWorkList<T>
+ public virtual bool Add (T o)
+ {
+ if (!this.Elements.Add (o))
+ return false;
+ AddToCollection (o);
+ return true;
+ }
+
+ public virtual bool IsEmpty ()
+ {
+ return this.Elements.Count == 0;
+ }
+
+ public abstract T Pull ();
+
+ public virtual bool AddAll (IEnumerable<T> objs)
+ {
+ bool any = false;
+ foreach (T o in objs) {
+ if (Add (o))
+ any = true;
+ }
+ return any;
+ }
+
+ public virtual IEnumerator<T> GetEnumerator ()
+ {
+ return Collection.GetEnumerator ();
+ }
+ #endregion
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ /// <summary>
+ /// This class is used with subroutines to substitute IStackInfo and IEdgeSubroutineAdapter to desired
+ /// </summary>
+ static class DecoratorHelper {
+ private static readonly List<object> ContextAdapters = new List<object> ();
+
+ private static object Last
+ {
+ get { return ContextAdapters [ContextAdapters.Count - 1]; }
+ }
+
+ public static void Push<T> (T @this) where T : class
+ {
+ ContextAdapters.Add (@this);
+ }
+
+ public static void Pop ()
+ {
+ ContextAdapters.RemoveAt (ContextAdapters.Count - 1);
+ }
+
+ public static T Dispatch<T> (T @this) where T : class
+ {
+ return FindAdaptorStartingAt (@this, 0);
+ }
+
+ private static T FindAdaptorStartingAt<T> (T @default, int startIndex)
+ where T : class
+ {
+ List<object> list = ContextAdapters;
+ for (int i = startIndex; i < list.Count; ++i) {
+ var obj = list [i] as T;
+ if (obj != null)
+ return obj;
+ }
+ return @default;
+ }
+
+ public static T Inner<T> (T @this) where T : class
+ {
+ for (int i = 0; i < ContextAdapters.Count; i++) {
+ if (ContextAdapters [i] == @this) {
+ ClearDuplicates (@this, i + 1);
+ T inner = FindAdaptorStartingAt (default(T), i + 1);
+ if (inner != null)
+ return inner;
+
+ throw new InvalidOperationException ("No inner context found");
+ }
+ }
+
+ throw new InvalidOperationException ("@this is not current adaptor");
+ }
+
+ private static void ClearDuplicates (object @this, int @from)
+ {
+ for (int i = from; i < ContextAdapters.Count; i++) {
+ if (ContextAdapters [i] == @this)
+ ContextAdapters [i] = null;
+ }
+ }
+ }
+}
--- /dev/null
+//
+// DepthFirst.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ static class DepthFirst {
+ public static void Visit<Node, EdgeInfo> (IGraph<Node, EdgeInfo> graph,
+ Predicate<Node> nodeStartVisitor,
+ EdgeVisitor<Node, EdgeInfo> edgeVisitor)
+ {
+ new Visitor<Node, EdgeInfo> (graph, nodeStartVisitor, edgeVisitor).VisitAll ();
+ }
+
+ public static void Visit<Node, EdgeInfo> (IGraph<Node, EdgeInfo> graph,
+ Node startNode,
+ Predicate<Node> nodeStartVisitor,
+ EdgeVisitor<Node, EdgeInfo> edgeVisitor)
+ {
+ new Visitor<Node, EdgeInfo> (graph, nodeStartVisitor, edgeVisitor).VisitSubGraphNonRecursive (startNode);
+ }
+
+ #region Nested type: Info
+ public class Info<Node> {
+ public readonly Node Parent;
+ public readonly int StartTime;
+
+ public int FinishTime;
+ public bool SourceOfBackEdge;
+ public bool TargetOfBackEdge;
+
+ public Info (Node parent, int startTime)
+ {
+ this.Parent = parent;
+ this.StartTime = startTime;
+ }
+ }
+ #endregion
+
+ #region Nested type: Visitor
+ public class Visitor<Node, Edge> {
+ private readonly HashSet<Tuple<Node, Edge, Node>> back_edges = new HashSet<Tuple<Node, Edge, Node>> ();
+ private readonly EdgeVisitor<Node, Edge> edge_visitor;
+ private readonly IGraph<Node, Edge> graph;
+
+ private readonly Dictionary<Node, Info<Node>> history = new Dictionary<Node, Info<Node>> ();
+ private readonly Action<Node> node_finish_visitor;
+ private readonly Predicate<Node> node_start_visitor;
+ private readonly Stack<SearchFrame> todo = new Stack<SearchFrame> ();
+ private int time;
+
+ public Visitor (IGraph<Node, Edge> graph, Predicate<Node> nodeStartVisitor, EdgeVisitor<Node, Edge> edgeVisitor)
+ : this (graph, nodeStartVisitor, null, edgeVisitor)
+ {
+ }
+
+ public Visitor (IGraph<Node, Edge> graph, Predicate<Node> nodeStartVisitor)
+ : this (graph, nodeStartVisitor, null, null)
+ {
+ }
+
+ public Visitor (IGraph<Node, Edge> graph, Predicate<Node> nodeStartVisitor, Action<Node> nodeFinishVisitor, EdgeVisitor<Node, Edge> edgeVisitor)
+ {
+ this.graph = graph;
+ this.node_start_visitor = nodeStartVisitor;
+ this.node_finish_visitor = nodeFinishVisitor;
+ this.edge_visitor = edgeVisitor;
+ }
+
+ public virtual void VisitAll ()
+ {
+ foreach (Node node in this.graph.Nodes)
+ VisitSubGraphNonRecursive (node);
+ }
+
+ public void VisitSubGraphNonRecursive (Node node)
+ {
+ ScheduleNode (node, default(Node));
+ IterativeDFS ();
+ }
+
+ private void IterativeDFS ()
+ {
+ while (this.todo.Count > 0) {
+ SearchFrame frame = this.todo.Peek ();
+ if (frame.Edges.MoveNext ()) {
+ Pair<Edge, Node> current = frame.Edges.Current;
+ VisitEdgeNonRecursive (frame.Info, frame.Node, current.Key, current.Value);
+ } else {
+ if (this.node_finish_visitor != null)
+ this.node_finish_visitor (frame.Node);
+ frame.Info.FinishTime = ++this.time;
+ this.todo.Pop ();
+ }
+ }
+ }
+
+ private void VisitEdgeNonRecursive (Info<Node> sourceInfo, Node source, Edge info, Node target)
+ {
+ if (this.edge_visitor != null)
+ this.edge_visitor (source, info, target);
+
+ Info<Node> targetInfo;
+ if (this.history.TryGetValue (target, out targetInfo)) {
+ if (targetInfo.FinishTime != 0)
+ return;
+
+ targetInfo.TargetOfBackEdge = true;
+ sourceInfo.SourceOfBackEdge = true;
+ this.back_edges.Add (new Tuple<Node, Edge, Node> (source, info, target));
+ } else
+ ScheduleNode (target, source);
+ }
+
+ private void VisitEdge (Info<Node> sourceInfo, Node source, Edge info, Node target)
+ {
+ if (this.edge_visitor != null)
+ this.edge_visitor (source, info, target);
+
+ Info<Node> targetInfo;
+ if (this.history.TryGetValue (target, out targetInfo)) {
+ if (targetInfo.FinishTime != 0)
+ return;
+
+ targetInfo.TargetOfBackEdge = true;
+ sourceInfo.SourceOfBackEdge = true;
+ this.back_edges.Add (new Tuple<Node, Edge, Node> (source, info, target));
+ } else
+ VisitSubGraph (target, source);
+ }
+
+ public void VisitSubGraph (Node node, Node parent)
+ {
+ if (this.history.ContainsKey (node))
+ return;
+
+ var info = new Info<Node> (parent, ++this.time);
+ this.history [node] = info;
+
+ if (this.node_start_visitor != null && !this.node_start_visitor (node))
+ return;
+
+ VisitSuccessors (info, node);
+
+ if (this.node_finish_visitor != null)
+ this.node_finish_visitor (node);
+
+ info.FinishTime = ++this.time;
+ }
+
+ public void ScheduleNode (Node node, Node parent)
+ {
+ if (this.history.ContainsKey (node))
+ return;
+
+ var info = new Info<Node> (parent, ++this.time);
+ this.history [node] = info;
+
+ if (this.node_start_visitor != null && !this.node_start_visitor (node))
+ return;
+
+ this.todo.Push (new SearchFrame (node, this.graph.Successors (node).GetEnumerator (), info));
+ }
+
+ private void VisitSuccessors (Info<Node> info, Node node)
+ {
+ foreach (var successor in this.graph.Successors (node))
+ VisitEdge (info, node, successor.Key, successor.Value);
+ }
+
+ public bool IsVisited (Node node)
+ {
+ return this.history.ContainsKey (node);
+ }
+
+ public bool IsBackEdge (Node source, Edge info, Node target)
+ {
+ return this.back_edges.Contains (new Tuple<Node, Edge, Node> (source, info, target));
+ }
+
+ public Info<Node> DepthFirstInfo (Node node)
+ {
+ return this.history [node];
+ }
+
+ #region Nested type: SearchFrame
+ private struct SearchFrame {
+ public readonly IEnumerator<Pair<Edge, Node>> Edges;
+ public readonly Info<Node> Info;
+ public readonly Node Node;
+
+ public SearchFrame (Node node, IEnumerator<Pair<Edge, Node>> edges, Info<Node> info)
+ {
+ this.Node = node;
+ this.Edges = edges;
+ this.Info = info;
+ }
+ }
+ #endregion
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// DoubleDictionary.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using System.Linq;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ class DoubleDictionary<A, B, C> : Dictionary<A, Dictionary<B, C>> {
+ public C this [A a, B b]
+ {
+ get { return base [a] [b]; }
+ set
+ {
+ Dictionary<B, C> dict;
+ if (!base.TryGetValue (a, out dict)) {
+ dict = new Dictionary<B, C> ();
+ base.Add (a, dict);
+ }
+ dict [b] = value;
+ }
+ }
+
+ public IEnumerable<A> Keys1
+ {
+ get { return base.Keys; }
+ }
+
+ public void Add (A a, B b, C value)
+ {
+ Dictionary<B, C> dict;
+ if (!base.TryGetValue (a, out dict)) {
+ dict = new Dictionary<B, C> ();
+ base.Add (a, dict);
+ }
+ dict.Add (b, value);
+ }
+
+ public IEnumerable<B> Keys2 (A a)
+ {
+ Dictionary<B, C> dict;
+ if (base.TryGetValue (a, out dict))
+ return dict.Keys;
+ return Enumerable.Empty<B> ();
+ }
+
+ public bool ContainsKey (A a, B b)
+ {
+ Dictionary<B, C> dict;
+ if (!base.TryGetValue (a, out dict))
+ return false;
+
+ return dict.ContainsKey (b);
+ }
+
+ public bool TryGetValue (A a, B b, out C value)
+ {
+ Dictionary<B, C> dict;
+ if (base.TryGetValue (a, out dict))
+ return dict.TryGetValue (b, out value);
+
+ value = default(C);
+ return false;
+ }
+ }
+}
--- /dev/null
+//
+// DoubleImmutableMap.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ class DoubleImmutableMap<A, B, C>
+ where A : IEquatable<A>
+ where B : IEquatable<B> {
+ private readonly B[] EmptyCache = new B[0];
+ private readonly IImmutableMap<A, IImmutableMap<B, C>> map;
+
+ private DoubleImmutableMap (IImmutableMap<A, IImmutableMap<B, C>> map)
+ {
+ this.map = map;
+ }
+
+ public C this [A key1, B key2]
+ {
+ get
+ {
+ IImmutableMap<B, C> inner = this.map [key1];
+ if (inner == null)
+ return default(C);
+ return inner [key2];
+ }
+ }
+
+ public int Keys1Count
+ {
+ get { return this.map.Count; }
+ }
+
+ public IEnumerable<A> Keys1
+ {
+ get { return this.map.Keys; }
+ }
+
+ public DoubleImmutableMap<A, B, C> Add (A key1, B key2, C value)
+ {
+ IImmutableMap<B, C> immutableMap = this.map [key1] ?? ImmutableMap<B, C>.Empty;
+ return new DoubleImmutableMap<A, B, C> (this.map.Add (key1, immutableMap.Add (key2, value)));
+ }
+
+ public DoubleImmutableMap<A, B, C> RemoveAll (A key1)
+ {
+ return new DoubleImmutableMap<A, B, C> (this.map.Remove (key1));
+ }
+
+ public DoubleImmutableMap<A, B, C> Remove (A key1, B key2)
+ {
+ IImmutableMap<B, C> inner = this.map [key1];
+ if (inner == null)
+ return this;
+ IImmutableMap<B, C> newInner = inner.Remove (key2);
+ if (newInner == inner)
+ return this;
+ return new DoubleImmutableMap<A, B, C> (this.map.Add (key1, newInner));
+ }
+
+ public static DoubleImmutableMap<A, B, C> Empty (Func<A, int> uniqueIdGenerator)
+ {
+ return new DoubleImmutableMap<A, B, C> (ImmutableIntKeyMap<A, IImmutableMap<B, C>>.Empty (uniqueIdGenerator));
+ }
+
+ public bool Contains (A key1, B key2)
+ {
+ IImmutableMap<B, C> inner = this.map [key1];
+ if (inner == null)
+ return false;
+ return inner.ContainsKey (key2);
+ }
+
+ public bool ContainsKey1 (A key1)
+ {
+ return this.map.ContainsKey (key1);
+ }
+
+ public int Keys2Count (A key1)
+ {
+ if (key1 == null)
+ return 0;
+ IImmutableMap<B, C> inner = this.map [key1];
+ if (inner == null)
+ return 0;
+ return inner.Count;
+ }
+
+ public IEnumerable<B> Keys2 (A key1)
+ {
+ if (key1 == null)
+ return this.EmptyCache;
+
+ IImmutableMap<B, C> inner = this.map [key1];
+ if (inner == null)
+ return this.EmptyCache;
+ return inner.Keys;
+ }
+ }
+}
--- /dev/null
+//
+// Dummy.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ struct Dummy : IEquatable<Dummy> {
+ public static readonly Dummy Value = new Dummy ();
+
+ #region IEquatable<Dummy> Members
+ public bool Equals (Dummy other)
+ {
+ return true;
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// EdgeVisitor.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ delegate void EdgeVisitor<Node, Info> (Node source, Info info, Node target);
+}
--- /dev/null
+//
+// GraphWrapper.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ class GraphWrapper<Node, Info> : IGraph<Node, Info> {
+ private readonly IEnumerable<Node> nodes;
+ private readonly Func<Node, IEnumerable<Pair<Info, Node>>> successors;
+
+ public GraphWrapper (IEnumerable<Node> nodes, Func<Node, IEnumerable<Pair<Info, Node>>> successors)
+ {
+ this.nodes = nodes;
+ this.successors = successors;
+ }
+
+ #region Implementation of IGraph<Node,Info>
+ public IEnumerable<Node> Nodes
+ {
+ get { return this.nodes; }
+ }
+
+ public IEnumerable<Pair<Info, Node>> Successors (Node node)
+ {
+ return this.successors (node);
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// IGraph.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ interface IGraph<Node, EdgeInfo> {
+ IEnumerable<Node> Nodes { get; }
+ IEnumerable<Pair<EdgeInfo, Node>> Successors (Node node);
+ }
+}
--- /dev/null
+//
+// IImmutableIntMap.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ interface IImmutableIntMap<T> {
+ T this [int key] { get; }
+ T Any { get; }
+ IEnumerable<T> Values { get; }
+ IEnumerable<int> Keys { get; }
+ int Count { get; }
+ T Lookup (int key);
+ bool Contains (int key);
+ IImmutableIntMap<T> Add (int key, T value);
+ IImmutableIntMap<T> Remove (int key);
+ void Visit (Action<T> action);
+ void Visit (Action<int, T> action);
+ }
+}
--- /dev/null
+//
+// IImmutableMap.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ interface IImmutableMap<K, V> {
+ V this [K key] { get; }
+
+ K AnyKey { get; }
+
+ IEnumerable<K> Keys { get; }
+ int Count { get; }
+ IImmutableMap<K, V> EmptyMap { get; }
+
+ IImmutableMap<K, V> Add (K key, V value);
+ IImmutableMap<K, V> Remove (K key);
+
+ bool ContainsKey (K key);
+ void Visit (Func<K, V, VisitStatus> func);
+ }
+}
--- /dev/null
+//
+// IImmutableSet.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ interface IImmutableSet<T>
+ where T : IEquatable<T> {
+ T Any { get; }
+ int Count { get; }
+ IEnumerable<T> Elements { get; }
+ IImmutableSet<T> Add (T item);
+ IImmutableSet<T> Remove (T item);
+ bool Contains (T item);
+ bool IsContainedIn (IImmutableSet<T> that);
+ IImmutableSet<T> Intersect (IImmutableSet<T> that);
+ IImmutableSet<T> Union (IImmutableSet<T> that);
+ void Visit (Action<T> visitor);
+ void Dump (TextWriter tw);
+ }
+}
--- /dev/null
+//
+// IIndexable.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ interface IIndexable<T> {
+ int Count { get; }
+ T this [int index] { get; }
+ }
+}
--- /dev/null
+//
+// ITypedProperties.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ internal interface ITypedProperties {
+ bool Contains (TypedKey key);
+ void Add<T> (TypedKey key, T value);
+ bool TryGetValue<T> (TypedKey key, out T value);
+ }
+}
--- /dev/null
+//
+// IWorkList.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ interface IWorkList<T> {
+ bool Add (T o);
+ bool IsEmpty ();
+ T Pull ();
+ }
+}
--- /dev/null
+//
+// ImmutableIntKeyMap.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ class ImmutableIntKeyMap<K, V> : IImmutableMap<K, V>, IEquatable<IImmutableMap<K, V>> {
+ private readonly IImmutableIntMap<Pair<K, V>> immutable_int_map;
+ private readonly Func<K, int> keyConverter;
+
+ private ImmutableIntKeyMap (IImmutableIntMap<Pair<K, V>> map, Func<K, int> converter)
+ {
+ this.immutable_int_map = map;
+ this.keyConverter = converter;
+ }
+
+ #region Implementation of IImmutableMap<K,V>
+ public V this [K key]
+ {
+ get
+ {
+ Pair<K, V> pair = this.immutable_int_map [this.keyConverter (key)];
+ if (pair != null)
+ return pair.Value;
+ return default(V);
+ }
+ }
+
+ public K AnyKey
+ {
+ get { return Keys.First (); }
+ }
+
+ public IEnumerable<K> Keys
+ {
+ get
+ {
+ var res = new List<K> ();
+ this.immutable_int_map.Visit (data => res.Add (data.Key));
+ return res;
+ }
+ }
+
+ public int Count
+ {
+ get { return this.immutable_int_map.Count; }
+ }
+
+ public IImmutableMap<K, V> EmptyMap
+ {
+ get { return Empty (this.keyConverter); }
+ }
+
+ public IImmutableMap<K, V> Add (K key, V value)
+ {
+ return new ImmutableIntKeyMap<K, V> (this.immutable_int_map.Add (this.keyConverter (key), new Pair<K, V> (key, value)), this.keyConverter);
+ }
+
+ public IImmutableMap<K, V> Remove (K key)
+ {
+ return new ImmutableIntKeyMap<K, V> (this.immutable_int_map.Remove (this.keyConverter (key)), this.keyConverter);
+ }
+
+ public bool ContainsKey (K key)
+ {
+ return this.immutable_int_map.Contains (this.keyConverter (key));
+ }
+
+ public void Visit (Func<K, V, VisitStatus> func)
+ {
+ this.immutable_int_map.Visit (data => func (data.Key, data.Value));
+ }
+ #endregion
+
+ #region Implementation of IEquatable<IImmutableMap<K,V>>
+ public bool Equals (IImmutableMap<K, V> other)
+ {
+ return this == other;
+ }
+ #endregion
+
+ public static IImmutableMap<K, V> Empty (Func<K, int> keyConverter)
+ {
+ return new ImmutableIntKeyMap<K, V> (ImmutableIntMap<Pair<K, V>>.Empty (), keyConverter);
+ }
+ }
+}
--- /dev/null
+//
+// ImmutableIntMap.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ class ImmutableIntMap<T> : IImmutableIntMap<T> {
+ private readonly Dictionary<int, T> map = new Dictionary<int, T> ();
+
+ private ImmutableIntMap (Dictionary<int, T> map)
+ {
+ this.map = map;
+ }
+
+ #region Implementation of IImm utableIntMap<T>
+ public T this [int key]
+ {
+ get
+ {
+ if (this.map == null || !this.map.ContainsKey (key))
+ return default(T);
+
+ return this.map [key];
+ }
+ }
+
+ public T Any
+ {
+ get
+ {
+ if (this.map == null)
+ return default(T);
+ return this.map.Values.First ();
+ }
+ }
+
+ public IEnumerable<T> Values
+ {
+ get
+ {
+ if (this.map == null)
+ return Enumerable.Empty<T> ();
+ return this.map.Values;
+ }
+ }
+
+ public IEnumerable<int> Keys
+ {
+ get
+ {
+ if (this.map == null)
+ return Enumerable.Empty<int> ();
+ return this.map.Keys;
+ }
+ }
+
+ public int Count
+ {
+ get
+ {
+ if (this.map == null)
+ return 0;
+ return this.map.Count;
+ }
+ }
+
+ public T Lookup (int key)
+ {
+ if (this.map == null)
+ return default(T);
+ return this.map [key];
+ }
+
+ public bool Contains (int key)
+ {
+ if (this.map == null)
+ return false;
+ return this.map.ContainsKey (key);
+ }
+
+ public IImmutableIntMap<T> Add (int key, T value)
+ {
+ if (this.map == null)
+ return new ImmutableIntMap<T> (new Dictionary<int, T> {{key, value}});
+
+ var newDict = new Dictionary<int, T> (this.map);
+ newDict [key] = value;
+ return new ImmutableIntMap<T> (newDict);
+ }
+
+ public IImmutableIntMap<T> Remove (int key)
+ {
+ if (this.map == null || !this.map.ContainsKey (key))
+ return this;
+
+ var newDict = new Dictionary<int, T> (this.map);
+ newDict.Remove (key);
+ return new ImmutableIntMap<T> (newDict);
+ }
+
+ public void Visit (Action<T> action)
+ {
+ foreach (T value in Values)
+ action (value);
+ }
+
+ public void Visit (Action<int, T> action)
+ {
+ foreach (int key in Keys)
+ action (key, this [key]);
+ }
+ #endregion
+
+ public static IImmutableIntMap<T> Empty ()
+ {
+ return new ImmutableIntMap<T> (null);
+ }
+ }
+}
--- /dev/null
+//
+// ImmutableMap.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ class ImmutableMap<K, V> : IImmutableMap<K, V>
+ where K : IEquatable<K> {
+ public static ImmutableMap<K, V> Empty = new ImmutableMap<K, V> (ImmutableIntMap<LispList<Pair<K, V>>>.Empty (), 0, null);
+ private readonly int count;
+ private readonly IImmutableIntMap<LispList<Pair<K, V>>> immutable_int_map;
+ private readonly LispList<K> keys;
+
+ private ImmutableMap (IImmutableIntMap<LispList<Pair<K, V>>> map, int count, LispList<K> keys)
+ {
+ this.keys = keys;
+ this.count = count;
+ this.immutable_int_map = map;
+ }
+
+ #region Implementation of IImmutableMap<K,V>
+ public V this [K key]
+ {
+ get
+ {
+ for (LispList<Pair<K, V>> list = this.immutable_int_map [key.GetHashCode ()]; list != null; list = list.Tail) {
+ K k = list.Head.Key;
+ if (key.Equals (k))
+ return list.Head.Value;
+ }
+ return default(V);
+ }
+ }
+
+ public K AnyKey
+ {
+ get { return this.keys.Head; }
+ }
+
+ public IEnumerable<K> Keys
+ {
+ get { return this.keys.AsEnumerable (); }
+ }
+
+ public int Count
+ {
+ get { return this.immutable_int_map.Count; }
+ }
+
+ public IImmutableMap<K, V> EmptyMap
+ {
+ get { return Empty; }
+ }
+
+ public IImmutableMap<K, V> Add (K key, V value)
+ {
+ int hashCode = key.GetHashCode ();
+ LispList<Pair<K, V>> list1 = this.immutable_int_map [hashCode];
+ LispList<Pair<K, V>> newList = Remove (list1, key).Cons (new Pair<K, V> (key, value));
+ int diff = newList.Length () - list1.Length ();
+ LispList<K> newKeys = diff == 0 ? this.keys : this.keys.Cons (key);
+
+ return new ImmutableMap<K, V> (this.immutable_int_map.Add (hashCode, newList), this.count + diff, newKeys);
+ }
+
+ public IImmutableMap<K, V> Remove (K key)
+ {
+ int hashCode = key.GetHashCode ();
+ LispList<Pair<K, V>> from = this.immutable_int_map [hashCode];
+ if (from == null)
+ return this;
+ LispList<Pair<K, V>> newList = Remove (from, key);
+ if (newList == from)
+ return this;
+ LispList<K> newKeys = RemoveKey (key, this.keys);
+ if (newList == null)
+ return new ImmutableMap<K, V> (this.immutable_int_map.Remove (hashCode), this.count - 1, newKeys);
+ return new ImmutableMap<K, V> (this.immutable_int_map.Add (hashCode, newList), this.count - 1, newKeys);
+ }
+
+ public bool ContainsKey (K key)
+ {
+ return this.immutable_int_map [key.GetHashCode ()].AsEnumerable ().Any (pair => key.Equals (pair.Key));
+ }
+
+ public void Visit (Func<K, V, VisitStatus> func)
+ {
+ this.immutable_int_map.Visit (list => {
+ foreach (var pair in list.AsEnumerable ())
+ func (pair.Key, pair.Value);
+ });
+ }
+
+ private LispList<Pair<K, V>> Remove (LispList<Pair<K, V>> from, K key)
+ {
+ if (from == null)
+ return null;
+ if (key.Equals (from.Head.Key))
+ return from.Tail;
+ LispList<Pair<K, V>> tail = Remove (from.Tail, key);
+ return tail == from.Tail ? from : tail.Cons (from.Head);
+ }
+
+ private static LispList<K> RemoveKey (K key, LispList<K> keys)
+ {
+ if (keys == null)
+ throw new InvalidOperationException ();
+
+ if (key.Equals (keys.Head))
+ return keys.Tail;
+
+ return RemoveKey (key, keys.Tail).Cons (keys.Head);
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// ImmutableSet.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ class ImmutableSet<T> : IImmutableSet<T>
+ where T : IEquatable<T> {
+ private readonly IImmutableMap<T, Dummy> underlying;
+
+ public ImmutableSet (IImmutableMap<T, Dummy> immutableMap)
+ {
+ this.underlying = immutableMap;
+ }
+
+ #region Implementation of IImmutableSet<T>
+ public T Any
+ {
+ get { return this.underlying.AnyKey; }
+ }
+
+ public int Count
+ {
+ get { return this.underlying.Count; }
+ }
+
+ public IEnumerable<T> Elements
+ {
+ get { return this.underlying.Keys; }
+ }
+
+ public IImmutableSet<T> Add (T item)
+ {
+ return new ImmutableSet<T> (this.underlying.Add (item, Dummy.Value));
+ }
+
+ public IImmutableSet<T> Remove (T item)
+ {
+ return new ImmutableSet<T> (this.underlying.Remove (item));
+ }
+
+ public bool Contains (T item)
+ {
+ return this.underlying.ContainsKey (item);
+ }
+
+ public bool IsContainedIn (IImmutableSet<T> that)
+ {
+ if (Count > that.Count)
+ return false;
+ bool result = true;
+ this.underlying.Visit ((e, dummy) => {
+ if (that.Contains (e))
+ return VisitStatus.ContinueVisit;
+
+ result = false;
+ return VisitStatus.StopVisit;
+ });
+ return result;
+ }
+
+ public IImmutableSet<T> Intersect (IImmutableSet<T> that)
+ {
+ if (this == that)
+ return this;
+ if (Count == 0)
+ return this;
+ IImmutableSet<T> set;
+ IImmutableSet<T> larger;
+ if (Count < that.Count) {
+ set = this;
+ larger = that;
+ } else {
+ if (that.Count == 0)
+ return that;
+ set = that;
+ larger = this;
+ }
+ IImmutableSet<T> result = set;
+ set.Visit ((e) => {
+ if (!larger.Contains (e))
+ result = result.Remove (e);
+ });
+ return result;
+ }
+
+ public IImmutableSet<T> Union (IImmutableSet<T> that)
+ {
+ if (this == that)
+ return this;
+ if (Count == 0)
+ return that;
+ IImmutableSet<T> smaller;
+ IImmutableSet<T> larger;
+ if (Count < that.Count) {
+ smaller = this;
+ larger = that;
+ } else {
+ if (that.Count == 0)
+ return this;
+ smaller = that;
+ larger = this;
+ }
+ IImmutableSet<T> result = larger;
+ smaller.Visit (e => { result = result.Add (e); });
+ return result;
+ }
+
+ public void Visit (Action<T> visitor)
+ {
+ this.underlying.Visit ((elem, dummy) => {
+ visitor (elem);
+ return VisitStatus.ContinueVisit;
+ });
+ }
+
+ public void Dump (TextWriter tw)
+ {
+ tw.Write ("{");
+ bool first = true;
+ foreach (T key in this.underlying.Keys) {
+ if (!first)
+ tw.Write (", ");
+ else
+ first = false;
+ tw.Write ("{0}", key);
+ }
+ tw.WriteLine ("}");
+ }
+
+ public static IImmutableSet<T> Empty ()
+ {
+ return new ImmutableSet<T> (ImmutableMap<T, Dummy>.Empty);
+ }
+
+ public static IImmutableSet<T> Empty (Func<T, int> keyConverter)
+ {
+ return new ImmutableSet<T> (ImmutableIntKeyMap<T, Dummy>.Empty (keyConverter));
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// ImmutableSetExtensions.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ static class ImmutableSetExtensions {
+ public static bool ContainsSafe<T> (this IImmutableSet<T> set, T value)
+ where T : IEquatable<T>
+ {
+ if (set == null || value == null)
+ return false;
+
+ return set.Contains (value);
+ }
+
+ public static int Count<T> (this IImmutableSet<T> set)
+ where T : IEquatable<T>
+ {
+ if (set == null)
+ return 0;
+
+ return set.Count;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// Indexable.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ class Indexable<T> : IIndexable<T> {
+ public static Indexable<T> Empty = new Indexable<T> (null);
+
+ private readonly IList<T> list;
+
+ public Indexable (IList<T> parameters)
+ {
+ this.list = parameters;
+ }
+
+ #region IIndexable<T> Members
+ public int Count
+ {
+ get { return this.list == null ? 0 : this.list.Count; }
+ }
+
+ public T this [int index]
+ {
+ get { return this.list [index]; }
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// LispList.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Text;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ class LispList<T> {
+ public static readonly LispList<T> Empty = null;
+ private readonly int count;
+ private readonly T element;
+ private readonly LispList<T> tail;
+
+ private LispList (T elem, LispList<T> tail)
+ {
+ this.element = elem;
+ this.tail = tail;
+ this.count = LengthOf (tail) + 1;
+ }
+
+ public T Head
+ {
+ get { return this.element; }
+ }
+
+ public LispList<T> Tail
+ {
+ get { return this.tail; }
+ }
+
+ public static LispList<T> Cons (T elem, LispList<T> tail)
+ {
+ return new LispList<T> (elem, tail);
+ }
+
+ public static LispList<T> Reverse (LispList<T> list)
+ {
+ LispList<T> rest = null;
+ for (; list != null; list = list.tail)
+ rest = rest.Cons (list.element);
+ return rest;
+ }
+
+ public static bool Contains (LispList<T> l, T o)
+ {
+ if (l == null)
+ return false;
+ var equatable = o as IEquatable<T>;
+ if (equatable != null) {
+ if (equatable.Equals (l.element))
+ return true;
+ } else if (o.Equals (l.element))
+ return true;
+
+ return Contains (l.tail, o);
+ }
+
+ public static int LengthOf (LispList<T> list)
+ {
+ if (list == null)
+ return 0;
+ return list.count;
+ }
+
+ public static void Apply (LispList<T> list, Action<T> action)
+ {
+ for (; list != null; list = list.tail)
+ action (list.Head);
+ }
+
+ public static IEnumerable<T> PrivateGetEnumerable (LispList<T> list)
+ {
+ LispList<T> current = list;
+ while (current != null) {
+ T next = current.Head;
+ current = current.tail;
+ yield return next;
+ }
+ }
+
+ public static LispList<S> Select<S> (LispList<T> list, Func<T, S> selector)
+ {
+ if (list == null)
+ return null;
+ return list.tail.Select (selector).Cons (selector (list.Head));
+ }
+
+ public override string ToString ()
+ {
+ var sb = new StringBuilder ();
+ BuildString (sb);
+
+ return sb.ToString ();
+ }
+
+ private void BuildString (StringBuilder sb)
+ {
+ sb.Append (this.element == null ? "<null>" : this.element.ToString ());
+ if (this.tail != null) {
+ sb.Append (",");
+ this.tail.BuildString (sb);
+ }
+ }
+ }
+}
--- /dev/null
+//
+// LispListExtensions.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ static class LispListExtensions {
+ public static LispList<T> Cons<T> (this LispList<T> rest, T elem)
+ {
+ return LispList<T>.Cons (elem, rest);
+ }
+
+ public static LispList<T> Append<T> (this LispList<T> list, LispList<T> append)
+ {
+ if (list == null)
+ return append;
+ if (append == null)
+ return list;
+
+ return Cons (list.Tail.Append (append), list.Head);
+ }
+
+ public static LispList<T> Where<T> (this LispList<T> list, Predicate<T> keep)
+ {
+ if (list == null)
+ return null;
+ LispList<T> rest = list.Tail.Where (keep);
+ if (!keep (list.Head))
+ return rest;
+
+ if (rest == list.Tail)
+ return list;
+
+ return Cons (rest, list.Head);
+ }
+
+ public static void Apply<T> (this LispList<T> list, Action<T> action)
+ {
+ LispList<T>.Apply (list, action);
+ }
+
+ public static IEnumerable<T> AsEnumerable<T> (this LispList<T> list)
+ {
+ return LispList<T>.PrivateGetEnumerable (list);
+ }
+
+ public static bool Any<T> (this LispList<T> list, Predicate<T> predicate)
+ {
+ if (list == null)
+ return false;
+
+ if (predicate (list.Head))
+ return true;
+
+ return list.Tail.Any (predicate);
+ }
+
+ public static int Length<T> (this LispList<T> list)
+ {
+ return LispList<T>.LengthOf (list);
+ }
+
+ public static bool IsEmpty<T> (this LispList<T> list)
+ {
+ return list == null;
+ }
+
+ public static LispList<S> Select<T, S> (this LispList<T> list, Func<T, S> selector)
+ {
+ return LispList<T>.Select (list, selector);
+ }
+
+ public static T Last<T> (this LispList<T> list)
+ {
+ if (list == null)
+ return default(T);
+
+ while (LispList<T>.LengthOf (list) > 1)
+ list = list.Tail;
+
+ return list.Head;
+ }
+
+ public static LispList<T> Coerce<S, T> (this LispList<S> list)
+ where S : T
+ {
+ return list.Select (l => (T) l);
+ }
+ }
+}
--- /dev/null
+//
+// Optional.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ struct Optional<T> {
+ public readonly bool IsValid;
+
+ public Optional (T value) : this ()
+ {
+ Value = value;
+ this.IsValid = true;
+ }
+
+ public T Value { get; private set; }
+
+ public static implicit operator Optional<T> (T value)
+ {
+ return new Optional<T> (value);
+ }
+ }
+}
--- /dev/null
+//
+// Pair.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ class Pair<K, V> : IEquatable<Pair<K, V>> {
+ private static readonly bool KeyIsReferenceType = default(K) == null;
+ private static readonly bool ValueIsReferenceType = default(V) == null;
+
+ public readonly K Key;
+ public readonly V Value;
+
+ public Pair (K key, V value)
+ {
+ this.Key = key;
+ this.Value = value;
+ }
+
+ #region IEquatable<Pair<K,V>> Members
+ public bool Equals (Pair<K, V> other)
+ {
+ var keyEquatable = ((object) this.Key) as IEquatable<K>;
+ bool keysAreEqual = keyEquatable != null ? keyEquatable.Equals (other.Key) : Equals (this.Key, other.Key);
+ if (!keysAreEqual)
+ return false;
+
+ var valueEquatable = ((object) this.Value) as IEquatable<V>;
+ return valueEquatable != null ? valueEquatable.Equals (other.Value) : Equals (this.Value, other.Value);
+ }
+ #endregion
+
+ public override int GetHashCode ()
+ {
+ return (!KeyIsReferenceType || ((object) this.Key) != null ? this.Key.GetHashCode () : 0)
+ + 13*(!ValueIsReferenceType || ((object) this.Value) != null ? this.Value.GetHashCode () : 0);
+ }
+
+ public override string ToString ()
+ {
+ return string.Format ("({0}, {1})",
+ (!KeyIsReferenceType || ((object) this.Key) != null) ? this.Key.ToString () : "<null>",
+ (!ValueIsReferenceType || ((object) this.Value) != null) ? this.Value.ToString () : "<null>");
+ }
+ }
+}
--- /dev/null
+//
+// PriorityQueue.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ class PriorityQueue<T> {
+ private readonly Comparison<T> comparison;
+ private readonly List<T> values;
+
+ public PriorityQueue (Comparison<T> compare)
+ {
+ this.comparison = compare;
+ this.values = new List<T> ();
+ this.values.Add (default(T)); //fake cell for start from 1
+ }
+
+ public int Count
+ {
+ get { return this.values.Count - 1; }
+ }
+
+ public T Peek ()
+ {
+ if (Count == 0)
+ return default(T);
+
+ return this.values [1];
+ }
+
+ public T Dequeue ()
+ {
+ if (Count == 0)
+ return default(T);
+
+ T res = this.values [1];
+ this.values [1] = this.values [this.values.Count - 1];
+ this.values.RemoveAt (this.values.Count - 1);
+
+ BubbleDown (1);
+
+ return res;
+ }
+
+ public void Enqueue (T item)
+ {
+ this.values.Add (item);
+ BubbleUp (this.values.Count - 1);
+ }
+
+ private void BubbleDown (int i)
+ {
+ int l = i << 1;
+ int r = (i << 1) + 1;
+
+ int min = i;
+ if (l < this.values.Count && this.comparison (this.values [l], this.values [i]) < 0)
+ min = l;
+ if (r < this.values.Count && this.comparison (this.values [r], this.values [min]) < 0)
+ min = r;
+
+ if (min != i) {
+ T tmp = this.values [min];
+ this.values [min] = this.values [i];
+ this.values [i] = tmp;
+ BubbleDown (min);
+ }
+ }
+
+ private void BubbleUp (int i)
+ {
+ int c = i;
+
+ while (c/2 != 0 &&
+ this.comparison (this.values [c >> 1], this.values [c]) > 0) {
+ T tmp = this.values [c >> 1];
+ this.values [c >> 1] = this.values [c];
+ this.values [c] = tmp;
+
+ c >>= 1;
+ }
+ }
+ }
+}
--- /dev/null
+//
+// TypedKey.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ struct TypedKey {
+ private readonly string key;
+
+ public TypedKey (string key)
+ {
+ this.key = key;
+ }
+
+ public bool Equals (TypedKey other)
+ {
+ return Equals (other.key, this.key);
+ }
+
+ public override bool Equals (object obj)
+ {
+ if (ReferenceEquals (null, obj))
+ return false;
+ if (obj.GetType () != typeof (TypedKey))
+ return false;
+ return Equals ((TypedKey) obj);
+ }
+
+ public override int GetHashCode ()
+ {
+ return (this.key != null ? this.key.GetHashCode () : 0);
+ }
+ }
+}
--- /dev/null
+//
+// TypedProperties.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ class TypedProperties : ITypedProperties {
+ private readonly Dictionary<object, object> dictionary = new Dictionary<object, object> ();
+
+ #region Implementation of ITypedProperties
+ public bool Contains (TypedKey key)
+ {
+ return this.dictionary.ContainsKey (key);
+ }
+
+ public void Add<T> (TypedKey key, T value)
+ {
+ this.dictionary.Add (key, value);
+ }
+
+ public bool TryGetValue<T> (TypedKey key, out T value)
+ {
+ object result;
+
+ if (!this.dictionary.TryGetValue (key, out result)) {
+ value = default(T);
+ return false;
+ }
+
+ value = (T) result;
+ return true;
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// VisitStatus.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ enum VisitStatus {
+ ContinueVisit,
+ StopVisit
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// WorkList.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.DataStructures {
+ sealed class WorkList<T> : AbstractWorkList<T> {
+ private readonly Queue<T> queue;
+
+ public WorkList ()
+ {
+ this.queue = new Queue<T> ();
+ }
+
+ #region Overrides of AbstractWorkList<T>
+ protected override IEnumerable<T> Collection
+ {
+ get { return this.queue; }
+ }
+
+ protected override void AddToCollection (T o)
+ {
+ this.queue.Enqueue (o);
+ }
+
+ public override T Pull ()
+ {
+ if (this.queue.Count == 0)
+ throw new InvalidOperationException ();
+ T a = this.queue.Dequeue ();
+ this.Elements.Remove (a);
+ return a;
+ }
+ #endregion
+ }
+}
--- /dev/null
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Mono.CodeContracts.Static.Extensions {
+ static class Extensions {
+ public static string ToString<T>(this IEnumerable<T> values, string separator)
+ {
+ return string.Join (separator, values.Select (v => v.ToString ()));
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// EnvironmentDomain.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+using System.Linq;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Lattices {
+ class EnvironmentDomain<K, V> : IAbstractDomain<EnvironmentDomain<K, V>>
+ where V : IAbstractDomain<V>
+ where K : IEquatable<K> {
+ public static readonly EnvironmentDomain<K, V> BottomValue = new EnvironmentDomain<K, V> (null);
+ private static Func<K, int> KeyConverter;
+ private readonly IImmutableMap<K, V> map;
+
+ private EnvironmentDomain (IImmutableMap<K, V> map)
+ {
+ this.map = map;
+ }
+
+ public V this [K key]
+ {
+ get { return this.map == null ? default(V) : this.map [key]; }
+ }
+
+ public IEnumerable<K> Keys
+ {
+ get { return this.map.Keys; }
+ }
+
+ #region IAbstractDomain<EnvironmentDomain<K,V>> Members
+ public EnvironmentDomain<K, V> Top
+ {
+ get { return TopValue (KeyConverter); }
+ }
+
+ public EnvironmentDomain<K, V> Bottom
+ {
+ get { return BottomValue; }
+ }
+
+ public bool IsTop
+ {
+ get { return this.map != null && this.map.Count == 0; }
+ }
+
+ public bool IsBottom
+ {
+ get { return this.map == null; }
+ }
+
+ public EnvironmentDomain<K, V> Join (EnvironmentDomain<K, V> that, bool widening, out bool weaker)
+ {
+ weaker = false;
+ if (this.map == that.map || IsTop)
+ return this;
+ if (that.IsTop) {
+ weaker = !IsTop;
+ return that;
+ }
+ if (IsBottom) {
+ weaker = !that.IsBottom;
+ return that;
+ }
+ if (that.IsBottom)
+ return this;
+
+ IImmutableMap<K, V> min;
+ IImmutableMap<K, V> max;
+ GetMinAndMaxByCount (this.map, that.map, out min, out max);
+
+ IImmutableMap<K, V> intersect = min;
+ foreach (K key in min.Keys) {
+ if (!max.ContainsKey (key))
+ intersect = intersect.Remove (key);
+ else {
+ bool keyWeaker;
+ V join = min [key].Join (max [key], widening, out keyWeaker);
+ if (keyWeaker) {
+ weaker = true;
+ intersect = join.IsTop ? intersect.Remove (key) : intersect.Add (key, join);
+ }
+ }
+ }
+
+ weaker |= intersect.Count < this.map.Count;
+ return new EnvironmentDomain<K, V> (intersect);
+ }
+
+ public EnvironmentDomain<K, V> Meet (EnvironmentDomain<K, V> that)
+ {
+ if (this.map == that.map)
+ return this;
+ if (IsTop)
+ return that;
+ if (that.IsTop || IsBottom)
+ return this;
+ if (that.IsBottom)
+ return that;
+
+ IImmutableMap<K, V> min;
+ IImmutableMap<K, V> max;
+ GetMinAndMaxByCount (this.map, that.map, out min, out max);
+
+ IImmutableMap<K, V> union = max;
+ foreach (K key in min.Keys) {
+ if (!max.ContainsKey (key))
+ union = union.Add (key, min [key]);
+ else {
+ V meet = min [key].Meet (max [key]);
+ union = union.Add (key, meet);
+ }
+ }
+
+ return new EnvironmentDomain<K, V> (union);
+ }
+
+ public bool LessEqual (EnvironmentDomain<K, V> that)
+ {
+ if (that.IsTop || IsBottom)
+ return true;
+ if (IsTop || that.IsBottom || this.map.Count < that.map.Count)
+ return false;
+
+ return that.map.Keys.All (key => this.map.ContainsKey (key) && this.map [key].LessEqual (that.map [key]));
+ }
+
+ public EnvironmentDomain<K, V> ImmutableVersion ()
+ {
+ return this;
+ }
+
+ public EnvironmentDomain<K, V> Clone ()
+ {
+ return this;
+ }
+
+ public void Dump (TextWriter tw)
+ {
+ if (IsTop)
+ tw.WriteLine ("Top");
+ else if (IsBottom)
+ tw.WriteLine ("Bot");
+ else {
+ this.map.Visit ((k, v) => {
+ tw.WriteLine ("{0} -> {1}", k, v);
+ return VisitStatus.ContinueVisit;
+ });
+ }
+ }
+ #endregion
+
+ private static bool GetMinAndMaxByCount (IImmutableMap<K, V> a, IImmutableMap<K, V> b,
+ out IImmutableMap<K, V> min, out IImmutableMap<K, V> max)
+ {
+ if (a.Count < b.Count) {
+ min = a;
+ max = b;
+ return true;
+ }
+ max = a;
+ min = b;
+ return false;
+ }
+
+ public static EnvironmentDomain<K, V> TopValue (Func<K, int> keyConverter)
+ {
+ if (KeyConverter == null)
+ KeyConverter = keyConverter;
+
+ return new EnvironmentDomain<K, V> (ImmutableIntKeyMap<K, V>.Empty (KeyConverter));
+ }
+
+ public EnvironmentDomain<K, V> Add (K key, V value)
+ {
+ return new EnvironmentDomain<K, V> (this.map.Add (key, value));
+ }
+
+ public EnvironmentDomain<K, V> Remove (K key)
+ {
+ return new EnvironmentDomain<K, V> (this.map.Remove (key));
+ }
+
+ public bool Contains (K key)
+ {
+ return this.map.ContainsKey (key);
+ }
+
+ public EnvironmentDomain<K, V> Empty ()
+ {
+ return new EnvironmentDomain<K, V> (this.map.EmptyMap);
+ }
+ }
+}
--- /dev/null
+//
+// FlatDomain.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+
+namespace Mono.CodeContracts.Static.Lattices {
+ /// <summary>
+ /// Represents domain, where abstract values are disjunct, and their join/meet turns into Top/Bottom respectively
+ /// </summary>
+ /// <example>
+ /// Top
+ /// / | \
+ /// v1 v2 v3
+ /// \ | /
+ /// Bot
+ /// </example>
+ /// <typeparam name="T"></typeparam>
+ struct FlatDomain<T> : IAbstractDomain<FlatDomain<T>>, IEquatable<FlatDomain<T>>
+ where T : IEquatable<T> {
+ public static readonly FlatDomain<T> BottomValue = new FlatDomain<T> (Kind.Bottom);
+ public static readonly FlatDomain<T> TopValue = new FlatDomain<T> (Kind.Top);
+
+ public readonly T Concrete;
+ private readonly Kind _kind;
+
+ private FlatDomain (Kind kind)
+ {
+ this._kind = kind;
+ this.Concrete = default(T);
+ }
+
+ public FlatDomain (T value)
+ {
+ this._kind = Kind.Concrete;
+ this.Concrete = value;
+ }
+
+ public static implicit operator FlatDomain<T> (T value)
+ {
+ return new FlatDomain<T> (value);
+ }
+
+ #region Implementation of IAbstractDomain<FlatDomain<T>>
+ public bool IsNormal
+ {
+ get { return this._kind == Kind.Concrete; }
+ }
+
+ public FlatDomain<T> Top
+ {
+ get { return TopValue; }
+ }
+
+ public FlatDomain<T> Bottom
+ {
+ get { return BottomValue; }
+ }
+
+ public bool IsTop
+ {
+ get { return this._kind == Kind.Top; }
+ }
+
+ public bool IsBottom
+ {
+ get { return this._kind == Kind.Bottom; }
+ }
+
+ public FlatDomain<T> Join (FlatDomain<T> that, bool widening, out bool weaker)
+ {
+ if (IsTop || that.IsBottom) {
+ weaker = false;
+ return this;
+ }
+ if (that.IsTop) {
+ weaker = !IsTop;
+ return that;
+ }
+ if (IsBottom) {
+ weaker = !that.IsBottom;
+ return that;
+ }
+ if (this.Concrete.Equals (that.Concrete)) {
+ weaker = false;
+ return that;
+ }
+
+ weaker = true;
+ return TopValue;
+ }
+
+ public FlatDomain<T> Meet (FlatDomain<T> that)
+ {
+ if (IsTop || that.IsBottom)
+ return that;
+ if (that.IsTop || IsBottom)
+ return this;
+ if (this.Concrete.Equals (that.Concrete))
+ return that;
+
+ return BottomValue;
+ }
+
+ public bool LessEqual (FlatDomain<T> that)
+ {
+ if (that.IsTop || IsBottom)
+ return true;
+ if (IsTop || that.IsBottom)
+ return false;
+
+ //less equal means equality of values
+ return this.Concrete.Equals (that.Concrete);
+ }
+
+ public FlatDomain<T> ImmutableVersion ()
+ {
+ return this;
+ }
+
+ public FlatDomain<T> Clone ()
+ {
+ return this;
+ }
+
+ public void Dump (TextWriter tw)
+ {
+ if (IsTop)
+ tw.WriteLine ("Top");
+ else if (IsBottom)
+ tw.WriteLine ("Bot");
+ else
+ tw.WriteLine ("<{0}>", this.Concrete);
+ }
+
+ public override string ToString ()
+ {
+ if (IsTop)
+ return "Top";
+ if (IsBottom)
+ return "Bot";
+
+ return string.Format ("<{0}>", this.Concrete);
+ }
+ #endregion
+
+ #region Implementation of IEquatable<FlatDomain<T>>
+ public bool Equals (FlatDomain<T> that)
+ {
+ if (!this.IsNormal)
+ return this._kind == that._kind;
+
+ if (!that.IsNormal)
+ return false;
+
+ if (this.Concrete.Equals (that.Concrete))
+ return true;
+
+ return false;
+ }
+ #endregion
+
+ #region Nested type: Kind
+ private enum Kind : byte {
+ Top = 0,
+ Bottom,
+ Concrete
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// IAbstractDomain.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+
+namespace Mono.CodeContracts.Static.Lattices {
+ /// <summary>
+ /// Represents abstraction of concrete value
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ interface IAbstractDomain<T> {
+ /// <summary>
+ /// Represents universe set (which holds every value)
+ /// </summary>
+ T Top { get; }
+
+ /// <summary>
+ /// Represents empty set (which holds nothing)
+ /// </summary>
+ T Bottom { get; }
+
+ /// <summary>
+ /// Is this value a universe set
+ /// </summary>
+ bool IsTop { get; }
+
+ /// <summary>
+ /// Is this value an empty set
+ /// </summary>
+ bool IsBottom { get; }
+
+ /// <summary>
+ /// Returns a union of this and that
+ /// </summary>
+ /// <param name="that"></param>
+ /// <param name="widening">Specifies that widening-join operator must be used</param>
+ /// <param name="weaker">Returns that result domain is weaker than this</param>
+ /// <returns></returns>
+ T Join (T that, bool widening, out bool weaker);
+
+ /// <summary>
+ /// Returns an intersection of this and that
+ /// </summary>
+ /// <param name="that"></param>
+ /// <returns></returns>
+ T Meet (T that);
+
+ bool LessEqual (T that);
+
+ T ImmutableVersion ();
+ T Clone ();
+
+ void Dump (TextWriter tw);
+ }
+}
--- /dev/null
+//
+// SetDomain.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.IO;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Lattices {
+ struct SetDomain<T> : IAbstractDomain<SetDomain<T>>
+ where T : IEquatable<T> {
+ public static readonly SetDomain<T> TopValue = new SetDomain<T> (ImmutableSet<T>.Empty ());
+ public static readonly SetDomain<T> BottomValue = new SetDomain<T> ((IImmutableSet<T>) null);
+
+ private readonly IImmutableSet<T> set;
+
+ private SetDomain (IImmutableSet<T> set)
+ {
+ this.set = set;
+ }
+
+ public SetDomain (Func<T, int> keyConverter)
+ {
+ this.set = ImmutableSet<T>.Empty (keyConverter);
+ }
+
+ public SetDomain<T> Top
+ {
+ get { return TopValue; }
+ }
+
+ public SetDomain<T> Bottom
+ {
+ get { return BottomValue; }
+ }
+
+ public bool IsTop
+ {
+ get
+ {
+ if (this.set != null)
+ return this.set.Count == 0;
+
+ return false;
+ }
+ }
+
+ public bool IsBottom
+ {
+ get { return this.set == null; }
+ }
+
+ public SetDomain<T> Join (SetDomain<T> that, bool widening, out bool weaker)
+ {
+ if (this.set == that.set) {
+ weaker = false;
+ return this;
+ }
+ if (IsBottom) {
+ weaker = !that.IsBottom;
+ return that;
+ }
+ if (that.IsBottom || IsTop) {
+ weaker = false;
+ return this;
+ }
+ if (that.IsTop) {
+ weaker = !IsTop;
+ return that;
+ }
+
+ IImmutableSet<T> join = this.set.Intersect (that.set);
+
+ weaker = join.Count < this.set.Count;
+ return new SetDomain<T> (join);
+ }
+
+ public SetDomain<T> Meet (SetDomain<T> that)
+ {
+ if (this.set == that.set || IsBottom || that.IsTop)
+ return this;
+ if (that.IsBottom || IsTop)
+ return that;
+
+ return new SetDomain<T> (this.set.Union (that.set));
+ }
+
+ public bool LessEqual (SetDomain<T> that)
+ {
+ if (IsBottom)
+ return true;
+ if (that.IsBottom)
+ return false;
+
+ return that.set.IsContainedIn (this.set);
+ }
+
+ public SetDomain<T> ImmutableVersion ()
+ {
+ return this;
+ }
+
+ public SetDomain<T> Clone ()
+ {
+ return this;
+ }
+
+ public SetDomain<T> Add (T elem)
+ {
+ return new SetDomain<T> (this.set.Add (elem));
+ }
+
+ public SetDomain<T> Remove (T elem)
+ {
+ return new SetDomain<T> (this.set.Remove (elem));
+ }
+
+ public bool Contains (T item)
+ {
+ return this.set.Contains (item);
+ }
+
+ public void Dump (TextWriter tw)
+ {
+ if (IsBottom)
+ tw.WriteLine ("Bot");
+ else if (IsTop)
+ tw.WriteLine ("Top");
+ else
+ this.set.Dump (tw);
+ }
+ }
+}
--- /dev/null
+//
+// CodeContractDecoder.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+
+namespace Mono.CodeContracts.Static.Providers {
+ class CodeContractDecoder : IContractProvider {
+ public static readonly CodeContractDecoder Instance = new CodeContractDecoder ();
+
+ #region IContractProvider Members
+ public bool VerifyMethod (Method method, bool analyzeNonUserCode)
+ {
+ //todo: implement this
+ return true;
+ }
+
+ public bool HasRequires (Method method)
+ {
+ method = GetMethodWithContractFor (method);
+ if (method.MethodContract == null)
+ return false;
+
+ return method.MethodContract.RequiresCount > 0;
+ }
+
+ public Result AccessRequires<Data, Result> (Method method,
+ ICodeConsumer<Data, Result> consumer, Data data)
+ {
+ method = GetMethodWithContractFor (method);
+ return consumer.Accept (CodeProviderImpl.Instance, new CodeProviderImpl.PC (method.MethodContract, 0), data);
+ }
+
+ public bool HasEnsures (Method method)
+ {
+ method = GetMethodWithContractFor (method);
+ if (method.MethodContract == null)
+ return false;
+
+ return method.MethodContract.EnsuresCount > 0;
+ }
+
+ public Result AccessEnsures<Data, Result> (Method method, ICodeConsumer<Data, Result> consumer, Data data)
+ {
+ method = GetMethodWithContractFor (method);
+ return consumer.Accept (CodeProviderImpl.Instance, new CodeProviderImpl.PC (method.MethodContract, method.MethodContract.RequiresCount + 2), data);
+ }
+
+ public bool CanInheritContracts (Method method)
+ {
+ return false;
+ }
+ #endregion
+
+ private Method GetMethodWithContractFor (Method method)
+ {
+ //todo: implement this
+ return method;
+ }
+ }
+}
--- /dev/null
+//
+// CodeProviderImpl.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Providers {
+ class CodeProviderImpl : IMethodCodeProvider<CodeProviderImpl.PC, ExceptionHandler> {
+ public static readonly CodeProviderImpl Instance = new CodeProviderImpl ();
+
+ #region IMethodCodeProvider<PC,ExceptionHandler> Members
+ public Result Decode<Visitor, Data, Result> (PC pc, Visitor visitor, Data data)
+ where Visitor : IAggregateVisitor<PC, Data, Result>
+ {
+ Node nested;
+ Node node = Decode (pc, out nested);
+ if (IsAtomicNested (nested))
+ node = nested;
+ else if (nested != null)
+ return visitor.Aggregate (pc, new PC (nested), nested is Block, data);
+
+ if (node == null)
+ return visitor.Nop (pc, data);
+
+ switch (node.NodeType) {
+ case NodeType.Block:
+ case NodeType.Nop:
+ return visitor.Nop (pc, data);
+ case NodeType.Clt:
+ case NodeType.Lt:
+ return visitor.Binary (pc, BinaryOperator.Clt, Dummy.Value, Dummy.Value, Dummy.Value, data);
+ case NodeType.Cgt:
+ case NodeType.Gt:
+ return visitor.Binary (pc, BinaryOperator.Cgt, Dummy.Value, Dummy.Value, Dummy.Value, data);
+ case NodeType.Ceq:
+ case NodeType.Eq:
+ return visitor.Binary (pc, BinaryOperator.Ceq, Dummy.Value, Dummy.Value, Dummy.Value, data);
+ case NodeType.Ne:
+ return visitor.Binary (pc, BinaryOperator.Cne_Un, Dummy.Value, Dummy.Value, Dummy.Value, data);
+ case NodeType.Ge:
+ return visitor.Binary (pc, BinaryOperator.Cge, Dummy.Value, Dummy.Value, Dummy.Value, data);
+ case NodeType.Le:
+ return visitor.Binary (pc, BinaryOperator.Cle, Dummy.Value, Dummy.Value, Dummy.Value, data);
+ case NodeType.Add:
+ return visitor.Binary (pc, BinaryOperator.Add, Dummy.Value, Dummy.Value, Dummy.Value, data);
+ case NodeType.Sub:
+ return visitor.Binary (pc, BinaryOperator.Sub, Dummy.Value, Dummy.Value, Dummy.Value, data);
+ case NodeType.Rem:
+ return visitor.Binary (pc, BinaryOperator.Rem, Dummy.Value, Dummy.Value, Dummy.Value, data);
+ case NodeType.Rem_Un:
+ return visitor.Binary (pc, BinaryOperator.Rem_Un, Dummy.Value, Dummy.Value, Dummy.Value, data);
+ case NodeType.Mul:
+ return visitor.Binary (pc, BinaryOperator.Mul, Dummy.Value, Dummy.Value, Dummy.Value, data);
+ case NodeType.Div:
+ return visitor.Binary (pc, BinaryOperator.Div, Dummy.Value, Dummy.Value, Dummy.Value, data);
+ case NodeType.Div_Un:
+ return visitor.Binary (pc, BinaryOperator.Div_Un, Dummy.Value, Dummy.Value, Dummy.Value, data);
+ case NodeType.And:
+ return visitor.Binary (pc, BinaryOperator.And, Dummy.Value, Dummy.Value, Dummy.Value, data);
+ case NodeType.Or:
+ return visitor.Binary (pc, BinaryOperator.Or, Dummy.Value, Dummy.Value, Dummy.Value, data);
+ case NodeType.Shr:
+ return visitor.Binary (pc, BinaryOperator.Shr, Dummy.Value, Dummy.Value, Dummy.Value, data);
+ case NodeType.Xor:
+ return visitor.Binary (pc, BinaryOperator.Xor, Dummy.Value, Dummy.Value, Dummy.Value, data);
+ case NodeType.Shl:
+ return visitor.Binary (pc, BinaryOperator.Shl, Dummy.Value, Dummy.Value, Dummy.Value, data);
+ case NodeType.Shr_Un:
+ return visitor.Binary (pc, BinaryOperator.Shr_Un, Dummy.Value, Dummy.Value, Dummy.Value, data);
+ case NodeType.Literal:
+ var literal = (Literal) node;
+ if (literal.Value == null)
+ return visitor.LoadNull (pc, Dummy.Value, data);
+ if (literal.Type == CoreSystemTypes.Instance.TypeBoolean && (bool) literal.Value)
+ return visitor.LoadConst (pc, CoreSystemTypes.Instance.TypeInt32, 1, Dummy.Value, data);
+
+ return visitor.LoadConst (pc, literal.Type, literal.Value, Dummy.Value, data);
+ case NodeType.This:
+ case NodeType.Parameter:
+ return visitor.LoadArg (pc, (Parameter) node, false, Dummy.Value, data);
+ case NodeType.Local:
+ return visitor.LoadLocal (pc, (Local) node, Dummy.Value, data);
+ case NodeType.Branch:
+ var branch = (Branch) node;
+ if (branch.Condition != null)
+ return visitor.BranchTrue (pc, new PC (branch.Target), Dummy.Value, data);
+ return visitor.Branch (pc, new PC (branch.Target), branch.LeavesExceptionBlock, data);
+ case NodeType.ExpressionStatement:
+ break;
+ case NodeType.Box:
+ break;
+ case NodeType.Return:
+ return visitor.Return (pc, Dummy.Value, data);
+ case NodeType.Neg:
+ return visitor.Unary (pc, UnaryOperator.Neg, false, Dummy.Value, Dummy.Value, data);
+ case NodeType.Not:
+ case NodeType.LogicalNot:
+ return visitor.Unary (pc, UnaryOperator.Not, false, Dummy.Value, Dummy.Value, data);
+ case NodeType.Conv:
+ break;
+ case NodeType.Conv_I1:
+ return visitor.Unary (pc, UnaryOperator.Conv_i1, false, Dummy.Value, Dummy.Value, data);
+ case NodeType.Conv_I2:
+ return visitor.Unary (pc, UnaryOperator.Conv_i2, false, Dummy.Value, Dummy.Value, data);
+ case NodeType.Conv_I4:
+ return visitor.Unary (pc, UnaryOperator.Conv_i4, false, Dummy.Value, Dummy.Value, data);
+ case NodeType.Conv_I8:
+ return visitor.Unary (pc, UnaryOperator.Conv_i8, false, Dummy.Value, Dummy.Value, data);
+ case NodeType.Conv_R4:
+ return visitor.Unary (pc, UnaryOperator.Conv_r4, false, Dummy.Value, Dummy.Value, data);
+ case NodeType.Conv_R8:
+ return visitor.Unary (pc, UnaryOperator.Conv_r8, false, Dummy.Value, Dummy.Value, data);
+ case NodeType.MethodContract:
+ return visitor.Nop (pc, data);
+ case NodeType.Requires:
+ return visitor.Assume (pc, EdgeTag.Requires, Dummy.Value, data);
+ case NodeType.Call:
+ var call = (MethodCall) node;
+ Method method = GetMethodFrom (call.Callee);
+ if (method.HasGenericParameters)
+ throw new NotImplementedException ();
+ if (method.Name != null && method.DeclaringType.Name != null && method.DeclaringType.Name.EndsWith ("Contract")) {
+ switch (method.Name) {
+ case "Assume":
+ if (method.Parameters.Count == 1)
+ return visitor.Assume (pc, EdgeTag.Assume, Dummy.Value, data);
+ break;
+ case "Assert":
+ if (method.Parameters.Count == 1)
+ return visitor.Assert (pc, EdgeTag.Assert, Dummy.Value, data);
+ break;
+ }
+ }
+ Indexable<Dummy> parameters = DummyIndexable (method);
+ return visitor.Call (pc, method, false, GetVarargs (call, method), Dummy.Value, parameters, data);
+
+ case NodeType.AssignmentStatement:
+ var assign = ((AssignmentStatement) node);
+ var local = assign.Target as Local;
+ if (local != null)
+ return visitor.StoreLocal (pc, local, Dummy.Value, data);
+ var parameter = assign.Target as Parameter;
+ if (parameter != null)
+ return visitor.StoreArg (pc, parameter, Dummy.Value, data);
+
+ var binding = assign.Target as MemberBinding;
+ if (binding != null) {
+ if (binding.BoundMember.IsStatic)
+ return visitor.StoreStaticField (pc, (Field) binding.BoundMember, Dummy.Value, data);
+ else
+ return visitor.StoreField (pc, (Field) binding.BoundMember, Dummy.Value, Dummy.Value, data);
+ }
+
+ throw new NotImplementedException ();
+ case NodeType.Construct:
+ Method ctor = GetMethodFrom (((Construct) node).Constructor);
+ if (!(ctor.DeclaringType is ArrayTypeNode))
+ return visitor.NewObj (pc, ctor, Dummy.Value, DummyIndexable (ctor), data);
+ var arrayType = (ArrayTypeNode) ctor.DeclaringType;
+ return visitor.NewArray (pc, arrayType, Dummy.Value, DummyIndexable (ctor), data);
+ default:
+ return visitor.Nop (pc, data);
+ }
+
+ throw new NotImplementedException ();
+ }
+
+ public bool Next (PC pc, out PC nextLabel)
+ {
+ Node nested;
+ if (Decode (pc, out nested) == null && pc.Node != null) {
+ nextLabel = new PC (pc.Node, pc.Index + 1);
+ return true;
+ }
+ nextLabel = new PC ();
+ return false;
+ }
+
+ public int GetILOffset (PC current)
+ {
+ throw new NotImplementedException ();
+ }
+ #endregion
+
+ private static Indexable<Dummy> DummyIndexable (Method method)
+ {
+ return new Indexable<Dummy> (Enumerable.Range (0, method.Parameters.Count).Select (it => Dummy.Value).ToList ());
+ }
+
+ private static Indexable<TypeNode> GetVarargs (MethodCall call, Method method)
+ {
+ int methodCount = method.Parameters.Count;
+ int callCount = call.Arguments.Count;
+
+ if (callCount <= methodCount)
+ return new Indexable<TypeNode> (null);
+
+ var array = new TypeNode[callCount - methodCount];
+ for (int i = methodCount; i < callCount; i++)
+ array [i - methodCount] = call.Arguments [i - methodCount].Type;
+
+ return new Indexable<TypeNode> (array);
+ }
+
+ private Method GetMethodFrom (Expression callee)
+ {
+ return (Method) ((MemberBinding) callee).BoundMember;
+ }
+
+ private static bool IsAtomicNested (Node nested)
+ {
+ if (nested == null)
+ return false;
+ switch (nested.NodeType) {
+ case NodeType.Local:
+ case NodeType.Parameter:
+ case NodeType.Literal:
+ case NodeType.This:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private Node Decode (PC pc, out Node nested)
+ {
+ Node node = DecodeInflate (pc, out nested);
+
+ return node;
+ }
+
+ /// <summary>
+ /// Decodes pc
+ /// </summary>
+ /// <param name="pc"></param>
+ /// <param name="nested"></param>
+ /// <returns>If node has nested, returns null and (nested = child). If last child given, node equals pc.Node</returns>
+ private static Node DecodeInflate (PC pc, out Node nested)
+ {
+ Node node = pc.Node;
+ if (node == null) {
+ nested = null;
+ return null;
+ }
+
+ int index = pc.Index;
+ switch (node.NodeType) {
+ case NodeType.MethodContract:
+ var methodContract = (MethodContract) node;
+ if (index < methodContract.RequiresCount) {
+ nested = methodContract.Requires [index];
+ return null;
+ }
+ if (index == methodContract.RequiresCount) {
+ nested = null;
+ return methodContract;
+ }
+
+ //todo: aggregate ensures
+ nested = null;
+ return methodContract;
+
+ case NodeType.Requires:
+ var requires = (Requires) node;
+ if (index == 0) {
+ nested = requires.Assertion;
+ return null;
+ }
+ nested = null;
+ return requires;
+ case NodeType.Block:
+ var block = (Block) node;
+ if (block.Statements == null) {
+ nested = null;
+ return block;
+ }
+ nested = index >= block.Statements.Count ? null : block.Statements [index];
+ return index + 1 < block.Statements.Count ? null : block;
+ case NodeType.Return:
+ var ret = (Return) node;
+ if (ret.Expression != null && index == 0) {
+ nested = ret.Expression;
+ return null;
+ }
+ nested = null;
+ return ret;
+ case NodeType.AssignmentStatement:
+ var assign = (AssignmentStatement) node;
+ int innerIndex = index;
+ {
+ var bind = assign.Target as MemberBinding;
+ if (bind != null) {
+ ++innerIndex;
+ if (bind.BoundMember.IsStatic)
+ ++innerIndex;
+ if (innerIndex == 1) {
+ nested = bind.TargetObject;
+ return null;
+ }
+ } else if (assign.Target is Variable)
+ innerIndex += 2;
+ else {
+ nested = null;
+ return assign;
+ }
+ }
+ if (innerIndex == 2) {
+ nested = assign.Source;
+ return null;
+ }
+
+ nested = null;
+ return assign;
+ case NodeType.ExpressionStatement:
+ var expressionStatement = (ExpressionStatement) node;
+ nested = expressionStatement.Expression;
+ return expressionStatement;
+ case NodeType.MethodCall:
+ case NodeType.Call:
+ case NodeType.Calli:
+ case NodeType.CallVirt:
+ var methodCall = (MethodCall) node;
+ var binding = (MemberBinding) methodCall.Callee;
+ if (binding.BoundMember.IsStatic) {
+ if (index < methodCall.Arguments.Count) {
+ nested = methodCall.Arguments [index];
+ return null;
+ }
+
+ nested = null;
+ return methodCall;
+ }
+
+ if (index == 0) {
+ nested = binding.TargetObject;
+ return null;
+ }
+ if (index < methodCall.Arguments.Count + 1) {
+ nested = methodCall.Arguments [index - 1];
+ return null;
+ }
+ nested = null;
+ return methodCall;
+ case NodeType.MemberBinding:
+ var bind1 = ((MemberBinding) node);
+ if (index == 0 && !bind1.BoundMember.IsStatic) {
+ nested = bind1.TargetObject;
+ return null;
+ }
+ nested = null;
+ return bind1;
+ case NodeType.Construct:
+ var construct = (Construct) node;
+ if (index < construct.Arguments.Count) {
+ nested = construct.Arguments [index];
+ return null;
+ }
+ nested = null;
+ return construct;
+ case NodeType.Branch:
+ var branch = ((Branch) node);
+ if (branch.Condition != null && index == 0) {
+ nested = branch.Condition;
+ return null;
+ }
+ nested = null;
+ return branch;
+ default:
+ var binary = node as BinaryExpression;
+ if (binary != null) {
+ if (index == 0) {
+ nested = binary.Operand1;
+ return null;
+ }
+ if (index == 1) {
+ nested = binary.Operand2;
+ return null;
+ }
+ nested = null;
+ return binary;
+ }
+
+ var unary = node as UnaryExpression;
+ if (unary != null) {
+ if (index == 0) {
+ nested = unary.Operand;
+ return null;
+ }
+
+ nested = null;
+ return unary;
+ }
+
+ //todo: ternary
+ nested = null;
+ return node;
+ }
+ }
+
+ public PC Entry (Method method)
+ {
+ return new PC (method.Body);
+ }
+
+ #region Implementation of IMethodCodeProvider<PC,Local,Parameter,Method,FieldReference,TypeReference,Dummy>
+ public bool IsFaultHandler (ExceptionHandler handler)
+ {
+ return handler.HandlerType == NodeType.FaultHandler;
+ }
+
+ public bool IsFilterHandler (ExceptionHandler handler)
+ {
+ return handler.HandlerType == NodeType.Filter;
+ }
+
+ public bool IsFinallyHandler (ExceptionHandler handler)
+ {
+ return handler.HandlerType == NodeType.Finally;
+ }
+
+ public PC FilterExpressionStart (ExceptionHandler handler)
+ {
+ return new PC (handler.FilterExpression);
+ }
+
+ public PC HandlerEnd (ExceptionHandler handler)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public PC HandlerStart (ExceptionHandler handler)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public PC TryStart (ExceptionHandler handler)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public PC TryEnd (ExceptionHandler handler)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public bool IsCatchHandler (ExceptionHandler handler)
+ {
+ return handler.HandlerType == NodeType.Catch;
+ }
+
+ public TypeNode CatchType (ExceptionHandler handler)
+ {
+ return handler.FilterType;
+ }
+
+ public bool IsCatchAllHandler (ExceptionHandler handler)
+ {
+ if (!IsCatchHandler (handler))
+ return false;
+ if (handler.FilterType != null)
+ return false;
+
+ return true;
+ }
+
+ public IEnumerable<ExceptionHandler> GetTryBlocks (Method method)
+ {
+ yield break;
+ }
+ #endregion
+
+ #region Nested type: PC
+ public struct PC : IEquatable<PC> {
+ public readonly int Index;
+ public readonly Node Node;
+
+ public PC (Node Node)
+ : this (Node, 0)
+ {
+ }
+
+ public PC (Node node, int index)
+ {
+ this.Node = node;
+ this.Index = index;
+ }
+
+ #region IEquatable<PC> Members
+ public bool Equals (PC other)
+ {
+ return Equals (other.Node, this.Node) && other.Index == this.Index;
+ }
+ #endregion
+
+ public override bool Equals (object obj)
+ {
+ if (ReferenceEquals (null, obj))
+ return false;
+ if (obj.GetType () != typeof (PC))
+ return false;
+ return Equals ((PC) obj);
+ }
+
+ public override int GetHashCode ()
+ {
+ unchecked {
+ return ((this.Node != null ? this.Node.GetHashCode () : 0)*397) ^ this.Index;
+ }
+ }
+ }
+ #endregion
+ }
+}
--- /dev/null
+using Mono.CodeContracts.Static.AST.Visitors;
+
+namespace Mono.CodeContracts.Static.Providers {
+ interface ICodeProvider<Label> {
+ Result Decode<CodeVisitor, Data, Result> (Label pc, CodeVisitor visitor, Data data)
+ where CodeVisitor : IAggregateVisitor<Label, Data, Result>;
+
+ bool Next (Label current, out Label nextLabel);
+ int GetILOffset (Label current);
+ }
+}
--- /dev/null
+//
+// IContractProvider.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+
+namespace Mono.CodeContracts.Static.Providers {
+ interface IContractProvider {
+ bool VerifyMethod (Method method, bool analyzeNonUserCode);
+
+ bool HasRequires (Method method);
+ Result AccessRequires<Data, Result> (Method method, ICodeConsumer<Data, Result> consumer, Data data);
+
+ bool HasEnsures (Method method);
+ Result AccessEnsures<Data, Result> (Method method, ICodeConsumer<Data, Result> consumer, Data data);
+
+ bool CanInheritContracts (Method method);
+ }
+}
--- /dev/null
+//
+// IILDecoder.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST.Visitors;
+
+namespace Mono.CodeContracts.Static.Providers {
+ interface IILDecoder<Label, Source, Dest, TContext, TEdgeData> {
+ TContext ContextProvider { get; }
+
+ Result ForwardDecode<Data, Result, Visitor> (Label pc, Visitor visitor, Data state)
+ where Visitor : IILVisitor<Label, Source, Dest, Data, Result>;
+
+ bool IsUnreachable (Label pc);
+ TEdgeData EdgeData (Label from, Label to);
+ }
+}
--- /dev/null
+//
+// IMetaDataProvider.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Providers {
+ interface IMetaDataProvider {
+ TypeNode System_Int32 { get; }
+ TypeNode System_String { get; }
+ TypeNode System_Boolean { get; }
+ TypeNode System_IntPtr { get; }
+ TypeNode System_UIntPtr { get; }
+ TypeNode System_Void { get; }
+ TypeNode System_Array { get; }
+ TypeNode System_Object { get; }
+ TypeNode System_Int8 { get; }
+ TypeNode System_Int64 { get; }
+ TypeNode System_Int16 { get; }
+ TypeNode System_UInt8 { get; }
+ TypeNode System_UInt64 { get; }
+ TypeNode System_UInt32 { get; }
+ TypeNode System_UInt16 { get; }
+
+ Result AccessMethodBody<Data, Result> (Method method, IMethodCodeConsumer<Data, Result> consumer, Data data);
+
+ IEnumerable<Method> Methods (AssemblyNode assembly);
+ IEnumerable<Property> Properties (TypeNode type);
+ IEnumerable<Field> Fields (TypeNode type);
+ IEnumerable<TypeNode> Interfaces (TypeNode type);
+ IIndexable<Local> Locals (Method method);
+ IIndexable<Parameter> Parameters (Method method);
+
+ IEnumerable<Method> ImplementedMethods (Method method);
+ IEnumerable<Method> OverridenAndImplementedMethods (Method method);
+
+ Parameter This (Method method);
+
+ string Name (Local local);
+ string Name (Method method);
+ string Name (Field field);
+ string Name (TypeNode type);
+
+ string FullName (Method method);
+ string FullName (TypeNode type);
+
+ TypeNode FieldType (Field field);
+ TypeNode ParameterType (Parameter parameter);
+ TypeNode LocalType (Local local);
+ TypeNode ReturnType (Method method);
+ TypeNode ManagedPointer (TypeNode type);
+ TypeNode ElementType (TypeNode type);
+ TypeNode ArrayType (TypeNode type, int rank);
+
+
+ TypeNode DeclaringType (Method method);
+ TypeNode DeclaringType (Field field);
+
+ bool Equal (Method thisMethod, Method thatMethod);
+
+ bool IsMain (Method method);
+
+ bool IsStatic (Method method);
+ bool IsStatic (Field field);
+ bool IsStatic (Property property);
+
+ bool IsPrivate (Method method);
+
+ bool IsProtected (Method method);
+ bool IsProtected (Field field);
+
+ bool IsPublic (Method method);
+ bool IsPublic (Field field);
+
+ bool IsVirtual (Method method);
+ bool IsNewSlot (Method method);
+ bool IsOverride (Method method);
+ bool IsFinal (Method method);
+ bool IsConstructor (Method method);
+ bool IsAbstract (Method method);
+ bool IsCompilerGenerated (Field field);
+ bool IsCompilerGenerated (Method method);
+
+ bool IsAutoPropertyMember (Method method);
+ bool IsPropertySetter (Method method, out Property property);
+ bool IsPropertyGetter (Method method, out Property property);
+ bool HasSetter (Property property, out Method method);
+ bool HasGetter (Property property, out Method method);
+
+ bool HasBody (Method method);
+ bool DerivesFrom (TypeNode sub, TypeNode type);
+ bool Equal (TypeNode type, TypeNode otherType);
+
+ bool TryGetImplementingMethod (TypeNode type, Method calledMethod, out Method implementingMethod);
+ bool TryGetRootMethod (Method method, out Method rootMethod);
+
+ Field Unspecialized (Field field);
+ Method Unspecialized (Method method);
+ TypeNode Unspecialized (TypeNode type);
+
+ Method DeclaringMethod (Parameter parameter);
+
+ int ParameterIndex (Parameter parameter);
+ int ParameterStackIndex (Parameter parameter);
+
+ bool TryLoadAssembly (string filename, out AssemblyNode assembly, out string reasonOnFailure);
+
+ string Name (Parameter parameter);
+
+ bool IsReferenceType (TypeNode type);
+ bool IsManagedPointer (TypeNode value);
+ bool IsStruct (TypeNode type);
+ bool IsInterface (TypeNode type);
+ bool IsArray (TypeNode type);
+ bool IsVoid (TypeNode type);
+ bool IsReadonly (Field value);
+ bool IsFinalizer (Method method);
+ bool IsDispose (Method method);
+ bool IsVoidMethod (Method method);
+ bool IsOut (Parameter p);
+ bool IsPrimitive (TypeNode type);
+ bool IsClass (TypeNode type);
+
+ bool IsAsVisibleAs (Field value, Method method);
+ bool IsAsVisibleAs (Method value, Method method);
+ bool IsVisibleFrom (Field field, TypeNode declaringType);
+ bool IsVisibleFrom (Method value, TypeNode declaringType);
+ bool IsVisibleFrom (TypeNode type, TypeNode fromType);
+
+ bool TryGetSystemType (string fullName, out TypeNode type);
+
+ bool HasValueRepresentation (TypeNode type);
+
+ void IsSpecialized (Method calledMethod, ref IImmutableMap<TypeNode, TypeNode> specialization);
+ bool IsSpecialized (Method method);
+
+ bool IsFormalTypeParameter (TypeNode type);
+ bool IsMethodFormalTypeParameter (TypeNode type);
+
+ int TypeSize (TypeNode type);
+ }
+}
--- /dev/null
+//
+// IMethodCodeProvider.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using Mono.CodeContracts.Static.AST;
+
+namespace Mono.CodeContracts.Static.Providers {
+ interface IMethodCodeProvider<Label, Handler> : ICodeProvider<Label> {
+ bool IsFaultHandler (Handler handler);
+ bool IsFilterHandler (Handler handler);
+ bool IsCatchHandler (Handler handler);
+ bool IsCatchAllHandler (Handler handler);
+ bool IsFinallyHandler (Handler handler);
+
+ TypeNode CatchType (Handler handler);
+ IEnumerable<Handler> GetTryBlocks (Method method);
+
+ Label FilterExpressionStart (Handler handler);
+ Label HandlerEnd (Handler handler);
+ Label HandlerStart (Handler handler);
+ Label TryStart (Handler handler);
+ Label TryEnd (Handler handler);
+ }
+}
--- /dev/null
+//
+// MetaDataProvider.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.Cecil;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.ContractExtraction;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Providers {
+ class MetaDataProvider : IMetaDataProvider {
+ public static readonly MetaDataProvider Instance = new MetaDataProvider ();
+
+ #region IMetaDataProvider Members
+ public Result AccessMethodBody<Data, Result> (Method method, IMethodCodeConsumer<Data, Result> consumer, Data data)
+ {
+ return consumer.Accept (CodeProviderImpl.Instance, CodeProviderImpl.Instance.Entry (method), method, data);
+ }
+
+ public bool IsReferenceType (TypeNode type)
+ {
+ return (!type.IsValueType);
+ }
+
+ public Method DeclaringMethod (Parameter parameter)
+ {
+ return parameter.DeclaringMethod;
+ }
+
+ public int ParameterIndex (Parameter parameter)
+ {
+ return parameter.Index;
+ }
+
+ public bool IsVoidMethod (Method method)
+ {
+ return IsVoid (method.ReturnType);
+ }
+
+ public bool TryLoadAssembly (string filename, out AssemblyNode assembly, out string reasonOfFailure)
+ {
+ assembly = AssemblyNode.ReadAssembly (filename);
+ if (!TryLoadContractNodes (ref assembly)) {
+ reasonOfFailure = "Couldn't find CodeContracts assembly in referencing assemblies";
+ return false;
+ }
+ reasonOfFailure = null;
+ return true;
+ }
+
+ public TypeNode ReturnType (Method method)
+ {
+ return method.ReturnType;
+ }
+
+ public IIndexable<Parameter> Parameters (Method method)
+ {
+ return new Indexable<Parameter> (method.Parameters);
+ }
+
+ public Parameter This (Method method)
+ {
+ return method.ThisParameter;
+ }
+
+ public string Name (Method method)
+ {
+ return method.Name;
+ }
+
+ public string Name (Field field)
+ {
+ return field.Name;
+ }
+
+ public string Name (TypeNode type)
+ {
+ return type.Name;
+ }
+
+ public TypeNode FieldType (Field field)
+ {
+ return field.FieldType;
+ }
+
+ public string FullName (Method method)
+ {
+ return method.FullName;
+ }
+
+ public string FullName (TypeNode type)
+ {
+ return type.FullName;
+ }
+
+ public TypeNode DeclaringType (Field field)
+ {
+ return field.DeclaringType;
+ }
+
+ public bool IsMain (Method method)
+ {
+ MethodDefinition entryPoint = method.Definition.Module.EntryPoint;
+
+ return entryPoint != null && entryPoint.Equals (method);
+ }
+
+ public bool IsStatic (Method method)
+ {
+ return method.IsStatic;
+ }
+
+ public bool IsStatic (Field field)
+ {
+ return field.IsStatic;
+ }
+
+ public bool IsPrivate (Method method)
+ {
+ return method.IsPrivate;
+ }
+
+ public bool IsProtected (Method method)
+ {
+ return method.IsProtected;
+ }
+
+ public bool IsPublic (Method method)
+ {
+ return method.IsPublic;
+ }
+
+ public bool IsVirtual (Method method)
+ {
+ return method.IsVirtual;
+ }
+
+ public bool IsNewSlot (Method method)
+ {
+ return method.IsNewSlot;
+ }
+
+ public bool IsOverride (Method method)
+ {
+ return !method.IsNewSlot && method.HasOverrides;
+ }
+
+ public bool IsFinal (Method method)
+ {
+ return method.IsFinal;
+ }
+
+ public bool IsConstructor (Method method)
+ {
+ return method.IsConstructor;
+ }
+
+ public bool IsAbstract (Method method)
+ {
+ return method.IsAbstract;
+ }
+
+ public bool IsPropertySetter (Method method, out Property property)
+ {
+ //todo: implement this
+
+ property = null;
+ return false;
+ }
+
+ public bool IsPropertyGetter (Method method, out Property property)
+ {
+ //todo: implement this
+
+ property = null;
+ return false;
+ }
+
+ public TypeNode DeclaringType (Method method)
+ {
+ return method.DeclaringType;
+ }
+
+ public bool HasBody (Method method)
+ {
+ return method.HasBody;
+ }
+
+ public bool DerivesFrom (TypeNode sub, TypeNode type)
+ {
+ return sub.IsAssignableTo (type);
+ }
+
+ public bool Equal (TypeNode type, TypeNode otherType)
+ {
+ return type == otherType;
+ }
+
+ public bool TryGetImplementingMethod (TypeNode type, Method calledMethod, out Method implementingMethod)
+ {
+ //todo: implement this
+ implementingMethod = null;
+ return false;
+ }
+
+ public Method Unspecialized (Method method)
+ {
+ if (method.HasGenericParameters)
+ throw new NotImplementedException ();
+
+ return method;
+ }
+
+ public IEnumerable<Method> OverridenAndImplementedMethods (Method method)
+ {
+ //todo: implement this
+ yield break;
+ }
+
+ public TypeNode ManagedPointer (TypeNode type)
+ {
+ return type.GetReferenceType ();
+ }
+
+ public bool TryGetRootMethod (Method method, out Method rootMethod)
+ {
+ //todo: implement this
+ rootMethod = method;
+ return true;
+ }
+
+ public IEnumerable<Method> ImplementedMethods (Method method)
+ {
+ yield break;
+ }
+
+ public bool IsAutoPropertyMember (Method method)
+ {
+ //todo: implement this
+ return false;
+ }
+
+ public bool IsFinalizer (Method method)
+ {
+ return "Finalize" == method.Name;
+ }
+
+ public bool IsDispose (Method method)
+ {
+ if (method.Name != "Dispose" && method.Name != "System.IDisposable.Dispose")
+ return false;
+ if (method.Parameters == null || method.Parameters.Count == 0)
+ return true;
+ if (method.Parameters.Count == 1)
+ return method.Parameters [0].Type == CoreSystemTypes.Instance.TypeBoolean;
+
+ return false;
+ }
+ #endregion
+
+ #region Implementation of IMetaDataProvider<Local,Parameter,Method,FieldReference,PropertyReference,EventReference,TypeNode,Attribute,AssemblyNode>
+ public TypeNode System_Double
+ {
+ get { return CoreSystemTypes.Instance.TypeDouble; }
+ }
+
+ public TypeNode System_Single
+ {
+ get { return CoreSystemTypes.Instance.TypeSingle; }
+ }
+
+ public TypeNode System_Type
+ {
+ get { return CoreSystemTypes.Instance.TypeSystemType; }
+ }
+
+ public TypeNode System_Char
+ {
+ get { return CoreSystemTypes.Instance.TypeChar; }
+ }
+
+ public TypeNode System_Int32
+ {
+ get { return CoreSystemTypes.Instance.TypeInt32; }
+ }
+
+ public TypeNode System_String
+ {
+ get { return CoreSystemTypes.Instance.TypeString; }
+ }
+
+ public TypeNode System_Boolean
+ {
+ get { return CoreSystemTypes.Instance.TypeBoolean; }
+ }
+
+ public TypeNode System_IntPtr
+ {
+ get { return CoreSystemTypes.Instance.TypeIntPtr; }
+ }
+
+ public TypeNode System_UIntPtr
+ {
+ get { return CoreSystemTypes.Instance.TypeUIntPtr; }
+ }
+
+ public TypeNode System_Void
+ {
+ get { return CoreSystemTypes.Instance.TypeVoid; }
+ }
+
+ public TypeNode System_Array
+ {
+ get { return CoreSystemTypes.Instance.TypeArray; }
+ }
+
+ public TypeNode System_Object
+ {
+ get { return CoreSystemTypes.Instance.TypeObject; }
+ }
+
+ public TypeNode System_Int8
+ {
+ get { return CoreSystemTypes.Instance.TypeSByte; }
+ }
+
+ public TypeNode System_Int64
+ {
+ get { return CoreSystemTypes.Instance.TypeInt64; }
+ }
+
+ public TypeNode System_Int16
+ {
+ get { return CoreSystemTypes.Instance.TypeInt16; }
+ }
+
+ public TypeNode System_UInt8
+ {
+ get { return CoreSystemTypes.Instance.TypeByte; }
+ }
+
+ public TypeNode System_UInt64
+ {
+ get { return CoreSystemTypes.Instance.TypeUInt64; }
+ }
+
+ public TypeNode System_UInt32
+ {
+ get { return CoreSystemTypes.Instance.TypeUInt32; }
+ }
+
+ public TypeNode System_UInt16
+ {
+ get { return CoreSystemTypes.Instance.TypeUInt16; }
+ }
+
+ public IEnumerable<Method> Methods (AssemblyNode assembly)
+ {
+ return assembly.Modules.SelectMany (a => a.Types).SelectMany (t => t.Methods);
+ }
+
+ public string Name (Parameter parameter)
+ {
+ return parameter.Name;
+ }
+
+ public TypeNode ParameterType (Parameter parameter)
+ {
+ return parameter.Type;
+ }
+
+ public TypeNode LocalType (Local local)
+ {
+ return local.Type;
+ }
+
+ public bool IsStruct (TypeNode type)
+ {
+ return type.IsValueType;
+ }
+
+ public Field Unspecialized (Field field)
+ {
+ return field;
+ }
+
+ public bool IsManagedPointer (TypeNode value)
+ {
+ return value is Reference;
+ }
+
+ public bool IsArray (TypeNode type)
+ {
+ return type.IsArray;
+ }
+
+ public IEnumerable<TypeNode> Interfaces (TypeNode type)
+ {
+ return type.Interfaces;
+ }
+
+ public bool TryGetSystemType (string fullName, out TypeNode type)
+ {
+ int len = fullName.LastIndexOf (".");
+ string ns = "";
+ string className = fullName;
+ if (len > 0) {
+ ns = fullName.Substring (0, len);
+ className = fullName.Substring (len + 1);
+ }
+ type = CoreSystemTypes.Instance.SystemAssembly.GetType (ns, className);
+ return type != null;
+ }
+
+ public bool IsInterface (TypeNode type)
+ {
+ return type.IsInterface;
+ }
+
+ public IEnumerable<Property> Properties (TypeNode type)
+ {
+ return type.Properties;
+ }
+
+ public bool IsStatic (Property property)
+ {
+ return property.IsStatic;
+ }
+
+ public bool IsAsVisibleAs (Field value, Method method)
+ {
+ return HelperMethods.IsReferenceAsVisibleAs (value, method);
+ }
+
+ public bool IsAsVisibleAs (Method value, Method method)
+ {
+ return HelperMethods.IsReferenceAsVisibleAs (value, method);
+ }
+
+ public bool IsVisibleFrom (Field field, TypeNode declaringType)
+ {
+ return field.IsVisibleFrom (declaringType);
+ }
+
+ public bool IsVisibleFrom (Method value, TypeNode declaringType)
+ {
+ return value.IsVisibleFrom (declaringType);
+ }
+
+ public bool Equal (Method thisMethod, Method thatMethod)
+ {
+ return thisMethod == thatMethod;
+ }
+
+ public IIndexable<Local> Locals (Method method)
+ {
+ return new Indexable<Local> (method.Locals);
+ }
+
+ public TypeNode ElementType (TypeNode type)
+ {
+ var reference = type as Reference;
+ if (reference != null)
+ return reference.ElementType;
+ //todo: array
+
+ throw new NotImplementedException ();
+ }
+
+ public TypeNode Unspecialized (TypeNode type)
+ {
+ return type;
+ }
+
+ public bool IsProtected (Field field)
+ {
+ return field.IsFamily || field.IsFamilyAndAssembly || field.IsFamilyOrAssembly;
+ }
+
+ public bool IsPublic (Field field)
+ {
+ return field.IsPublic;
+ }
+
+ public int ParameterStackIndex (Parameter parameter)
+ {
+ Method declaringMethod = parameter.DeclaringMethod;
+ return declaringMethod.Parameters.Count + (declaringMethod.IsStatic ? 0 : 1) - parameter.Index - 1;
+ }
+
+ public bool HasGetter (Property property, out Method method)
+ {
+ if (property.HasGetter) {
+ method = property.Getter;
+ return true;
+ }
+ method = null;
+ return false;
+ }
+
+ public bool HasSetter (Property property, out Method method)
+ {
+ if (property.HasSetter) {
+ method = property.Setter;
+ return true;
+ }
+ method = null;
+ return false;
+ }
+
+ public bool IsReadonly (Field value)
+ {
+ return value.IsReadonly;
+ }
+
+ public bool HasValueRepresentation (TypeNode type)
+ {
+ return !IsStruct (type) || IsPrimitive (type) || IsEnum (type);
+ }
+
+ public bool IsVoid (TypeNode type)
+ {
+ return type.Equals (System_Void);
+ }
+
+ public void IsSpecialized (Method calledMethod, ref IImmutableMap<TypeNode, TypeNode> specialization)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public IEnumerable<Field> Fields (TypeNode type)
+ {
+ return type.Fields;
+ }
+
+ public bool IsOut (Parameter p)
+ {
+ return p.IsOut;
+ }
+
+ public bool IsPrimitive (TypeNode type)
+ {
+ return type.IsPrimitive;
+ }
+
+ public bool IsClass (TypeNode type)
+ {
+ return type.IsClass;
+ }
+
+ public bool IsVisibleFrom (TypeNode type, TypeNode fromType)
+ {
+ return type.IsVisibleFrom (fromType);
+ }
+
+ public bool IsCompilerGenerated (Method method)
+ {
+ return method.IsCompilerGenerated;
+ }
+
+ public bool IsSpecialized (Method method)
+ {
+ return false;
+ }
+
+ public bool IsFormalTypeParameter (TypeNode type)
+ {
+ return false;
+ }
+
+ public bool IsMethodFormalTypeParameter (TypeNode type)
+ {
+ return false;
+ }
+
+ public TypeNode ArrayType (TypeNode type, int rank)
+ {
+ return type.GetArrayType (rank);
+ }
+
+ public bool IsCompilerGenerated (Field field)
+ {
+ return field.IsCompilerGenerated;
+ }
+
+ public int TypeSize (TypeNode type)
+ {
+ int classSize = type.ClassSize;
+ if (classSize > 0)
+ return classSize;
+ int size = TypeSizeHelper (type);
+ type.ClassSize = size;
+ return size;
+ }
+
+ public string Name (Local local)
+ {
+ return local.Name;
+ }
+
+ private int TypeSizeHelper (TypeNode type)
+ {
+ if (IsManagedPointer (type))
+ return 4;
+ if (type == System_Boolean)
+ return 1;
+ if (type == System_Char)
+ return 2;
+ if (type == System_Int8)
+ return 1;
+ if (type == System_Int16)
+ return 2;
+ if (type == System_Int32)
+ return 4;
+ if (type == System_Int64)
+ return 8;
+ if (type == System_IntPtr || type == System_Object || type == System_String || type == System_Type)
+ return 4;
+
+ if (type == System_UInt8)
+ return 1;
+ if (type == System_UInt16)
+ return 2;
+ if (type == System_UInt32)
+ return 4;
+ if (type == System_UInt64)
+ return 8;
+
+ if (type == System_UIntPtr || type == System_Single)
+ return 4;
+ if (type == System_Double)
+ return 8;
+
+ return -1;
+ }
+
+ private bool IsEnum (TypeNode type)
+ {
+ return type.IsEnum;
+ }
+ #endregion
+
+ private bool TryLoadContractNodes (ref AssemblyNode assembly)
+ {
+ ContractNodes nodes = null;
+ foreach (Module module in assembly.Modules) {
+ IAssemblyResolver assemblyResolver = module.Definition.AssemblyResolver;
+ foreach (AssemblyNameReference reference in module.Definition.AssemblyReferences) {
+ AssemblyDefinition def = assemblyResolver.Resolve (reference);
+ nodes = ContractNodes.GetContractNodes (new AssemblyNode (def), (s) => { });
+ if (nodes != null)
+ break;
+ }
+ }
+
+ if (nodes == null)
+ return false;
+
+ var extractor = new ContractExtractor (nodes, assembly, true);
+ assembly = (AssemblyNode) extractor.Visit (assembly);
+ return true;
+ }
+ }
+}
--- /dev/null
+//
+// AssertionFinder.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.Analysis.Drivers;
+using Mono.CodeContracts.Static.ControlFlow;
+
+namespace Mono.CodeContracts.Static.Proving {
+ static class AssertionFinder {
+ public static void ValidateAssertions<TExpression, TVariable> (IFactQuery<BoxedExpression, TVariable> facts, IMethodDriver<TExpression, TVariable> driver, List<string> proofResults)
+ where TExpression : IEquatable<TExpression>
+ where TVariable : IEquatable<TVariable>
+ {
+ Bind<TExpression, TVariable>.ValidateAssertions (facts, driver, proofResults);
+ }
+
+ #region Nested type: Bind
+ private static class Bind<TExpression, TVariable>
+ where TExpression : IEquatable<TExpression>
+ where TVariable : IEquatable<TVariable> {
+ public static void ValidateAssertions (IFactQuery<BoxedExpression, TVariable> facts, IMethodDriver<TExpression, TVariable> driver, List<string> proofResults)
+ {
+ APC entryAfterRequires = driver.ContextProvider.MethodContext.CFG.EntryAfterRequires;
+ if (facts.IsUnreachable (entryAfterRequires)) {
+ proofResults.Add ("Method precondition is unsatisfiable");
+ return;
+ }
+
+ object assertStats;
+ foreach (AssertionObligation obl in GetAssertions (driver, out assertStats)) {
+ ProofOutcome outcome = facts.IsTrue (obl.Apc, BoxedExpression.For (driver.ContextProvider.ExpressionContext.Refine (obl.Apc, obl.Condition), driver.ExpressionDecoder));
+
+ string pc = obl.Apc.ToString ();
+ switch (outcome) {
+ case ProofOutcome.Top:
+ proofResults.Add ("Assertion at point " + pc + " is unproven");
+ break;
+ case ProofOutcome.True:
+ proofResults.Add ("Assertion at point " + pc + " is true");
+ break;
+ case ProofOutcome.False:
+ proofResults.Add ("Assertion at point " + pc + " is false");
+ break;
+ case ProofOutcome.Bottom:
+ proofResults.Add ("Assertion at point " + pc + " is unreachable");
+ break;
+ }
+ }
+ }
+
+ private static IEnumerable<AssertionObligation> GetAssertions (IMethodDriver<TExpression, TVariable> driver, out object assertStats)
+ {
+ var analysis = new AssertionCrawlerAnalysis ();
+ List<AssertionObligation> obligations = analysis.Gather (driver);
+
+ assertStats = null;
+ return obligations;
+ }
+
+ #region Nested type: AssertionCrawlerAnalysis
+ private class AssertionCrawlerAnalysis : ValueCodeVisitor<TVariable> {
+ private readonly List<AssertionObligation> Obligations = new List<AssertionObligation> ();
+
+ public List<AssertionObligation> Gather (IMethodDriver<TExpression, TVariable> driver)
+ {
+ Run (driver.ValueLayer);
+ return this.Obligations;
+ }
+
+ public override bool Assert (APC pc, EdgeTag tag, TVariable condition, bool data)
+ {
+ if (pc.InsideRequiresAtCallInsideContract)
+ return data;
+
+ this.Obligations.Add (new AssertionObligation (pc, tag, condition));
+ return data;
+ }
+
+ public override bool Assume (APC pc, EdgeTag tag, TVariable condition, bool data)
+ {
+ if (!pc.InsideRequiresAtCallInsideContract && tag == EdgeTag.Assume)
+ this.Obligations.Add (new AssertionObligation (pc, tag, condition, true));
+
+ return data;
+ }
+ }
+ #endregion
+
+ #region Nested type: AssertionObligation
+ private class AssertionObligation {
+ public readonly APC Apc;
+ public readonly TVariable Condition;
+ public readonly bool IsAssume;
+ public readonly EdgeTag Tag;
+
+ public AssertionObligation (APC pc, EdgeTag tag, TVariable cond)
+ : this (pc, tag, cond, false)
+ {
+ }
+
+ public AssertionObligation (APC pc, EdgeTag tag, TVariable cond, bool isAssume)
+ {
+ this.Apc = pc;
+ this.Tag = tag;
+ this.Condition = cond;
+ this.IsAssume = isAssume;
+ }
+ }
+ #endregion
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// BasicFacts.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.Analysis;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Proving {
+ class BasicFacts<Expression, Variable> : IFactQuery<BoxedExpression, Variable> {
+ protected IExpressionContextProvider<Expression, Variable> ContextProvider;
+ protected IFactBase<Variable> FactBase;
+ protected Predicate<APC> isUnreachable;
+
+ public BasicFacts (IExpressionContextProvider<Expression, Variable> contextProvider, IFactBase<Variable> factBase, Predicate<APC> isUnreachable)
+ {
+ this.ContextProvider = contextProvider;
+ this.FactBase = factBase;
+ this.isUnreachable = isUnreachable;
+ }
+
+ #region Implementation of IFactBase<Variable>
+ public ProofOutcome IsNull (APC pc, Variable variable)
+ {
+ return this.FactBase.IsNull (pc, variable);
+ }
+
+ public ProofOutcome IsNonNull (APC pc, Variable variable)
+ {
+ return this.FactBase.IsNonNull (pc, variable);
+ }
+
+ public bool IsUnreachable (APC pc)
+ {
+ if (this.isUnreachable != null && this.isUnreachable (pc))
+ return true;
+
+ return this.FactBase.IsUnreachable (pc);
+ }
+
+ protected static bool TryVariable (BoxedExpression e, out Variable v)
+ {
+ object underlyingVariable = e.UnderlyingVariable;
+ if (underlyingVariable is Variable) {
+ v = (Variable) underlyingVariable;
+ return true;
+ }
+
+ v = default(Variable);
+ return false;
+ }
+ #endregion
+
+ #region Implementation of IFactQuery<BoxedExpression,Variable>
+ public virtual ProofOutcome IsNull (APC pc, BoxedExpression expr)
+ {
+ Variable v;
+ if (TryVariable (expr, out v)) {
+ ProofOutcome outcome = this.FactBase.IsNull (pc, v);
+ if (outcome != ProofOutcome.Top)
+ return outcome;
+ }
+ return ProofOutcome.Top;
+ }
+
+ public virtual ProofOutcome IsNonNull (APC pc, BoxedExpression expr)
+ {
+ Variable v;
+ if (TryVariable (expr, out v)) {
+ ProofOutcome outcome = this.FactBase.IsNonNull (pc, v);
+ if (outcome != ProofOutcome.Top)
+ return outcome;
+ }
+ return ProofOutcome.Top;
+ }
+
+ public ProofOutcome IsTrue (APC pc, BoxedExpression expr)
+ {
+ return IsNonZero (pc, expr);
+ }
+
+ public ProofOutcome IsTrueImply (APC pc, LispList<BoxedExpression> positiveAssumptions, LispList<BoxedExpression> negativeAssumptions, BoxedExpression goal)
+ {
+ ProofOutcome outcome = IsTrue (pc, goal);
+ switch (outcome) {
+ case ProofOutcome.True:
+ case ProofOutcome.Bottom:
+ return outcome;
+ default:
+ return ProofOutcome.Top;
+ }
+ }
+
+ public ProofOutcome IsGreaterEqualToZero (APC pc, BoxedExpression expr)
+ {
+ return ProofOutcome.Top;
+ }
+
+ public ProofOutcome IsLessThan (APC pc, BoxedExpression expr, BoxedExpression right)
+ {
+ return ProofOutcome.Top;
+ }
+
+ public ProofOutcome IsNonZero (APC pc, BoxedExpression expr)
+ {
+ return IsNonNull (pc, expr);
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// BoxedExpression.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.AST.Visitors;
+using Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding;
+using Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Proving {
+ internal abstract class BoxedExpression {
+ public virtual bool IsVariable
+ {
+ get { return false; }
+ }
+
+ public virtual bool IsBooleanTyped
+ {
+ get { return false; }
+ }
+
+ public virtual object UnderlyingVariable
+ {
+ get { return false; }
+ }
+
+ public virtual PathElement[] AccessPath
+ {
+ get { return null; }
+ }
+
+ public virtual bool IsConstant
+ {
+ get { return false; }
+ }
+
+ public virtual object Constant
+ {
+ get { throw new InvalidOperationException (); }
+ }
+
+ public virtual object ConstantType
+ {
+ get { throw new InvalidOperationException (); }
+ }
+
+ public virtual bool IsSizeof
+ {
+ get { return false; }
+ }
+
+ public virtual bool IsUnary
+ {
+ get { return false; }
+ }
+
+ public virtual UnaryOperator UnaryOperator
+ {
+ get { throw new InvalidOperationException (); }
+ }
+
+ public virtual BoxedExpression UnaryArgument
+ {
+ get { throw new InvalidOperationException (); }
+ }
+
+ public virtual bool IsBinary
+ {
+ get { return false; }
+ }
+
+ public virtual BinaryOperator BinaryOperator
+ {
+ get { throw new InvalidOperationException (); }
+ }
+
+ public virtual BoxedExpression BinaryLeftArgument
+ {
+ get { throw new InvalidOperationException (); }
+ }
+
+ public virtual BoxedExpression BinaryRightArgument
+ {
+ get { throw new InvalidOperationException (); }
+ }
+
+ public virtual bool IsIsinst
+ {
+ get { return false; }
+ }
+
+ public virtual bool IsNull
+ {
+ get { return false; }
+ }
+
+ public virtual bool IsCast
+ {
+ get { return false; }
+ }
+
+ public virtual bool IsResult
+ {
+ get { return false; }
+ }
+
+ public virtual bool TryGetType (out object type)
+ {
+ type = null;
+ return false;
+ }
+
+ public virtual bool IsBinaryExpression (out BinaryOperator op, out BoxedExpression left, out BoxedExpression right)
+ {
+ op = BinaryOperator.Add;
+ left = null;
+ right = null;
+ return false;
+ }
+
+ public virtual bool IsUnaryExpression (out UnaryOperator op, out BoxedExpression argument)
+ {
+ op = UnaryOperator.Conv_i;
+ argument = null;
+ return false;
+ }
+
+ public virtual bool IsIsinstExpression (out BoxedExpression expr, out TypeNode type)
+ {
+ expr = null;
+ type = null;
+ return false;
+ }
+
+ public abstract void AddFreeVariables (HashSet<BoxedExpression> set);
+
+ public virtual BoxedExpression Substitute (BoxedExpression what, BoxedExpression replace)
+ {
+ if (this == what || Equals (what))
+ return replace;
+
+ return RecursiveSubstitute (what, replace);
+ }
+
+ public abstract BoxedExpression Substitute<Variable> (Func<Variable, BoxedExpression, BoxedExpression> map);
+
+ protected internal virtual BoxedExpression RecursiveSubstitute (BoxedExpression what, BoxedExpression replace)
+ {
+ return this;
+ }
+
+ public abstract Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
+ where Visitor : IILVisitor<PC, Dummy, Dummy, Data, Result>;
+
+ public static BoxedExpression Var (object var)
+ {
+ return new VariableExpression (var);
+ }
+
+ public static BoxedExpression For<Variable, Expression> (Expression external, IFullExpressionDecoder<Variable, Expression> decoder)
+ where Expression : IEquatable<Expression>
+ {
+ return new ExternalBox<Variable, Expression> (external, decoder);
+ }
+
+ public static BoxedExpression MakeIsinst (TypeNode type, BoxedExpression arg)
+ {
+ return new IsinstExpression (arg, type);
+ }
+
+ public static BoxedExpression Convert<Variable, ExternalExpression> (ExternalExpression expr, IFullExpressionDecoder<Variable, ExternalExpression> decoder)
+ {
+ TypeNode type;
+ object value;
+ if (decoder.IsConstant (expr, out value, out type))
+ return new ConstantExpression (value, type);
+ if (decoder.IsNull (expr))
+ return new ConstantExpression (null, null);
+
+ object variable;
+ if (decoder.IsVariable (expr, out variable)) {
+ LispList<PathElement> variableAccessPath = decoder.GetVariableAccessPath (expr);
+ return new VariableExpression (variable, variableAccessPath);
+ }
+
+ if (decoder.IsSizeof (expr, out type)) {
+ int sizeAsConstant;
+ return decoder.TrySizeOfAsConstant (expr, out sizeAsConstant) ? new SizeOfExpression (type, sizeAsConstant) : new SizeOfExpression (type);
+ }
+
+ ExternalExpression arg;
+ if (decoder.IsIsinst (expr, out arg, out type))
+ return new IsinstExpression (Convert (arg, decoder), type);
+
+ UnaryOperator op;
+ if (decoder.IsUnaryExpression (expr, out op, out arg))
+ return new UnaryExpression (op, Convert (arg, decoder));
+
+ BinaryOperator bop;
+ ExternalExpression left;
+ ExternalExpression right;
+ if (!decoder.IsBinaryExpression (expr, out bop, out left, out right))
+ throw new InvalidOperationException ();
+
+ return new BinaryExpression (bop, Convert (left, decoder), Convert (right, decoder));
+ }
+
+ #region Nested type: AssertExpression
+ public class AssertExpression : ContractExpression {
+ public AssertExpression (BoxedExpression condition, EdgeTag tag, APC pc) : base (condition, tag, pc)
+ {
+ }
+
+ #region Overrides of ContractExpression
+ public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
+ {
+ return visitor.Assert (pc, this.Tag, Dummy.Value, data);
+ }
+
+ public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
+ {
+ BoxedExpression cond = this.Condition.Substitute (map);
+ if (cond == this.Condition)
+ return this;
+ if (cond == null)
+ return null;
+
+ return new AssertExpression (cond, this.Tag, this.Apc);
+ }
+ #endregion
+ }
+ #endregion
+
+ #region Nested type: AssumeExpression
+ public class AssumeExpression : ContractExpression {
+ public AssumeExpression (BoxedExpression condition, EdgeTag tag, APC pc)
+ : base (condition, tag, pc)
+ {
+ }
+
+ #region Overrides of ContractExpression
+ public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
+ {
+ return visitor.Assume (pc, this.Tag, Dummy.Value, data);
+ }
+
+ public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
+ {
+ BoxedExpression cond = this.Condition.Substitute (map);
+ if (cond == this.Condition)
+ return this;
+ if (cond == null)
+ return null;
+
+ return new AssumeExpression (cond, this.Tag, this.Apc);
+ }
+ #endregion
+ }
+ #endregion
+
+ #region Nested type: BinaryExpression
+ public class BinaryExpression : BoxedExpression {
+ public readonly BoxedExpression Left;
+ public readonly BinaryOperator Op;
+ public readonly BoxedExpression Right;
+
+ public BinaryExpression (BinaryOperator op, BoxedExpression left, BoxedExpression right)
+ {
+ this.Op = op;
+ this.Left = left;
+ this.Right = right;
+ }
+
+ public override bool IsBinary
+ {
+ get { return true; }
+ }
+
+ public override BoxedExpression BinaryLeftArgument
+ {
+ get { return this.Left; }
+ }
+
+ public override BoxedExpression BinaryRightArgument
+ {
+ get { return this.Right; }
+ }
+
+ public override BinaryOperator BinaryOperator
+ {
+ get { return this.Op; }
+ }
+
+ public override bool IsBinaryExpression (out BinaryOperator op, out BoxedExpression left, out BoxedExpression right)
+ {
+ op = this.Op;
+ left = this.Left;
+ right = this.Right;
+ return true;
+ }
+
+ #region Overrides of BoxedExpression
+ public override void AddFreeVariables (HashSet<BoxedExpression> set)
+ {
+ this.Left.AddFreeVariables (set);
+ this.Right.AddFreeVariables (set);
+ }
+
+ protected internal override BoxedExpression RecursiveSubstitute (BoxedExpression what, BoxedExpression replace)
+ {
+ BoxedExpression left = this.Left.Substitute (what, replace);
+ BoxedExpression right = this.Right.Substitute (what, replace);
+ if (left == this.Left && right == this.Right)
+ return this;
+
+ return new BinaryExpression (this.Op, left, right);
+ }
+
+ public override BoxedExpression Substitute<Variable> (Func<Variable, BoxedExpression, BoxedExpression> map)
+ {
+ BoxedExpression left = this.Left.Substitute (map);
+ if (left == null)
+ return null;
+
+ BoxedExpression right = this.Right.Substitute (map);
+ if (right == null)
+ return null;
+
+ if (this.Left == left && this.Right == right)
+ return this;
+ return new BinaryExpression (this.Op, left, right);
+ }
+
+ public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
+ {
+ return visitor.Binary (pc, this.Op, Dummy.Value, Dummy.Value, Dummy.Value, data);
+ }
+ #endregion
+ }
+ #endregion
+
+ #region Nested type: CastExpression
+ public class CastExpression : BoxedExpression {
+ public readonly TypeNode CastToType;
+ public readonly BoxedExpression Expr;
+
+ public CastExpression (TypeNode castToType, BoxedExpression expr)
+ {
+ this.CastToType = castToType;
+ this.Expr = expr;
+ }
+
+ public override bool IsCast
+ {
+ get { return true; }
+ }
+
+ public override PathElement[] AccessPath
+ {
+ get { return this.Expr.AccessPath; }
+ }
+
+ public override BoxedExpression BinaryLeftArgument
+ {
+ get { return this.Expr.BinaryLeftArgument; }
+ }
+
+ public override BoxedExpression BinaryRightArgument
+ {
+ get { return this.Expr.BinaryRightArgument; }
+ }
+
+ public override BinaryOperator BinaryOperator
+ {
+ get { return this.Expr.BinaryOperator; }
+ }
+
+ public override object Constant
+ {
+ get { return this.Expr.Constant; }
+ }
+
+ public override object ConstantType
+ {
+ get { return this.Expr.ConstantType; }
+ }
+
+ public override bool IsBinary
+ {
+ get { return this.Expr.IsBinary; }
+ }
+
+ public override bool IsBooleanTyped
+ {
+ get { return this.Expr.IsBooleanTyped; }
+ }
+
+ public override bool IsConstant
+ {
+ get { return this.Expr.IsConstant; }
+ }
+
+
+ public override bool IsSizeof
+ {
+ get { return this.Expr.IsSizeof; }
+ }
+
+ public override bool IsNull
+ {
+ get { return this.Expr.IsNull; }
+ }
+
+ public override bool IsIsinst
+ {
+ get { return this.Expr.IsIsinst; }
+ }
+
+ public override bool IsResult
+ {
+ get { return this.Expr.IsResult; }
+ }
+
+ public override bool IsUnary
+ {
+ get { return this.Expr.IsUnary; }
+ }
+
+ public override bool IsVariable
+ {
+ get { return this.Expr.IsVariable; }
+ }
+
+ public override BoxedExpression UnaryArgument
+ {
+ get { return this.Expr.UnaryArgument; }
+ }
+
+ public override UnaryOperator UnaryOperator
+ {
+ get { return this.Expr.UnaryOperator; }
+ }
+
+ public override object UnderlyingVariable
+ {
+ get { return this.Expr.UnderlyingVariable; }
+ }
+
+
+ public override void AddFreeVariables (HashSet<BoxedExpression> set)
+ {
+ this.Expr.AddFreeVariables (set);
+ }
+
+ public override BoxedExpression Substitute<Variable> (Func<Variable, BoxedExpression, BoxedExpression> map)
+ {
+ return this.Expr.Substitute (map);
+ }
+
+ public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
+ {
+ return this.Expr.ForwardDecode<Data, Result, Visitor> (pc, visitor, data);
+ }
+
+ public override bool IsBinaryExpression (out BinaryOperator op, out BoxedExpression left, out BoxedExpression right)
+ {
+ return this.Expr.IsBinaryExpression (out op, out left, out right);
+ }
+
+ protected internal override BoxedExpression RecursiveSubstitute (BoxedExpression what, BoxedExpression replace)
+ {
+ return this.Expr.RecursiveSubstitute (what, replace);
+ }
+
+ public override BoxedExpression Substitute (BoxedExpression what, BoxedExpression replace)
+ {
+ return this.Expr.Substitute (what, replace);
+ }
+
+ public override bool IsUnaryExpression (out UnaryOperator op, out BoxedExpression argument)
+ {
+ return this.Expr.IsUnaryExpression (out op, out argument);
+ }
+ }
+ #endregion
+
+ #region Nested type: ConstantExpression
+ public class ConstantExpression : BoxedExpression {
+ public readonly TypeNode Type;
+ public readonly object Value;
+ private readonly bool is_boolean;
+
+ public ConstantExpression (object value, TypeNode type)
+ : this (value, type, false)
+ {
+ }
+
+ public ConstantExpression (object value, TypeNode type, bool isBoolean)
+ {
+ this.Value = value;
+ this.Type = type;
+ this.is_boolean = isBoolean;
+ }
+
+ public override bool IsBooleanTyped
+ {
+ get { return this.is_boolean; }
+ }
+
+ public override bool IsConstant
+ {
+ get { return true; }
+ }
+
+ public override object Constant
+ {
+ get { return this.Value; }
+ }
+
+ public override object ConstantType
+ {
+ get { return this.Type; }
+ }
+
+ public override bool IsNull
+ {
+ get
+ {
+ if (this.Value == null)
+ return true;
+
+ var conv = this.Value as IConvertible;
+ if (conv != null) {
+ try {
+ if (conv.ToInt32 (null) == 0)
+ return true;
+ } catch {
+ return false;
+ }
+ }
+
+ return false;
+ }
+ }
+
+ public override void AddFreeVariables (HashSet<BoxedExpression> set)
+ {
+ }
+
+ public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
+ {
+ return this;
+ }
+
+ public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
+ {
+ if (this.Value == null)
+ return visitor.LoadNull (pc, Dummy.Value, data);
+
+ return visitor.LoadConst (pc, this.Type, this.Value, Dummy.Value, data);
+ }
+ }
+ #endregion
+
+ #region Nested type: ContractExpression
+ public abstract class ContractExpression : BoxedExpression {
+ public readonly APC Apc;
+ public readonly BoxedExpression Condition;
+ public readonly EdgeTag Tag;
+
+ public ContractExpression (BoxedExpression condition, EdgeTag tag, APC pc)
+ {
+ this.Tag = tag;
+ this.Condition = condition;
+ this.Apc = pc;
+ }
+
+ public override void AddFreeVariables (HashSet<BoxedExpression> set)
+ {
+ this.Condition.AddFreeVariables (set);
+ }
+
+ public abstract override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data);
+ public abstract override BoxedExpression Substitute<Variable> (Func<Variable, BoxedExpression, BoxedExpression> map);
+ }
+ #endregion
+
+ #region Nested type: ExternalBox
+ public class ExternalBox<Variable, LabeledSymbol> : BoxedExpression
+ where LabeledSymbol : IEquatable<LabeledSymbol> {
+ private readonly IFullExpressionDecoder<Variable, LabeledSymbol> decoder;
+ private readonly LabeledSymbol expr;
+ private Optional<Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression>> binary;
+
+ private Optional<Tuple<bool, object, TypeNode>> constant;
+ private Optional<Tuple<bool, BoxedExpression, TypeNode>> isInst;
+ private Optional<Pair<bool, object>> isVar;
+ private Optional<Pair<bool, TypeNode>> type;
+ private Optional<Tuple<bool, UnaryOperator, BoxedExpression>> unary;
+ private Optional<object> var;
+
+ public ExternalBox (LabeledSymbol external, IFullExpressionDecoder<Variable, LabeledSymbol> decoder)
+ {
+ this.expr = external;
+ this.decoder = decoder;
+ }
+
+ public override bool IsBinary
+ {
+ get
+ {
+ Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression> binary;
+ TryGetBinaryFromCache (out binary);
+ return binary.Item1;
+ }
+ }
+
+ public override BinaryOperator BinaryOperator
+ {
+ get
+ {
+ Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression> binary;
+ bool res = TryGetBinaryFromCache (out binary);
+ if (!res)
+ throw new InvalidOperationException ();
+
+ return binary.Item2;
+ }
+ }
+
+ public override BoxedExpression BinaryLeftArgument
+ {
+ get
+ {
+ Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression> binary;
+ bool res = TryGetBinaryFromCache (out binary);
+ if (!res)
+ throw new InvalidOperationException ();
+
+ return binary.Item3;
+ }
+ }
+
+ public override BoxedExpression BinaryRightArgument
+ {
+ get
+ {
+ Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression> binary;
+ bool res = TryGetBinaryFromCache (out binary);
+ if (!res)
+ throw new InvalidOperationException ();
+
+ return binary.Item4;
+ }
+ }
+
+ public override bool IsConstant
+ {
+ get
+ {
+ Tuple<bool, object, TypeNode> consta;
+ TryGetConstantFromCache (out consta);
+
+ return consta.Item1;
+ }
+ }
+
+ public override object Constant
+ {
+ get
+ {
+ Tuple<bool, object, TypeNode> consta;
+ if (!TryGetConstantFromCache (out consta))
+ throw new InvalidOperationException ();
+
+ return consta.Item2;
+ }
+ }
+
+ public override object ConstantType
+ {
+ get
+ {
+ Tuple<bool, object, TypeNode> consta;
+ if (!TryGetConstantFromCache (out consta))
+ throw new InvalidOperationException();
+
+ return consta.Item3;
+ }
+ }
+
+ public override bool IsIsinst
+ {
+ get
+ {
+ Tuple<bool, BoxedExpression, TypeNode> isinst;
+ TryGetIsInstFromCache (out isinst);
+ return isinst.Item1;
+ }
+ }
+
+ public override bool IsNull
+ {
+ get { return this.decoder.IsNull (this.expr); }
+ }
+
+ public override bool IsUnary
+ {
+ get
+ {
+ Tuple<bool, UnaryOperator, BoxedExpression> unary;
+ TryGetUnaryFromCache (out unary);
+ return unary.Item1;
+ }
+ }
+
+ public override UnaryOperator UnaryOperator
+ {
+ get
+ {
+ Tuple<bool, UnaryOperator, BoxedExpression> unary;
+ if (!TryGetUnaryFromCache (out unary))
+ throw new InvalidOperationException();
+ return unary.Item2;
+ }
+ }
+
+ public override BoxedExpression UnaryArgument
+ {
+ get
+ {
+ Tuple<bool, UnaryOperator, BoxedExpression> unary;
+ if (!TryGetUnaryFromCache (out unary))
+ throw new InvalidOperationException ();
+ return unary.Item3;
+ }
+ }
+
+ public override bool IsSizeof
+ {
+ get
+ {
+ TypeNode type;
+ return this.decoder.IsSizeof (this.expr, out type);
+ }
+ }
+
+ public override bool IsVariable
+ {
+ get
+ {
+ Pair<bool, object> var1;
+ TryGetIsVariableFromCache (out var1);
+ return var1.Key;
+ }
+ }
+
+ public override object UnderlyingVariable
+ {
+ get
+ {
+ if (!this.var.IsValid)
+ this.var = this.decoder.UnderlyingVariable (this.expr);
+
+ return this.var.Value;
+ }
+ }
+
+ private bool TryGetBinaryFromCache (out Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression> binary)
+ {
+ if (this.binary.IsValid) {
+ binary = this.binary.Value;
+ return true;
+ }
+ BinaryOperator op;
+ LabeledSymbol left;
+ LabeledSymbol right;
+ bool res = this.decoder.IsBinaryExpression (this.expr, out op, out left, out right);
+ this.binary = binary = new Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression> (res, op, For (left, this.decoder), For (right, this.decoder));
+
+ return res;
+ }
+
+ private bool TryGetUnaryFromCache (out Tuple<bool, UnaryOperator, BoxedExpression> unary)
+ {
+ if (this.unary.IsValid) {
+ unary = this.unary.Value;
+ return true;
+ }
+ UnaryOperator op;
+ LabeledSymbol arg;
+ bool res = this.decoder.IsUnaryExpression (this.expr, out op, out arg);
+ this.unary = unary = new Tuple<bool, UnaryOperator, BoxedExpression> (res, op, For (arg, this.decoder));
+
+ return res;
+ }
+
+ private bool TryGetIsInstFromCache (out Tuple<bool, BoxedExpression, TypeNode> isinst)
+ {
+ if (this.isInst.IsValid) {
+ isinst = this.isInst.Value;
+ return true;
+ }
+
+ LabeledSymbol arg;
+ TypeNode type;
+ bool res = this.decoder.IsIsinst (this.expr, out arg, out type);
+ this.isInst = isinst = new Tuple<bool, BoxedExpression, TypeNode> (res, For (arg, this.decoder), type);
+
+ return res;
+ }
+
+ private bool TryGetConstantFromCache (out Tuple<bool, object, TypeNode> result)
+ {
+ if (this.constant.IsValid) {
+ result = this.constant.Value;
+ return true;
+ }
+ object value;
+ TypeNode type;
+ bool res = this.decoder.IsConstant (this.expr, out value, out type);
+ this.constant = result = new Tuple<bool, object, TypeNode> (res, value, type);
+
+ return res;
+ }
+
+ private bool TryGetTypeFromCache (out Pair<bool, TypeNode> result)
+ {
+ if (this.type.IsValid) {
+ result = this.type.Value;
+ return true;
+ }
+
+ TypeNode type;
+ bool res = this.decoder.TryGetType (this.expr, out type);
+ this.type = result = new Pair<bool, TypeNode> (res, type);
+
+ return res;
+ }
+
+ private bool TryGetIsVariableFromCache (out Pair<bool, object> result)
+ {
+ if (this.isVar.IsValid) {
+ result = this.isVar.Value;
+ return true;
+ }
+
+ object value;
+ bool res = this.decoder.IsVariable (this.expr, out value);
+ this.isVar = result = new Pair<bool, object> (res, value);
+
+ return res;
+ }
+
+ public override bool IsBinaryExpression (out BinaryOperator op, out BoxedExpression left, out BoxedExpression right)
+ {
+ Tuple<bool, BinaryOperator, BoxedExpression, BoxedExpression> bin;
+ if (!TryGetBinaryFromCache (out bin) || !bin.Item1) {
+ op = BinaryOperator.Add;
+ left = null;
+ right = null;
+ return false;
+ }
+
+ op = bin.Item2;
+ left = bin.Item3;
+ right = bin.Item4;
+ return true;
+ }
+
+ public override bool IsIsinstExpression (out BoxedExpression expr, out TypeNode type)
+ {
+ Tuple<bool, BoxedExpression, TypeNode> isinst;
+ if (!TryGetIsInstFromCache (out isinst) || !isinst.Item1) {
+ expr = null;
+ type = null;
+ return false;
+ }
+
+ expr = isinst.Item2;
+ type = isinst.Item3;
+ return true;
+ }
+
+ public override bool IsUnaryExpression (out UnaryOperator op, out BoxedExpression argument)
+ {
+ Tuple<bool, UnaryOperator, BoxedExpression> unary;
+ if (!TryGetUnaryFromCache (out unary) || !unary.Item1) {
+ op = UnaryOperator.Conv_i;
+ argument = null;
+ return false;
+ }
+
+ op = unary.Item2;
+ argument = unary.Item3;
+ return true;
+ }
+
+ protected internal override BoxedExpression RecursiveSubstitute (BoxedExpression what, BoxedExpression replace)
+ {
+ return Convert (this.expr, this.decoder).Substitute (what, replace);
+ }
+
+ public override void AddFreeVariables (HashSet<BoxedExpression> set)
+ {
+ this.decoder.AddFreeVariables (this.expr, new SetWrapper (set, this.decoder));
+ }
+
+ public override BoxedExpression Substitute<V> (Func<V, BoxedExpression, BoxedExpression> map)
+ {
+ return Convert (this.expr, this.decoder).Substitute (map);
+ }
+
+ public override bool TryGetType (out object type)
+ {
+ Pair<bool, TypeNode> result;
+ if (!TryGetTypeFromCache (out result) || !result.Key) {
+ type = null;
+ return false;
+ }
+
+ type = result.Value;
+ return true;
+ }
+
+ public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
+ {
+ Tuple<bool, object, TypeNode> constant;
+ if (TryGetConstantFromCache (out constant)) {
+ if (constant.Item2 != null)
+ return visitor.LoadConst (pc, constant.Item3, constant, Dummy.Value, data);
+
+ return visitor.LoadNull (pc, Dummy.Value, data);
+ }
+
+ UnaryOperator op;
+ LabeledSymbol arg;
+ if (this.decoder.IsUnaryExpression (this.expr, out op, out arg))
+ return visitor.Unary (pc, op, false, Dummy.Value, Dummy.Value, data);
+
+ BinaryOperator bop;
+ LabeledSymbol left;
+ LabeledSymbol right;
+ if (this.decoder.IsBinaryExpression (this.expr, out bop, out left, out right))
+ return visitor.Binary (pc, bop, Dummy.Value, Dummy.Value, Dummy.Value, data);
+ TypeNode type;
+ if (this.decoder.IsIsinst (this.expr, out arg, out type))
+ return visitor.Isinst (pc, type, Dummy.Value, Dummy.Value, data);
+ if (this.decoder.IsNull (this.expr))
+ return visitor.LoadNull (pc, Dummy.Value, data);
+ if (this.decoder.IsSizeof (this.expr, out type))
+ return visitor.Sizeof (pc, type, Dummy.Value, data);
+
+ return visitor.Nop (pc, data);
+ }
+
+ #region Nested type: SetWrapper
+ private struct SetWrapper : ISet<LabeledSymbol>, IEnumerable<LabeledSymbol> {
+ private readonly IFullExpressionDecoder<Variable, LabeledSymbol> decoder;
+ private readonly HashSet<BoxedExpression> set;
+
+ #region Implementation of IEnumerable
+ public IEnumerator<LabeledSymbol> GetEnumerator ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator ()
+ {
+ return GetEnumerator ();
+ }
+ #endregion
+
+ public SetWrapper (HashSet<BoxedExpression> set, IFullExpressionDecoder<Variable, LabeledSymbol> decoder)
+ {
+ this.set = set;
+ this.decoder = decoder;
+ }
+
+ #region Implementation of ICollection<ExternalExpression>
+ public void Add (LabeledSymbol item)
+ {
+ this.set.Add (For (item, this.decoder));
+ }
+
+ bool ISet<LabeledSymbol>.Add (LabeledSymbol item)
+ {
+ Add (item);
+ return true;
+ }
+
+ public void UnionWith (IEnumerable<LabeledSymbol> other)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public void IntersectWith (IEnumerable<LabeledSymbol> other)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public void ExceptWith (IEnumerable<LabeledSymbol> other)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public void SymmetricExceptWith (IEnumerable<LabeledSymbol> other)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public bool IsSubsetOf (IEnumerable<LabeledSymbol> other)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public bool IsSupersetOf (IEnumerable<LabeledSymbol> other)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public bool IsProperSupersetOf (IEnumerable<LabeledSymbol> other)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public bool IsProperSubsetOf (IEnumerable<LabeledSymbol> other)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public bool Overlaps (IEnumerable<LabeledSymbol> other)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public bool SetEquals (IEnumerable<LabeledSymbol> other)
+ {
+ throw new NotImplementedException ();
+ }
+
+
+ public void Clear ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ public bool Contains (LabeledSymbol item)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public void CopyTo (LabeledSymbol[] array, int arrayIndex)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public bool Remove (LabeledSymbol item)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public int Count
+ {
+ get { throw new NotImplementedException (); }
+ }
+
+ public bool IsReadOnly
+ {
+ get { throw new NotImplementedException (); }
+ }
+ #endregion
+ }
+ #endregion
+ }
+ #endregion
+
+ #region Nested type: IsinstExpression
+ public class IsinstExpression : BoxedExpression {
+ private readonly BoxedExpression arg;
+ private readonly TypeNode type;
+
+ public IsinstExpression (BoxedExpression boxedExpression, TypeNode type)
+ {
+ this.arg = boxedExpression;
+ this.type = type;
+ }
+
+ public override bool IsIsinst
+ {
+ get { return true; }
+ }
+
+ public override BoxedExpression UnaryArgument
+ {
+ get { return this.arg; }
+ }
+
+ public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
+ {
+ return visitor.Isinst (pc, this.type, Dummy.Value, Dummy.Value, data);
+ }
+
+ public override void AddFreeVariables (HashSet<BoxedExpression> set)
+ {
+ this.arg.AddFreeVariables (set);
+ }
+
+ public override BoxedExpression Substitute<Variable> (Func<Variable, BoxedExpression, BoxedExpression> map)
+ {
+ BoxedExpression arg = this.arg.Substitute (map);
+ if (arg == this.arg)
+ return this;
+ if (arg == null)
+ return null;
+
+ return new IsinstExpression (arg, this.type);
+ }
+ }
+ #endregion
+
+ #region Nested type: OldExpression
+ public class OldExpression : BoxedExpression {
+ private const string ContractOldValueTemplate = "Contract.OldValue({0})";
+
+ public readonly BoxedExpression Old;
+ public readonly TypeNode Type;
+
+ public OldExpression (BoxedExpression old, TypeNode type)
+ {
+ this.Old = old;
+ this.Type = type;
+ }
+
+ #region Overrides of BoxedExpression
+ public override void AddFreeVariables (HashSet<BoxedExpression> set)
+ {
+ this.Old.AddFreeVariables (set);
+ }
+
+ public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
+ {
+ BoxedExpression old = this.Old.Substitute (map);
+ if (old == this.Old)
+ return this;
+ if (old == null)
+ return null;
+
+ return new OldExpression (old, this.Type);
+ }
+
+ public override bool IsBinaryExpression (out BinaryOperator op, out BoxedExpression left, out BoxedExpression right)
+ {
+ return this.Old.IsBinaryExpression (out op, out left, out right);
+ }
+
+ public override bool IsUnaryExpression (out UnaryOperator op, out BoxedExpression argument)
+ {
+ return this.Old.IsUnaryExpression (out op, out argument);
+ }
+
+ public override bool IsIsinstExpression (out BoxedExpression expr, out TypeNode type)
+ {
+ return this.Old.IsIsinstExpression (out expr, out type);
+ }
+
+ public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
+ {
+ return visitor.EndOld (pc, new PC (pc.Node, 0), this.Type, Dummy.Value, Dummy.Value, data);
+ }
+ #endregion
+
+ public override PathElement[] AccessPath
+ {
+ get { return this.Old.AccessPath; }
+ }
+
+ public override BoxedExpression BinaryLeftArgument
+ {
+ get { return this.Old.BinaryLeftArgument; }
+ }
+
+ public override BoxedExpression BinaryRightArgument
+ {
+ get { return this.Old.BinaryRightArgument; }
+ }
+
+ public override BinaryOperator BinaryOperator
+ {
+ get { return this.Old.BinaryOperator; }
+ }
+
+ public override object Constant
+ {
+ get { return this.Old.Constant; }
+ }
+
+ public override object ConstantType
+ {
+ get { return this.Old.ConstantType; }
+ }
+
+ public override bool IsBinary
+ {
+ get { return this.Old.IsBinary; }
+ }
+
+ public override bool IsConstant
+ {
+ get { return this.Old.IsConstant; }
+ }
+
+ public override bool IsSizeof
+ {
+ get { return this.Old.IsSizeof; }
+ }
+
+ public override bool IsNull
+ {
+ get { return this.Old.IsNull; }
+ }
+
+ public override bool IsIsinst
+ {
+ get { return this.Old.IsIsinst; }
+ }
+
+ public override bool IsUnary
+ {
+ get { return this.Old.IsUnary; }
+ }
+
+ public override bool IsVariable
+ {
+ get { return this.Old.IsVariable; }
+ }
+
+ public override BoxedExpression UnaryArgument
+ {
+ get { return this.Old.UnaryArgument; }
+ }
+
+ public override UnaryOperator UnaryOperator
+ {
+ get { return this.Old.UnaryOperator; }
+ }
+
+ public override object UnderlyingVariable
+ {
+ get { return this.Old.UnderlyingVariable; }
+ }
+ }
+ #endregion
+
+ #region Nested type: PC
+ public struct PC {
+ public readonly int Index;
+ public readonly BoxedExpression Node;
+
+ public PC (BoxedExpression expr, int index)
+ {
+ this.Node = expr;
+ this.Index = index;
+ }
+ }
+ #endregion
+
+ #region Nested type: ResultExpression
+ public class ResultExpression : BoxedExpression {
+ private const string ContractResultTemplate = "Contract.Result<{0}>()";
+
+ public readonly TypeNode Type;
+
+ public ResultExpression (TypeNode type)
+ {
+ this.Type = type;
+ }
+
+ public override bool IsResult
+ {
+ get { return true; }
+ }
+
+ public override void AddFreeVariables (HashSet<BoxedExpression> set)
+ {
+ }
+
+ public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
+ {
+ return this;
+ }
+
+ public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
+ {
+ return visitor.LoadResult (pc, this.Type, Dummy.Value, Dummy.Value, data);
+ }
+ }
+ #endregion
+
+ #region Nested type: SizeOfExpression
+ public class SizeOfExpression : BoxedExpression {
+ public readonly int SizeAsConstant;
+ public readonly TypeNode Type;
+
+ public SizeOfExpression (TypeNode type, int sizeAsConstant)
+ {
+ this.Type = type;
+ this.SizeAsConstant = sizeAsConstant;
+ }
+
+ public SizeOfExpression (TypeNode type)
+ : this (type, -1)
+ {
+ }
+
+ public override bool IsSizeof
+ {
+ get { return true; }
+ }
+
+ public override void AddFreeVariables (HashSet<BoxedExpression> set)
+ {
+ }
+
+ public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
+ {
+ return this;
+ }
+
+ public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
+ {
+ return visitor.Sizeof (pc, this.Type, Dummy.Value, data);
+ }
+ }
+ #endregion
+
+ #region Nested type: UnaryExpression
+ public class UnaryExpression : BoxedExpression {
+ public readonly BoxedExpression Argument;
+ public readonly UnaryOperator Op;
+
+ public UnaryExpression (UnaryOperator op, BoxedExpression argument)
+ {
+ this.Op = op;
+ this.Argument = argument;
+ }
+
+ public override bool IsUnary
+ {
+ get { return true; }
+ }
+
+ public override BoxedExpression UnaryArgument
+ {
+ get { return this.Argument; }
+ }
+
+ public override UnaryOperator UnaryOperator
+ {
+ get { return this.Op; }
+ }
+
+ public override bool IsUnaryExpression (out UnaryOperator op, out BoxedExpression argument)
+ {
+ op = this.Op;
+ argument = this.Argument;
+ return true;
+ }
+
+ public override void AddFreeVariables (HashSet<BoxedExpression> set)
+ {
+ this.Argument.AddFreeVariables (set);
+ }
+
+ public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
+ {
+ BoxedExpression argument = this.Argument.Substitute (map);
+ if (argument == this.Argument)
+ return this;
+ if (argument == null)
+ return null;
+
+ return new UnaryExpression (this.Op, argument);
+ }
+
+ protected internal override BoxedExpression RecursiveSubstitute (BoxedExpression what, BoxedExpression replace)
+ {
+ BoxedExpression argument = this.Argument.Substitute (what, replace);
+
+ if (argument == this.Argument)
+ return this;
+
+ return new UnaryExpression (this.Op, argument);
+ }
+
+ public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
+ {
+ return visitor.Unary (pc, this.Op, false, Dummy.Value, Dummy.Value, data);
+ }
+
+ public override bool Equals (object obj)
+ {
+ if (this == obj)
+ return true;
+
+ var unary = obj as UnaryExpression;
+ return unary != null && this.Op == unary.Op && this.Argument.Equals (unary.Argument);
+ }
+
+ public override int GetHashCode ()
+ {
+ return this.Op.GetHashCode () * 13 + (this.Argument == null ? 0 : this.Argument.GetHashCode ());
+ }
+
+ }
+ #endregion
+
+ #region Nested type: ValueAtReturnExpression
+ public class ValueAtReturnExpression : BoxedExpression {
+ private const string ContractValueAtReturnTemplate = "Contract.ValueAtReturn({0})";
+
+ public readonly TypeNode Type;
+ public readonly BoxedExpression Value;
+
+ public ValueAtReturnExpression (BoxedExpression old, TypeNode type)
+ {
+ this.Value = old;
+ this.Type = type;
+ }
+
+ #region Overrides of BoxedExpression
+ public override void AddFreeVariables (HashSet<BoxedExpression> set)
+ {
+ this.Value.AddFreeVariables (set);
+ }
+
+ public override BoxedExpression Substitute<Variable1> (Func<Variable1, BoxedExpression, BoxedExpression> map)
+ {
+ BoxedExpression value = this.Value.Substitute (map);
+ if (value == this.Value)
+ return this;
+ if (value == null)
+ return null;
+
+ return new ValueAtReturnExpression (value, this.Type);
+ }
+
+ public override bool IsBinaryExpression (out BinaryOperator op, out BoxedExpression left, out BoxedExpression right)
+ {
+ return this.Value.IsBinaryExpression (out op, out left, out right);
+ }
+
+ public override bool IsUnaryExpression (out UnaryOperator op, out BoxedExpression argument)
+ {
+ return this.Value.IsUnaryExpression (out op, out argument);
+ }
+
+ public override bool IsIsinstExpression (out BoxedExpression expr, out TypeNode type)
+ {
+ return this.Value.IsIsinstExpression (out expr, out type);
+ }
+
+ public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
+ {
+ throw new NotImplementedException ();
+ }
+ #endregion
+
+ public override PathElement[] AccessPath
+ {
+ get { return this.Value.AccessPath; }
+ }
+
+ public override BoxedExpression BinaryLeftArgument
+ {
+ get { return this.Value.BinaryLeftArgument; }
+ }
+
+ public override BoxedExpression BinaryRightArgument
+ {
+ get { return this.Value.BinaryRightArgument; }
+ }
+
+ public override BinaryOperator BinaryOperator
+ {
+ get { return this.Value.BinaryOperator; }
+ }
+
+ public override object Constant
+ {
+ get { return this.Value.Constant; }
+ }
+
+ public override object ConstantType
+ {
+ get { return this.Value.ConstantType; }
+ }
+
+ public override bool IsBinary
+ {
+ get { return this.Value.IsBinary; }
+ }
+
+ public override bool IsConstant
+ {
+ get { return this.Value.IsConstant; }
+ }
+
+ public override bool IsSizeof
+ {
+ get { return this.Value.IsSizeof; }
+ }
+
+ public override bool IsNull
+ {
+ get { return this.Value.IsNull; }
+ }
+
+ public override bool IsIsinst
+ {
+ get { return this.Value.IsIsinst; }
+ }
+
+ public override bool IsUnary
+ {
+ get { return this.Value.IsUnary; }
+ }
+
+ public override bool IsVariable
+ {
+ get { return this.Value.IsVariable; }
+ }
+
+ public override BoxedExpression UnaryArgument
+ {
+ get { return this.Value.UnaryArgument; }
+ }
+
+ public override UnaryOperator UnaryOperator
+ {
+ get { return this.Value.UnaryOperator; }
+ }
+
+ public override object UnderlyingVariable
+ {
+ get { return this.Value.UnderlyingVariable; }
+ }
+ }
+ #endregion
+
+ #region Nested type: VariableExpression
+ public class VariableExpression : BoxedExpression {
+ private readonly PathElement[] Path;
+ private readonly object UnderlyingVar;
+ public readonly object VarType;
+
+ public VariableExpression (object var)
+ : this (var, (LispList<PathElement>) null)
+ {
+ }
+
+ public VariableExpression (object var, LispList<PathElement> path)
+ {
+ this.UnderlyingVar = var;
+ this.Path = path != null ? path.AsEnumerable ().ToArray () : null;
+ }
+
+ public VariableExpression (object var, LispList<PathElement> path, object type)
+ : this (var, path)
+ {
+ this.VarType = type;
+ }
+
+ public VariableExpression (object var, PathElement[] path)
+ {
+ this.UnderlyingVar = var;
+ this.Path = path;
+ }
+
+ public VariableExpression (object var, PathElement[] path, object type)
+ : this (var, path)
+ {
+ this.VarType = type;
+ }
+
+ public override bool IsVariable
+ {
+ get { return true; }
+ }
+
+ public override object UnderlyingVariable
+ {
+ get { return this.UnderlyingVar; }
+ }
+
+ public override PathElement[] AccessPath
+ {
+ get { return this.Path; }
+ }
+
+ public override bool IsBooleanTyped
+ {
+ get { return this.Path != null && this.Path [this.Path.Length - 1].IsBooleanTyped; }
+ }
+
+ public override bool TryGetType (out object type)
+ {
+ type = this.VarType;
+ return type != null;
+ }
+
+ public override void AddFreeVariables (HashSet<BoxedExpression> set)
+ {
+ set.Add (this);
+ }
+
+ protected internal override BoxedExpression RecursiveSubstitute (BoxedExpression what, BoxedExpression replace)
+ {
+ var varExpr = what as VariableExpression;
+ if (varExpr != null && varExpr.UnderlyingVar.Equals (this.UnderlyingVar))
+ return replace;
+
+ return this;
+ }
+
+ public override Result ForwardDecode<Data, Result, Visitor> (PC pc, Visitor visitor, Data data)
+ {
+ return visitor.Nop (pc, data);
+ }
+
+ public override bool Equals (object obj)
+ {
+ if (this == obj)
+ return true;
+ var boxedExpression = obj as BoxedExpression;
+ if (boxedExpression != null && boxedExpression.IsVariable)
+ return this.UnderlyingVar.Equals (boxedExpression.UnderlyingVariable);
+
+ return false;
+ }
+
+ public override int GetHashCode ()
+ {
+ return this.UnderlyingVariable != null ? 0 : this.UnderlyingVariable.GetHashCode ();
+ }
+
+ public override BoxedExpression Substitute<Variable> (Func<Variable, BoxedExpression, BoxedExpression> map)
+ {
+ if (!(this.UnderlyingVar is Variable))
+ return this;
+ var variable = ((Variable) this.UnderlyingVar);
+ return map (variable, this);
+ }
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// BoxedExpressionExtensions.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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;
+
+namespace Mono.CodeContracts.Static.Proving
+{
+ static class BoxedExpressionExtensions
+ {
+ public static bool IsConstantIntOrNull(this BoxedExpression e, out int res)
+ {
+ res = 0;
+ if (e.IsConstant) {
+ IConvertible convertible = e.Constant as IConvertible;
+ if (convertible != null) {
+ if (e.Constant is string || e.Constant is float || e.Constant is double)
+ return false;
+
+ try {
+ res = convertible.ToInt32 (null);
+ return true;
+ } catch {
+ }
+ }
+ if (e.Constant == null)
+ return true;
+ }
+ return false;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// ComposedFactQuery.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Proving
+{
+ class ComposedFactQuery<Variable> : IFactQuery<BoxedExpression, Variable>
+ {
+ private List<IFactQuery<BoxedExpression, Variable>> elements = new List<IFactQuery<BoxedExpression, Variable>> ();
+ private Predicate<APC> isUnreachable;
+
+ public ComposedFactQuery(Predicate<APC> isUnreachable )
+ {
+ this.isUnreachable = isUnreachable;
+ }
+
+ public void Add(IFactQuery<BoxedExpression, Variable> item )
+ {
+ if (item == null)
+ return;
+ this.elements.Add (item);
+ }
+
+ #region Implementation of IFactBase<Variable>
+ public ProofOutcome IsNull(APC pc, Variable variable)
+ {
+ return elements.Select(fact => fact.IsNull(pc, variable)).FirstOrDefault(factResult => factResult != ProofOutcome.Top);
+ }
+
+ public ProofOutcome IsNonNull(APC pc, Variable variable)
+ {
+ return elements.Select(fact => fact.IsNonNull(pc, variable)).FirstOrDefault(factResult => factResult != ProofOutcome.Top);
+ }
+
+ public bool IsUnreachable(APC pc)
+ {
+ if (this.isUnreachable != null && this.isUnreachable(pc))
+ return true;
+ return elements.Any (factQuery => factQuery.IsUnreachable (pc));
+ }
+ #endregion
+
+ #region Implementation of IFactQuery<BoxedExpression,Variable>
+ public ProofOutcome IsNull(APC pc, BoxedExpression expr)
+ {
+ return elements.Select (fact => fact.IsNull (pc, expr)).FirstOrDefault (factResult => factResult != ProofOutcome.Top);
+ }
+
+ public ProofOutcome IsNonNull(APC pc, BoxedExpression expr)
+ {
+ return elements.Select(fact => fact.IsNonNull(pc, expr)).FirstOrDefault(factResult => factResult != ProofOutcome.Top);
+ }
+
+ public ProofOutcome IsTrue(APC pc, BoxedExpression expr)
+ {
+ ProofOutcome res = ProofOutcome.Top;
+ foreach (var factQuery in elements) {
+ var outcome = factQuery.IsTrue (pc, expr);
+ switch (outcome) {
+ case ProofOutcome.True:
+ case ProofOutcome.Bottom:
+ return outcome;
+ case ProofOutcome.False:
+ res = outcome;
+ continue;
+ default:
+ continue;
+ }
+ }
+ if (res != ProofOutcome.Top)
+ return res;
+
+ BinaryOperator op;
+ BoxedExpression left;
+ BoxedExpression right;
+ if (expr.IsBinaryExpression (out op, out left, out right)) {
+ if ((op == BinaryOperator.Ceq || op == BinaryOperator.Cobjeq) && this.IsRelational (left) && this.IsNull (pc, right) == ProofOutcome.True) {
+ var outcome = this.IsTrue (pc, left);
+ switch (outcome) {
+ case ProofOutcome.False:
+ return ProofOutcome.True;
+ case ProofOutcome.True:
+ return ProofOutcome.False;
+ default:
+ return outcome;
+ }
+ }
+ int leftInt;
+ int rightInt;
+ if (op == BinaryOperator.Ceq && left.IsConstantIntOrNull (out leftInt) && right.IsConstantIntOrNull (out rightInt))
+ return leftInt == rightInt ? ProofOutcome.True : ProofOutcome.False;
+ }
+
+ if (expr.IsUnary && expr.UnaryOperator == UnaryOperator.Not) {
+ var outcome = this.IsTrue (pc, expr.UnaryArgument);
+ switch (outcome) {
+ case ProofOutcome.False:
+ return ProofOutcome.True;
+ case ProofOutcome.True:
+ return ProofOutcome.False;
+ default:
+ return outcome;
+ }
+ }
+
+ return ProofOutcome.Top;
+ }
+
+ private bool IsRelational(BoxedExpression e)
+ {
+ BinaryOperator op;
+ BoxedExpression left;
+ BoxedExpression right;
+ if (e.IsBinaryExpression (out op, out left, out right))
+ switch (op) {
+ case BinaryOperator.Ceq:
+ case BinaryOperator.Cobjeq:
+ case BinaryOperator.Cne_Un:
+ case BinaryOperator.Cge:
+ case BinaryOperator.Cge_Un:
+ case BinaryOperator.Cgt:
+ case BinaryOperator.Cgt_Un:
+ case BinaryOperator.Cle:
+ case BinaryOperator.Cle_Un:
+ case BinaryOperator.Clt:
+ case BinaryOperator.Clt_Un:
+ return true;
+ }
+ return false;
+ }
+
+ public ProofOutcome IsTrueImply(APC pc, LispList<BoxedExpression> positiveAssumptions, LispList<BoxedExpression> negativeAssumptions, BoxedExpression goal)
+ {
+ return elements.Select(fact => fact.IsTrueImply(pc, positiveAssumptions, negativeAssumptions, goal)).FirstOrDefault(factResult => factResult != ProofOutcome.Top);
+ }
+
+ public ProofOutcome IsGreaterEqualToZero(APC pc, BoxedExpression expr)
+ {
+ return elements.Select(fact => fact.IsGreaterEqualToZero(pc, expr)).FirstOrDefault(factResult => factResult != ProofOutcome.Top);
+ }
+
+ public ProofOutcome IsLessThan(APC pc, BoxedExpression expr, BoxedExpression right)
+ {
+ return elements.Select(fact => fact.IsLessThan(pc, expr, right)).FirstOrDefault(factResult => factResult != ProofOutcome.Top);
+ }
+
+ public ProofOutcome IsNonZero(APC pc, BoxedExpression expr)
+ {
+ return elements.Select(fact => fact.IsNonZero(pc, expr)).FirstOrDefault(factResult => factResult != ProofOutcome.Top);
+ }
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// ConstantPropagationFactQuery.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Linq;
+using Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Proving
+{
+ class ConstantPropagationFactQuery<Variable> : IFactQuery<BoxedExpression, Variable>
+ {
+ #region Implementation of IFactBase<Variable>
+ public ProofOutcome IsNull(APC pc, Variable variable)
+ {
+ return ProofOutcome.Top;
+ }
+
+ public ProofOutcome IsNonNull(APC pc, Variable variable)
+ {
+ return ProofOutcome.Top;
+ }
+
+ public bool IsUnreachable(APC pc)
+ {
+ return false;
+ }
+ #endregion
+
+ #region Implementation of IFactQuery<BoxedExpression,Variable>
+ public ProofOutcome IsNull(APC pc, BoxedExpression expr)
+ {
+ int num;
+ if (expr.IsConstantIntOrNull (out num))
+ return IsTrueOrTop (num == 0);
+
+ return ProofOutcome.Top;
+ }
+
+ public ProofOutcome IsNonNull(APC pc, BoxedExpression expr)
+ {
+ int num;
+ if (expr.IsConstantIntOrNull (out num))
+ return IsTrueOrTop (num != 0);
+
+ return ProofOutcome.Top;
+ }
+
+ public ProofOutcome IsTrue(APC pc, BoxedExpression expr)
+ {
+ int num;
+ if (expr.IsConstantIntOrNull (out num))
+ return IsTrueOrTop (num != 0);
+
+ return ConstantFact (expr);
+ }
+
+
+ public ProofOutcome IsTrueImply(APC pc, LispList<BoxedExpression> positiveAssumptions, LispList<BoxedExpression> negativeAssumptions, BoxedExpression goal)
+ {
+ UnaryOperator op;
+ BoxedExpression arg;
+ while (goal.IsUnaryExpression (out op, out arg) && op.IsConversionOperator ())
+ goal = arg;
+
+ if (positiveAssumptions.AsEnumerable ().Any (positiveAssumption => positiveAssumptions.Equals (goal)))
+ return ProofOutcome.True;
+
+ return ProofOutcome.Top;
+ }
+
+ public ProofOutcome IsGreaterEqualToZero(APC pc, BoxedExpression expr)
+ {
+ int num;
+ if (expr.IsConstantIntOrNull(out num))
+ return IsTrueOrTop(num >= 0);
+
+ return ProofOutcome.Top;
+ }
+
+ public ProofOutcome IsLessThan(APC pc, BoxedExpression left, BoxedExpression right)
+ {
+ int l;
+ int r;
+ if (left.IsConstantIntOrNull(out l) && right.IsConstantIntOrNull(out r))
+ return IsTrueOrTop (l < r);
+
+ return ProofOutcome.Top;
+ }
+
+ public ProofOutcome IsNonZero(APC pc, BoxedExpression expr)
+ {
+ int num;
+ if (expr.IsConstantIntOrNull(out num))
+ return IsTrueOrTop (num != 0);
+
+ return ProofOutcome.Top;
+ }
+
+ private static ProofOutcome IsTrueOrTop(bool condition)
+ {
+ return condition ? ProofOutcome.True : ProofOutcome.Top;
+ }
+
+ private ProofOutcome ConstantFact(BoxedExpression expr)
+ {
+ BinaryOperator op;
+ BoxedExpression left;
+ BoxedExpression right;
+ if (expr.IsBinaryExpression (out op, out left, out right)) {
+ int l;
+ var leftIsInt = left.IsConstantIntOrNull (out l);
+
+ int r;
+ var rightIsInt = right.IsConstantIntOrNull(out r);
+
+ if (leftIsInt || rightIsInt) {
+ if (leftIsInt && rightIsInt) {
+ switch (op) {
+ case BinaryOperator.Add:
+ return IsTrueOrTop ((l + r) != 0);
+ case BinaryOperator.And:
+ return IsTrueOrTop((l & r) != 0);
+ case BinaryOperator.Ceq:
+ return IsTrueOrTop(l == r);
+ case BinaryOperator.Cobjeq:
+ return ProofOutcome.Top;
+ case BinaryOperator.Cne_Un:
+ return IsTrueOrTop(l != r);
+ case BinaryOperator.Cge:
+ return IsTrueOrTop(l >= r);
+ case BinaryOperator.Cge_Un:
+ return IsTrueOrTop((uint)l >= (uint)r);
+ case BinaryOperator.Cgt:
+ return IsTrueOrTop(l > r);
+ case BinaryOperator.Cgt_Un:
+ return IsTrueOrTop((uint)l > (uint)r);
+ case BinaryOperator.Cle:
+ return IsTrueOrTop(l <= r);
+ case BinaryOperator.Cle_Un:
+ return IsTrueOrTop((uint)l <= (uint)r);
+ case BinaryOperator.Clt:
+ return IsTrueOrTop(l < r);
+ case BinaryOperator.Clt_Un:
+ return IsTrueOrTop((uint)l < (uint)r);
+ case BinaryOperator.Div:
+ return IsTrueOrTop(r != 0 && ((l / r) != 0));
+ case BinaryOperator.LogicalAnd:
+ return IsTrueOrTop(l != 0 && r != 0);
+ case BinaryOperator.LogicalOr:
+ return IsTrueOrTop(l != 0 || r != 0);
+ case BinaryOperator.Mul:
+ return IsTrueOrTop(l * r != 0);
+ case BinaryOperator.Or:
+ return IsTrueOrTop((l | r) != 0);
+ case BinaryOperator.Rem:
+ return IsTrueOrTop(r != 0 && (l % r != 0));
+ case BinaryOperator.Shl:
+ return IsTrueOrTop(l << r != 0);
+ case BinaryOperator.Shr:
+ return IsTrueOrTop(l >> r != 0);
+ case BinaryOperator.Sub:
+ return IsTrueOrTop(l - r != 0);
+ case BinaryOperator.Xor:
+ return IsTrueOrTop((l ^ r) != 0);
+ }
+ }
+ if (op == BinaryOperator.Ceq && (leftIsInt && l == 0 || rightIsInt && r == 0))
+ return this.ConstantFact (left).Negate ();
+ }
+ else if (left.IsConstant && right.IsConstant) {
+ var lConst = left.Constant;
+ var rConst = right.Constant;
+ switch (op) {
+ case BinaryOperator.Cobjeq:
+ return lConst == null ? IsTrueOrTop (rConst == null) : IsTrueOrTop (lConst.Equals (rConst));
+ case BinaryOperator.Cne_Un:
+ return lConst == null ? IsTrueOrTop (rConst != null) : IsTrueOrTop (!lConst.Equals (rConst));
+ }
+ }
+ }
+
+ return ProofOutcome.Top;
+ }
+ #endregion
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// IFactBase.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.ControlFlow;
+
+namespace Mono.CodeContracts.Static.Proving {
+ interface IFactBase<Variable> {
+ ProofOutcome IsNull (APC pc, Variable variable);
+ ProofOutcome IsNonNull (APC pc, Variable variable);
+ bool IsUnreachable (APC pc);
+ }
+}
--- /dev/null
+//
+// IFactQuery.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.DataStructures;
+
+namespace Mono.CodeContracts.Static.Proving {
+ interface IFactQuery<Expression, Variable> : IFactBase<Variable> {
+ ProofOutcome IsNull (APC pc, Expression expr);
+ ProofOutcome IsNonNull (APC pc, Expression expr);
+ ProofOutcome IsTrue (APC pc, Expression expr);
+ ProofOutcome IsTrueImply (APC pc, LispList<Expression> positiveAssumptions, LispList<Expression> negativeAssumptions, Expression goal);
+ ProofOutcome IsGreaterEqualToZero (APC pc, Expression expr);
+ ProofOutcome IsLessThan (APC pc, Expression expr, Expression right);
+ ProofOutcome IsNonZero (APC pc, Expression expr);
+ }
+}
--- /dev/null
+//
+// SimpleLogicInference.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.Analysis;
+using Mono.CodeContracts.Static.ControlFlow;
+
+namespace Mono.CodeContracts.Static.Proving {
+ class SimpleLogicInference<Expression, Variable> : BasicFacts<Expression, Variable> {
+ public SimpleLogicInference (IExpressionContextProvider<Expression, Variable> contextProvider, IFactBase<Variable> factBase, Predicate<APC> isUnreachable)
+ : base (contextProvider, factBase, isUnreachable)
+ {
+ }
+
+ public override ProofOutcome IsNull (APC pc, BoxedExpression expr)
+ {
+ Variable v;
+ if (TryVariable (expr, out v)) {
+ ProofOutcome proofOutcome = this.FactBase.IsNull (pc, v);
+ if (proofOutcome != ProofOutcome.Top)
+ return proofOutcome;
+ }
+
+ if (expr.IsConstant) {
+ object constant = expr.Constant;
+ if (constant == null)
+ return ProofOutcome.True;
+ if (constant is string)
+ return ProofOutcome.False;
+ var convertible = constant as IConvertible;
+ if (convertible != null) {
+ try {
+ return (convertible.ToInt64 (null) == 0) ? ProofOutcome.True : ProofOutcome.False;
+ } catch {
+ return ProofOutcome.Top;
+ }
+ }
+ }
+
+ BinaryOperator op;
+ BoxedExpression left;
+ BoxedExpression right;
+ if (expr.IsBinaryExpression (out op, out left, out right)) {
+ if ((op == BinaryOperator.Ceq || op == BinaryOperator.Cobjeq) && IsNull (pc, right) == ProofOutcome.True)
+ return IsNonNull (pc, left);
+ if (op == BinaryOperator.Cne_Un && IsNull (pc, right) == ProofOutcome.True)
+ return IsNull (pc, left);
+ }
+ return ProofOutcome.Top;
+ }
+
+ public override ProofOutcome IsNonNull (APC pc, BoxedExpression expr)
+ {
+ Variable v;
+ if (TryVariable (expr, out v)) {
+ ProofOutcome proofOutcome = this.FactBase.IsNonNull (pc, v);
+ if (proofOutcome != ProofOutcome.Top)
+ return proofOutcome;
+ }
+
+ if (expr.IsConstant) {
+ object constant = expr.Constant;
+ if (constant == null)
+ return ProofOutcome.False;
+ if (constant is string)
+ return ProofOutcome.True;
+ var convertible = constant as IConvertible;
+ if (convertible != null) {
+ try {
+ return (convertible.ToInt64 (null) == 0) ? ProofOutcome.False : ProofOutcome.True;
+ } catch {
+ return ProofOutcome.Top;
+ }
+ }
+ }
+
+ BinaryOperator op;
+ BoxedExpression left;
+ BoxedExpression right;
+ if (expr.IsBinaryExpression (out op, out left, out right)) {
+ if ((op == BinaryOperator.Ceq || op == BinaryOperator.Cobjeq) && IsNull (pc, right) == ProofOutcome.True)
+ return IsNull (pc, left);
+ if (op == BinaryOperator.Cne_Un && IsNull (pc, right) == ProofOutcome.True)
+ return IsNonNull (pc, left);
+ }
+ return ProofOutcome.Top;
+ }
+ }
+}
--- /dev/null
+//
+// CheckOptions.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static {
+ public class CheckOptions {
+ public CheckOptions ()
+ {
+ }
+
+ public string Assembly { get; set; }
+ /// <summary>
+ /// Method name constraint
+ /// If specified, check is performed only on methods containing this name as substring
+ /// </summary>
+ public string Method { get; set; }
+
+ public bool ShowDebug { get; set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// CheckResults.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.Collections.Generic;
+using System.Linq;
+
+namespace Mono.CodeContracts.Static {
+ public class CheckResults {
+ private readonly ICollection<string> warnings;
+ private readonly ICollection<string> errors;
+ private readonly IDictionary<string, ICollection<string>> checker_messages;
+
+ internal static CheckResults Error(string warning)
+ {
+ return new CheckResults (new[] {warning}, null, null);
+ }
+
+ internal CheckResults (ICollection<string> warnings, ICollection<string> errors, IDictionary<string, ICollection<string>> checkerMessages)
+ {
+ this.warnings = warnings;
+ this.errors = errors;
+ this.checker_messages = checkerMessages;
+ }
+
+ 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> (); }
+ }
+
+ public IDictionary<string, ICollection<string>> Results
+ {
+ get { return this.checker_messages ?? null; }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// Checker.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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 Mono.CodeContracts.Static.AST;
+using Mono.CodeContracts.Static.Analysis.Drivers;
+using Mono.CodeContracts.Static.Analysis.HeapAnalysis;
+using Mono.CodeContracts.Static.Analysis.NonNull;
+using Mono.CodeContracts.Static.ControlFlow;
+using Mono.CodeContracts.Static.Providers;
+using Mono.CodeContracts.Static.Proving;
+
+namespace Mono.CodeContracts.Static {
+ public class Checker {
+ private readonly CheckOptions options;
+ private CodeContractsAnalysisDriver<IMethodResult<SymbolicValue>> analysis_driver;
+ private Dictionary<string, IMethodAnalysis> analyzers;
+
+ private Checker (CheckOptions options)
+ {
+ this.options = options;
+ }
+
+ public static CheckResults Check (CheckOptions options)
+ {
+ var checker = new Checker (options);
+ return checker.Analyze ();
+ }
+
+ private CheckResults Analyze ()
+ {
+ if (this.options.Assembly == null)
+ return CheckResults.Error ("No assembly given to check");
+
+ DebugOptions.Debug = this.options.ShowDebug;
+
+ this.analyzers = new Dictionary<string, IMethodAnalysis> {{"non-null", new NonNullAnalysisFacade ()}};
+ this.analysis_driver = new CodeContractsAnalysisDriver<IMethodResult<SymbolicValue>> (
+ new BasicAnalysisDriver (MetaDataProvider.Instance, CodeContractDecoder.Instance));
+
+ return AnalyzeAssembly (this.options.Assembly);
+ }
+
+ private CheckResults AnalyzeAssembly (string assemblyPath)
+ {
+ IMetaDataProvider metadataDecoder = this.analysis_driver.MetaDataProvider;
+ AssemblyNode assembly;
+ string reason;
+ if (!metadataDecoder.TryLoadAssembly (assemblyPath, out assembly, out reason))
+ return CheckResults.Error (string.Format ("Cannot load assembly: {0}", reason));
+
+ var proofResults = new Dictionary<string, ICollection<string>> ();
+ foreach (Method method in metadataDecoder.Methods (assembly))
+ AnalyzeMethod (method, proofResults);
+ if (proofResults.Count == 0)
+ return CheckResults.Error ("No methods found.");
+
+ return new CheckResults (null, null, proofResults);
+ }
+
+ private void AnalyzeMethod (Method method, Dictionary<string, ICollection<string>> proofResults)
+ {
+ IMetaDataProvider metadataDecoder = this.analysis_driver.MetaDataProvider;
+ if (!metadataDecoder.HasBody (method))
+ return;
+ if (this.options.Method != null && !metadataDecoder.FullName (method).Contains (this.options.Method))
+ return;
+
+ var results = new List<string> ();
+ proofResults.Add (method.FullName, results);
+ try {
+ AnalyzeMethodInternal (method, results);
+ } catch (Exception e) {
+ results.Add ("Exception: " + e.Message);
+ return;
+ }
+
+ results.Add (string.Format ("Checked {0} assertions", results.Count));
+ }
+
+ private void AnalyzeMethodInternal (Method method, List<string> proofResults)
+ {
+ string fullMethodName = method.FullName;
+ IMethodDriver<LabeledSymbol<APC, SymbolicValue>, SymbolicValue> methodDriver = this.analysis_driver.CreateMethodDriver (method);
+
+ methodDriver.RunHeapAndExpressionAnalyses ();
+
+ var results = new List<IMethodResult<SymbolicValue>> (this.analyzers.Values.Count);
+ foreach (IMethodAnalysis analysis in this.analyzers.Values) {
+ IMethodResult<SymbolicValue> result = analysis.Analyze (fullMethodName, methodDriver);
+ results.Add (result);
+ }
+
+ ComposedFactQuery<SymbolicValue> facts = CreateFactQuery (methodDriver.BasicFacts.IsUnreachable, results);
+ foreach (var methodResult in results)
+ methodResult.ValidateImplicitAssertions (facts, proofResults);
+
+ AssertionFinder.ValidateAssertions (facts, methodDriver, proofResults);
+ }
+
+ private ComposedFactQuery<Variable> CreateFactQuery<Variable> (Predicate<APC> isUnreachable, IEnumerable<IMethodResult<Variable>> results)
+ {
+ var res = new ComposedFactQuery<Variable> (isUnreachable);
+ res.Add (new ConstantPropagationFactQuery<Variable> ());
+ foreach (var methodResult in results)
+ res.Add (methodResult.FactQuery);
+ return res;
+ }
+ }
+}
--- /dev/null
+//
+// DebugOptions.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static {
+ static class DebugOptions {
+ public static bool Debug { get; set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// ProofOutcome.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static {
+ public enum ProofOutcome {
+ Top,
+ True,
+ False,
+ Bottom
+ }
+}
--- /dev/null
+//
+// ProofOutcomeExtensions.cs
+//
+// Authors:
+// Alexander Chebaturkin (chebaturkin@gmail.com)
+//
+// Copyright (C) 2011 Alexander Chebaturkin
+//
+// 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.
+//
+
+namespace Mono.CodeContracts.Static {
+ static class ProofOutcomeExtensions {
+ public static ProofOutcome Negate (this ProofOutcome o)
+ {
+ switch (o) {
+ case ProofOutcome.Top:
+ case ProofOutcome.Bottom:
+ return o;
+ case ProofOutcome.True:
+ return ProofOutcome.False;
+ case ProofOutcome.False:
+ return ProofOutcome.True;
+ default:
+ return ProofOutcome.Top;
+ }
+ }
+
+ public static ProofOutcome Meet (this ProofOutcome a, ProofOutcome b)
+ {
+ if (a == b)
+ return a;
+ if (a == ProofOutcome.Top || b == ProofOutcome.Bottom)
+ return b;
+ if (b == ProofOutcome.Top || a == ProofOutcome.Bottom)
+ return a;
+
+ return ProofOutcome.Bottom;
+ }
+
+ public static ProofOutcome Join (this ProofOutcome a, ProofOutcome b)
+ {
+ if (a == b || a == ProofOutcome.Top || b == ProofOutcome.Bottom)
+ return a;
+ if (b == ProofOutcome.Top || a == ProofOutcome.Bottom)
+ return b;
+
+ return ProofOutcome.Top;
+ }
+
+ public static bool IsNormal (this ProofOutcome o)
+ {
+ return o == ProofOutcome.False || o == ProofOutcome.True;
+ }
+ }
+}
Mono.CodeContracts.Rewrite.AstVisitors/ExprVisitor.cs
Mono.CodeContracts.Rewrite.AstVisitors/InstructionExtentVisitor.cs
Mono.CodeContracts.Rewrite.AstVisitors/SourcePositionVisitor.cs
-
+Mono.CodeContracts.Static.Analysis.Drivers/AnalysisDriver.cs
+Mono.CodeContracts.Static.Analysis.Drivers/BasicAnalysisDriver.cs
+Mono.CodeContracts.Static.Analysis.Drivers/BasicMethodDriver.cs
+Mono.CodeContracts.Static.Analysis.Drivers/CodeContractsAnalysisDriver.cs
+Mono.CodeContracts.Static.Analysis.Drivers/IBasicAnalysisDriver.cs
+Mono.CodeContracts.Static.Analysis.Drivers/IBasicMethodDriver.cs
+Mono.CodeContracts.Static.Analysis.Drivers/IMethodAnalysis.cs
+Mono.CodeContracts.Static.Analysis.Drivers/IMethodAnalysisFixPoint.cs
+Mono.CodeContracts.Static.Analysis.Drivers/IMethodDriver.cs
+Mono.CodeContracts.Static.Analysis.Drivers/IMethodResult.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding/FullExpressionDecoder.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding/IFullExpressionDecoder.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding/QueryVisitor.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding/VisitorForIsBinaryExpression.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding/VisitorForIsInst.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding/VisitorForIsNull.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding/VisitorForIsUnaryExpression.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding/VisitorForSizeOf.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding/VisitorForUnderlyingVariable.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding/VisitorForValueOf.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding/VisitorForVariable.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Decoding/VisitorForVariablesIn.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions/BinaryExpr.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions/ConstExpr.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions/Expr.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions/IsInstExpr.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions/NullExpr.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions/SizeOfExpr.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis.Expressions/UnaryExpr.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis/AnalysisDecoder.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis/AssumeDecoder.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis/ExprDomain.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis/ExpressionAnalysisFacade.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis/ExpressionDecoder.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis/ExpressionDecoderAdapter.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis/ExpressionPrinterFactory.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis/ILDecoderAdapter.cs
+Mono.CodeContracts.Static.Analysis.ExpressionAnalysis/ValueAnalysis.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths/AccessPathFilter.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths/IVisibilityCheck.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths/MethodCallPathElement.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths/ParameterPathElement.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths/PathElement.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths/PathElementBase.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths/PathElement`1.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths/PathExtensions.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths/SpecialPathElement.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis.Paths/SpecialPathElementKind.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph/AbstractDomainUpdate.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph/EdgeUpdate.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph/EliminateEdgeUpdate.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph/EqualityPair.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph/EqualityUpdate.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph/IMergeInfo.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph/MergeInfo.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph/MultiEdge.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph/MultiEdgeUpdate.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph/SymGraph.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph/SymGraphTerm.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph/Update.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis/AbstractType.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis/AnalysisDecoder.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis/Domain.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis/FunctionsTable.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis/HeapAnalysis.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis/IAbstractDomainForEGraph.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis/IConstantInfo.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis/ISymGraph.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis/LabeledSymbol.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis/MethodWrapper.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis/ParameterWrapper.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis/StackToSymbolicAdapter.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis/SymbolicValue.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis/SymFunction.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis/SymValue.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis/TypeCache.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis/ValueContextProvider.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis/ValueDecoder.cs
+Mono.CodeContracts.Static.Analysis.HeapAnalysis/Wrapper.cs
+Mono.CodeContracts.Static.Analysis.NonNull/Analysis.cs
+Mono.CodeContracts.Static.Analysis.NonNull/Domain.cs
+Mono.CodeContracts.Static.Analysis.NonNull/ExpressionAssertDischarger.cs
+Mono.CodeContracts.Static.Analysis.NonNull/ExpressionAssumeDecoder.cs
+Mono.CodeContracts.Static.Analysis.NonNull/NonNullAnalysisFacade.cs
+Mono.CodeContracts.Static.Analysis.StackAnalysis/APCMap.cs
+Mono.CodeContracts.Static.Analysis.StackAnalysis/SequenceGenerator.cs
+Mono.CodeContracts.Static.Analysis.StackAnalysis/StackDecoder.cs
+Mono.CodeContracts.Static.Analysis.StackAnalysis/StackDepthFactory.cs
+Mono.CodeContracts.Static.Analysis.StackAnalysis/StackDepthProvider.cs
+Mono.CodeContracts.Static.Analysis.StackAnalysis/StackInfo.cs
+Mono.CodeContracts.Static.Analysis.StackAnalysis/StackInfo`1.cs
+Mono.CodeContracts.Static.Analysis/CodeLayer.cs
+Mono.CodeContracts.Static.Analysis/CodeLayerFactory.cs
+Mono.CodeContracts.Static.Analysis/ICodeLayer.cs
+Mono.CodeContracts.Static.Analysis/IExpressionContext.cs
+Mono.CodeContracts.Static.Analysis/IExpressionContextProvider.cs
+Mono.CodeContracts.Static.Analysis/ILPrinter.cs
+Mono.CodeContracts.Static.Analysis/IMethodContext.cs
+Mono.CodeContracts.Static.Analysis/IMethodContextProvider.cs
+Mono.CodeContracts.Static.Analysis/IStackContext.cs
+Mono.CodeContracts.Static.Analysis/IStackContextProvider.cs
+Mono.CodeContracts.Static.Analysis/IValueContext.cs
+Mono.CodeContracts.Static.Analysis/IValueContextProvider.cs
+Mono.CodeContracts.Static.Analysis/PrinterFactory.cs
+Mono.CodeContracts.Static.AST.Visitors/CodeVisitor.cs
+Mono.CodeContracts.Static.AST.Visitors/DefaultNodeVisitor.cs
+Mono.CodeContracts.Static.AST.Visitors/IAggregateVisitor.cs
+Mono.CodeContracts.Static.AST.Visitors/ICodeConsumer.cs
+Mono.CodeContracts.Static.AST.Visitors/IExpressionILVisitor.cs
+Mono.CodeContracts.Static.AST.Visitors/IILVisitor.cs
+Mono.CodeContracts.Static.AST.Visitors/ILVisitorBase.cs
+Mono.CodeContracts.Static.AST.Visitors/IMethodCodeConsumer.cs
+Mono.CodeContracts.Static.AST.Visitors/ISymbolicExpressionVisitor.cs
+Mono.CodeContracts.Static.AST.Visitors/ISyntheticILVisitor.cs
+Mono.CodeContracts.Static.AST.Visitors/NodeInspector.cs
+Mono.CodeContracts.Static.AST.Visitors/NodeVisitor.cs
+Mono.CodeContracts.Static.AST.Visitors/ValueCodeVisitor.cs
+Mono.CodeContracts.Static.AST/ArrayTypeNode.cs
+Mono.CodeContracts.Static.AST/AssemblyNode.cs
+Mono.CodeContracts.Static.AST/AssignmentStatement.cs
+Mono.CodeContracts.Static.AST/BinaryExpression.cs
+Mono.CodeContracts.Static.AST/BinaryOperator.cs
+Mono.CodeContracts.Static.AST/Block.cs
+Mono.CodeContracts.Static.AST/BlockExpression.cs
+Mono.CodeContracts.Static.AST/BodyParser.cs
+Mono.CodeContracts.Static.AST/Branch.cs
+Mono.CodeContracts.Static.AST/CatchFilter.cs
+Mono.CodeContracts.Static.AST/Class.cs
+Mono.CodeContracts.Static.AST/Construct.cs
+Mono.CodeContracts.Static.AST/CoreSystemTypes.cs
+Mono.CodeContracts.Static.AST/EndFinally.cs
+Mono.CodeContracts.Static.AST/Ensures.cs
+Mono.CodeContracts.Static.AST/ExceptionHandler.cs
+Mono.CodeContracts.Static.AST/Expression.cs
+Mono.CodeContracts.Static.AST/ExpressionStatement.cs
+Mono.CodeContracts.Static.AST/FaultHandler.cs
+Mono.CodeContracts.Static.AST/Field.cs
+Mono.CodeContracts.Static.AST/Literal.cs
+Mono.CodeContracts.Static.AST/Local.cs
+Mono.CodeContracts.Static.AST/Member.cs
+Mono.CodeContracts.Static.AST/MemberBinding.cs
+Mono.CodeContracts.Static.AST/Method.cs
+Mono.CodeContracts.Static.AST/MethodCall.cs
+Mono.CodeContracts.Static.AST/MethodContract.cs
+Mono.CodeContracts.Static.AST/MethodContractElement.cs
+Mono.CodeContracts.Static.AST/Module.cs
+Mono.CodeContracts.Static.AST/NaryExpression.cs
+Mono.CodeContracts.Static.AST/Node.cs
+Mono.CodeContracts.Static.AST/NodeType.cs
+Mono.CodeContracts.Static.AST/OperatorExtensions.cs
+Mono.CodeContracts.Static.AST/Parameter.cs
+Mono.CodeContracts.Static.AST/Property.cs
+Mono.CodeContracts.Static.AST/Reference.cs
+Mono.CodeContracts.Static.AST/Requires.cs
+Mono.CodeContracts.Static.AST/Return.cs
+Mono.CodeContracts.Static.AST/Statement.cs
+Mono.CodeContracts.Static.AST/This.cs
+Mono.CodeContracts.Static.AST/TypeNode.cs
+Mono.CodeContracts.Static.AST/UnaryExpression.cs
+Mono.CodeContracts.Static.AST/UnaryOperator.cs
+Mono.CodeContracts.Static.AST/Variable.cs
+Mono.CodeContracts.Static.ContractExtraction/ContractExtractor.cs
+Mono.CodeContracts.Static.ContractExtraction/ContractNodes.cs
+Mono.CodeContracts.Static.ContractExtraction/GatherLocals.cs
+Mono.CodeContracts.Static.ContractExtraction/HelperMethods.cs
+Mono.CodeContracts.Static.ContractExtraction/RepresentationForAttribute.cs
+Mono.CodeContracts.Static.ControlFlow.Blocks/AssumeBlock.cs
+Mono.CodeContracts.Static.ControlFlow.Blocks/BlockBase.cs
+Mono.CodeContracts.Static.ControlFlow.Blocks/BlockWithLabels.cs
+Mono.CodeContracts.Static.ControlFlow.Blocks/CatchFilterEntryBlock.cs
+Mono.CodeContracts.Static.ControlFlow.Blocks/EnsuresBlock.cs
+Mono.CodeContracts.Static.ControlFlow.Blocks/EntryBlock.cs
+Mono.CodeContracts.Static.ControlFlow.Blocks/EntryExitBlock.cs
+Mono.CodeContracts.Static.ControlFlow.Blocks/LabelAdapter.cs
+Mono.CodeContracts.Static.ControlFlow.Blocks/MethodCallBlock.cs
+Mono.CodeContracts.Static.ControlFlow.Blocks/NewObjCallBlock.cs
+Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders/BlockBuilder.cs
+Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders/BlockStartGatherer.cs
+Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders/EnsuresFactory.cs
+Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders/RequiresFactory.cs
+Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders/SimpleSubroutineBuilder.cs
+Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders/SubroutineBuilder.cs
+Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders/SubroutineFactory.cs
+Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders/SubroutineWithHandlersBuilder.cs
+Mono.CodeContracts.Static.ControlFlow.Subroutines/EnsuresSubroutine.cs
+Mono.CodeContracts.Static.ControlFlow.Subroutines/FaultFinallySubroutineBase.cs
+Mono.CodeContracts.Static.ControlFlow.Subroutines/FaultSubroutine.cs
+Mono.CodeContracts.Static.ControlFlow.Subroutines/FinallySubroutine.cs
+Mono.CodeContracts.Static.ControlFlow.Subroutines/MethodContractSubroutine.cs
+Mono.CodeContracts.Static.ControlFlow.Subroutines/MethodSubroutine.cs
+Mono.CodeContracts.Static.ControlFlow.Subroutines/OldScanStateMachine.cs
+Mono.CodeContracts.Static.ControlFlow.Subroutines/OldValueSubroutine.cs
+Mono.CodeContracts.Static.ControlFlow.Subroutines/RequiresSubroutine.cs
+Mono.CodeContracts.Static.ControlFlow.Subroutines/SimpleSubroutine.cs
+Mono.CodeContracts.Static.ControlFlow.Subroutines/SubroutineBase.cs
+Mono.CodeContracts.Static.ControlFlow.Subroutines/SubroutineFacade.cs
+Mono.CodeContracts.Static.ControlFlow.Subroutines/SubroutineWithHandlers.cs
+Mono.CodeContracts.Static.ControlFlow/APC.cs
+Mono.CodeContracts.Static.ControlFlow/APCDecoder.cs
+Mono.CodeContracts.Static.ControlFlow/CFGBlock.cs
+Mono.CodeContracts.Static.ControlFlow/ContractFilteredCFG.cs
+Mono.CodeContracts.Static.ControlFlow/ControlFlowGraph.cs
+Mono.CodeContracts.Static.ControlFlow/Edge.cs
+Mono.CodeContracts.Static.ControlFlow/EdgeMap.cs
+Mono.CodeContracts.Static.ControlFlow/EdgeTag.cs
+Mono.CodeContracts.Static.ControlFlow/EdgeTagExtensions.cs
+Mono.CodeContracts.Static.ControlFlow/EdgeVisitor.cs
+Mono.CodeContracts.Static.ControlFlow/ICFG.cs
+Mono.CodeContracts.Static.ControlFlow/IConstantInfo.cs
+Mono.CodeContracts.Static.ControlFlow/IHandlerFilter.cs
+Mono.CodeContracts.Static.ControlFlow/IMethodInfo.cs
+Mono.CodeContracts.Static.ControlFlow/IStackInfo.cs
+Mono.CodeContracts.Static.ControlFlow/RemoveBranchDelegator.cs
+Mono.CodeContracts.Static.ControlFlow/Subroutine.cs
+Mono.CodeContracts.Static.ControlFlow/SubroutineKind.cs
+Mono.CodeContracts.Static.DataFlowAnalysis/DataFlowAnalysisBase.cs
+Mono.CodeContracts.Static.DataFlowAnalysis/EdgeBasedWidening.cs
+Mono.CodeContracts.Static.DataFlowAnalysis/EdgeConverter.cs
+Mono.CodeContracts.Static.DataFlowAnalysis/ForwardAnalysis.cs
+Mono.CodeContracts.Static.DataFlowAnalysis/ForwardDataFlowAnalysisBase.cs
+Mono.CodeContracts.Static.DataFlowAnalysis/IAnalysis.cs
+Mono.CodeContracts.Static.DataFlowAnalysis/IFixPointInfo.cs
+Mono.CodeContracts.Static.DataFlowAnalysis/IWidenStrategy.cs
+Mono.CodeContracts.Static.DataFlowAnalysis/Joiner.cs
+Mono.CodeContracts.Static.DataFlowAnalysis/StepWidening.cs
+Mono.CodeContracts.Static.DataStructures/AbstractWorkList.cs
+Mono.CodeContracts.Static.DataStructures/DecoratorHelper.cs
+Mono.CodeContracts.Static.DataStructures/DepthFirst.cs
+Mono.CodeContracts.Static.DataStructures/DoubleDictionary.cs
+Mono.CodeContracts.Static.DataStructures/DoubleImmutableMap.cs
+Mono.CodeContracts.Static.DataStructures/Dummy.cs
+Mono.CodeContracts.Static.DataStructures/EdgeVisitor.cs
+Mono.CodeContracts.Static.DataStructures/GraphWrapper.cs
+Mono.CodeContracts.Static.DataStructures/IGraph.cs
+Mono.CodeContracts.Static.DataStructures/IImmutableIntMap.cs
+Mono.CodeContracts.Static.DataStructures/IImmutableMap.cs
+Mono.CodeContracts.Static.DataStructures/IImmutableSet.cs
+Mono.CodeContracts.Static.DataStructures/IIndexable.cs
+Mono.CodeContracts.Static.DataStructures/ImmutableIntKeyMap.cs
+Mono.CodeContracts.Static.DataStructures/ImmutableIntMap.cs
+Mono.CodeContracts.Static.DataStructures/ImmutableMap.cs
+Mono.CodeContracts.Static.DataStructures/ImmutableSet.cs
+Mono.CodeContracts.Static.DataStructures/ImmutableSetExtensions.cs
+Mono.CodeContracts.Static.DataStructures/Indexable.cs
+Mono.CodeContracts.Static.DataStructures/ITypedProperties.cs
+Mono.CodeContracts.Static.DataStructures/IWorkList.cs
+Mono.CodeContracts.Static.DataStructures/LispList.cs
+Mono.CodeContracts.Static.DataStructures/LispListExtensions.cs
+Mono.CodeContracts.Static.DataStructures/Optional.cs
+Mono.CodeContracts.Static.DataStructures/Pair.cs
+Mono.CodeContracts.Static.DataStructures/PriorityQueue.cs
+Mono.CodeContracts.Static.DataStructures/TypedKey.cs
+Mono.CodeContracts.Static.DataStructures/TypedProperties.cs
+Mono.CodeContracts.Static.DataStructures/VisitStatus.cs
+Mono.CodeContracts.Static.DataStructures/WorkList.cs
+Mono.CodeContracts.Static.Extensions/Extensions.cs
+Mono.CodeContracts.Static.Lattices/EnvironmentDomain.cs
+Mono.CodeContracts.Static.Lattices/FlatDomain.cs
+Mono.CodeContracts.Static.Lattices/IAbstractDomain.cs
+Mono.CodeContracts.Static.Lattices/SetDomain.cs
+Mono.CodeContracts.Static.Providers/CodeContractDecoder.cs
+Mono.CodeContracts.Static.Providers/CodeProviderImpl.cs
+Mono.CodeContracts.Static.Providers/ICodeProvider.cs
+Mono.CodeContracts.Static.Providers/IContractProvider.cs
+Mono.CodeContracts.Static.Providers/IILDecoder.cs
+Mono.CodeContracts.Static.Providers/IMetaDataProvider.cs
+Mono.CodeContracts.Static.Providers/IMethodCodeProvider.cs
+Mono.CodeContracts.Static.Providers/MetaDataProvider.cs
+Mono.CodeContracts.Static.Proving/AssertionFinder.cs
+Mono.CodeContracts.Static.Proving/BasicFacts.cs
+Mono.CodeContracts.Static.Proving/BoxedExpression.cs
+Mono.CodeContracts.Static.Proving/BoxedExpressionExtensions.cs
+Mono.CodeContracts.Static.Proving/ComposedFactQuery.cs
+Mono.CodeContracts.Static.Proving/ConstantPropagationFactQuery.cs
+Mono.CodeContracts.Static.Proving/IFactBase.cs
+Mono.CodeContracts.Static.Proving/IFactQuery.cs
+Mono.CodeContracts.Static.Proving/SimpleLogicInference.cs
+Mono.CodeContracts.Static/CheckResults.cs
+Mono.CodeContracts.Static/CheckOptions.cs
+Mono.CodeContracts.Static/Checker.cs
+Mono.CodeContracts.Static/DebugOptions.cs
+Mono.CodeContracts.Static/ProofOutcome.cs
+Mono.CodeContracts.Static/ProofOutcomeExtensions.cs
lc \
mono-configuration-crypto \
ccrewrite \
+ cccheck \
security
net_2_0_dirs := \
--- /dev/null
+thisdir = tools/cccheck
+SUBDIRS =
+include ../../build/rules.make
+
+PROGRAM = cccheck.exe
+
+LOCAL_MCS_FLAGS = -r:Mono.CodeContracts.dll
+
+include ../../build/executable.make
--- /dev/null
+using System;
+using Mono.CodeContracts.Static;
+using Mono.Options;
+
+namespace cccheck {
+ internal class Program {
+ private static void Main (string[] args)
+ {
+ var options = new CheckOptions ();
+ bool showOptions = false;
+ string showMsg = null;
+
+ var optionSet = new OptionSet {
+ {"help", "Show this help.", v => showOptions = v != null},
+ {"assembly=", "Assembly to check.", v => options.Assembly = v},
+ {"method=", "Method name (if you want to check only it).", v => options.Method = v},
+ {"debug=", "Show debug information", v=> options.ShowDebug = v != null}
+ };
+
+ try {
+ optionSet.Parse (args);
+ } catch (OptionException e) {
+ showOptions = true;
+ showMsg = e.Message;
+ }
+
+ if (showOptions) {
+ Console.WriteLine ("cccheck");
+ Console.WriteLine ();
+ Console.WriteLine ("Options:");
+ optionSet.WriteOptionDescriptions (Console.Out);
+ Console.WriteLine ();
+ if (showMsg != null) {
+ Console.WriteLine (showMsg);
+ Console.WriteLine ();
+ }
+ return;
+ }
+
+ CheckResults results = Checker.Check (options);
+ Console.WriteLine ();
+ if (results.AnyErrors) {
+ foreach (string error in results.Errors)
+ Console.WriteLine ("Error: " + error);
+ }
+
+ if (results.AnyWarnings) {
+ foreach (string warning in results.Warnings)
+ Console.WriteLine ("Warning: " + warning);
+ }
+
+ if (results.Results != null) {
+ foreach (var methodValidationResults in results.Results) {
+ string methodName = methodValidationResults.Key;
+ Console.WriteLine ("Method: " + methodName);
+ foreach (string result in methodValidationResults.Value)
+ Console.WriteLine (" " + result);
+ Console.WriteLine ();
+ }
+ }
+
+ Console.WriteLine ();
+ Console.WriteLine ("*** done ***");
+ }
+ }
+}
--- /dev/null
+../../build/common/Consts.cs
+../../class/Mono.Options/Mono.Options/Options.cs
+Program.cs