using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Cci;
using Microsoft.Cci.MetadataReader;
using Microsoft.Cci.MutableCodeModel;
using Microsoft.Cci.Contracts;
using Microsoft.Cci.ILToCodeModel;
using Bpl = Microsoft.Boogie;
using System.Diagnostics.Contracts;
namespace BytecodeTranslator {
class WholeProgram : TraverserFactory {
///
/// Table to be filled by the metadata traverser before visiting any assemblies.
///
/// The table lists the direct supertypes of all type definitions that it encounters during the
/// traversal. (But the table is organized so that subTypes[T] is the list of type definitions
/// that are direct subtypes of T.)
///
readonly public Dictionary> subTypes = new Dictionary>();
public override MetadataTraverser MakeMetadataTraverser(Sink sink,
IDictionary contractProviders, // TODO: remove this parameter?
IDictionary pdbReaders) {
return new WholeProgramMetadataSemantics(this, sink, pdbReaders);
}
public class WholeProgramMetadataSemantics : MetadataTraverser {
readonly WholeProgram parent;
readonly Sink sink;
readonly Dictionary codeUnderAnalysis = new Dictionary();
public WholeProgramMetadataSemantics(WholeProgram parent, Sink sink, IDictionary pdbReaders)
: base(sink, pdbReaders) {
this.parent = parent;
this.sink = sink;
}
public override void TranslateAssemblies(IEnumerable assemblies) {
#region traverse all of the units gathering type information
var typeRecorder = new RecordSubtypes(this.parent.subTypes);
foreach (var a in assemblies) {
this.codeUnderAnalysis.Add(a, true);
typeRecorder.Visit(a);
}
#endregion
base.TranslateAssemblies(assemblies);
}
class RecordSubtypes : BaseMetadataTraverser {
Dictionary> subTypes;
public RecordSubtypes(Dictionary> subTypes) {
this.subTypes = subTypes;
}
public override void Visit(ITypeDefinition typeDefinition) {
foreach (var baseClass in typeDefinition.BaseClasses) {
if (!this.subTypes.ContainsKey(baseClass)) {
this.subTypes[baseClass] = new List();
}
this.subTypes[baseClass].Add(typeDefinition);
}
base.Visit(typeDefinition);
}
}
}
public override ExpressionTraverser MakeExpressionTraverser(Sink sink, StatementTraverser/*?*/ statementTraverser, bool contractContext) {
return new WholeProgramExpressionSemantics(this, sink, statementTraverser, contractContext);
}
///
/// implement virtual method calls to methods defined in the CUA (code under analysis, i.e.,
/// the set of assemblies being translated) by a "switch statement" that dispatches to the
/// most derived type's method. I.e., make explicit the dynamic dispatch mechanism.
///
public class WholeProgramExpressionSemantics : CLRSemantics.CLRExpressionSemantics {
readonly WholeProgram parent;
readonly public Dictionary> subTypes;
public WholeProgramExpressionSemantics(WholeProgram parent, Sink sink, StatementTraverser/*?*/ statementTraverser, bool contractContext)
: base(sink, statementTraverser, contractContext) {
this.parent = parent;
this.subTypes = parent.subTypes;
}
public override void Visit(IMethodCall methodCall) {
if (!methodCall.IsVirtualCall) {
base.Visit(methodCall);
return;
}
var containingType = methodCall.MethodToCall.ContainingType;
List subTypesOfContainingType;
if (!this.subTypes.TryGetValue(containingType, out subTypesOfContainingType)) {
base.Visit(methodCall);
return;
}
Contract.Assert(0 < subTypesOfContainingType.Count);
Contract.Assert(!methodCall.IsStaticCall);
var resolvedMethod = methodCall.MethodToCall.ResolvedMethod;
Contract.Assert(!resolvedMethod.IsConstructor);
var overrides = FindOverrides(containingType, resolvedMethod);
if (0 == overrides.Count) {
base.Visit(methodCall);
return;
}
Bpl.IToken token = methodCall.Token();
List inexpr;
List outvars;
Bpl.IdentifierExpr thisExpr;
Dictionary toBoxed;
var proc = TranslateArgumentsAndReturnProcedure(token, methodCall.MethodToCall, resolvedMethod, methodCall.IsStaticCall ? null : methodCall.ThisArgument, methodCall.Arguments, out inexpr, out outvars, out thisExpr, out toBoxed);
Bpl.QKeyValue attrib = null;
foreach (var a in resolvedMethod.Attributes) {
if (TypeHelper.GetTypeName(a.Type).EndsWith("AsyncAttribute")) {
attrib = new Bpl.QKeyValue(token, "async", new List