//-----------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation. All Rights Reserved.
//
//-----------------------------------------------------------------------------
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;
using TranslationPlugins;
using BytecodeTranslator.Phone;
using BytecodeTranslator.TranslationPlugins;
namespace BytecodeTranslator {
///
/// Responsible for traversing all metadata elements (i.e., everything exclusive
/// of method bodies).
///
public class BCTMetadataTraverser : MetadataTraverser {
readonly Sink sink;
public readonly TraverserFactory Factory;
public readonly IDictionary PdbReaders;
public PdbReader/*?*/ PdbReader;
public BCTMetadataTraverser(Sink sink, IDictionary pdbReaders, TraverserFactory factory)
: base() {
this.sink = sink;
this.Factory = factory;
this.PdbReaders = pdbReaders;
}
public IEnumerable getPreconditionTranslation(IMethodContract contract) {
ICollection translatedPres = new List();
foreach (IPrecondition pre in contract.Preconditions) {
var stmtTraverser = this.Factory.MakeStatementTraverser(sink, null, true);
ExpressionTraverser exptravers = this.Factory.MakeExpressionTraverser(sink, stmtTraverser, true);
exptravers.Traverse(pre.Condition); // TODO
// Todo: Deal with Descriptions
var req = new Bpl.Requires(pre.Token(), false, exptravers.TranslatedExpressions.Pop(), "");
translatedPres.Add(req);
}
return translatedPres;
}
public IEnumerable getPostconditionTranslation(IMethodContract contract) {
ICollection translatedPosts = new List();
foreach (IPostcondition post in contract.Postconditions) {
var stmtTraverser = this.Factory.MakeStatementTraverser(sink, null, true);
ExpressionTraverser exptravers = this.Factory.MakeExpressionTraverser(sink, stmtTraverser, true);
exptravers.Traverse(post.Condition);
// Todo: Deal with Descriptions
var ens = new Bpl.Ensures(post.Token(), false, exptravers.TranslatedExpressions.Pop(), "");
translatedPosts.Add(ens);
}
return translatedPosts;
}
public IEnumerable getModifiedIdentifiers(IMethodContract contract) {
ICollection modifiedExpr = new List();
foreach (IAddressableExpression mod in contract.ModifiedVariables) {
ExpressionTraverser exptravers = this.Factory.MakeExpressionTraverser(sink, null, true);
exptravers.Traverse(mod);
Bpl.IdentifierExpr idexp = exptravers.TranslatedExpressions.Pop() as Bpl.IdentifierExpr;
if (idexp == null) {
throw new TranslationException(String.Format("Cannot create IdentifierExpr for Modifyed Variable {0}", mod.ToString()));
}
modifiedExpr.Add(idexp);
}
return modifiedExpr;
}
#region Overrides
public override void TraverseChildren(IModule module) {
this.PdbReaders.TryGetValue(module, out this.PdbReader);
if (!(module.EntryPoint is Dummy))
this.entryPoint = module.EntryPoint;
base.TraverseChildren(module);
}
public override void TraverseChildren(IAssembly assembly) {
this.PdbReaders.TryGetValue(assembly, out this.PdbReader);
this.sink.BeginAssembly(assembly);
try {
base.TraverseChildren(assembly);
} finally {
this.sink.EndAssembly(assembly);
}
}
///
/// Translate the type definition.
///
///
public override void TraverseChildren(ITypeDefinition typeDefinition) {
if (!this.sink.TranslateType(typeDefinition)) return;
var savedPrivateTypes = this.privateTypes;
this.privateTypes = new List();
trackPhonePageNameVariableName(typeDefinition);
trackPhoneApplicationClassname(typeDefinition);
var gtp = typeDefinition as IGenericTypeParameter;
if (gtp != null) {
return;
}
if (typeDefinition.IsClass) {
bool savedSawCctor = this.sawCctor;
this.sawCctor = false;
sink.FindOrDefineType(typeDefinition);
base.TraverseChildren(typeDefinition);
if (!this.sawCctor) {
CreateStaticConstructor(typeDefinition);
}
this.sawCctor = savedSawCctor;
} else if (typeDefinition.IsDelegate) {
ITypeDefinition unspecializedType = Microsoft.Cci.MutableContracts.ContractHelper.Unspecialized(typeDefinition).ResolvedType;
sink.AddDelegateType(unspecializedType);
} else if (typeDefinition.IsInterface) {
sink.FindOrCreateTypeReference(typeDefinition);
base.TraverseChildren(typeDefinition);
} else if (typeDefinition.IsEnum) {
return; // enums just are translated as ints
} else if (typeDefinition.IsStruct) {
sink.FindOrCreateTypeReference(typeDefinition);
CreateDefaultStructConstructor(typeDefinition);
CreateStructCopyConstructor(typeDefinition);
base.TraverseChildren(typeDefinition);
} else {
Console.WriteLine("Unknown kind of type definition '{0}' was found",
TypeHelper.GetTypeName(typeDefinition));
throw new NotImplementedException(String.Format("Unknown kind of type definition '{0}'.", TypeHelper.GetTypeName(typeDefinition)));
}
this.Traverse(typeDefinition.PrivateHelperMembers);
foreach (var t in this.privateTypes) {
this.Traverse(t);
}
}
List privateTypes = new List();
private void trackPhoneApplicationClassname(ITypeDefinition typeDef) {
if (PhoneCodeHelper.instance().PhonePlugin != null && typeDef.isPhoneApplicationClass(sink.host)) {
INamespaceTypeDefinition namedTypeDef = typeDef as INamespaceTypeDefinition;
// string fullyQualifiedName = namedTypeDef.ContainingNamespace.Name.Value + "." + namedTypeDef.Name.Value;
string fullyQualifiedName = namedTypeDef.ToString();
PhoneCodeHelper.instance().setMainAppTypeReference(typeDef);
PhoneCodeHelper.instance().setMainAppTypeName(fullyQualifiedName);
}
}
private void trackPhonePageNameVariableName(ITypeDefinition typeDef) {
if (PhoneCodeHelper.instance().PhonePlugin != null && typeDef.isPhoneApplicationPageClass(sink.host)) {
INamespaceTypeDefinition namedTypeDef = typeDef as INamespaceTypeDefinition;
string fullyQualifiedName = namedTypeDef.ToString();
string xamlForClass = PhoneCodeHelper.instance().getXAMLForPage(fullyQualifiedName);
if (xamlForClass != null) { // if not it is possibly an abstract page
string uriName = UriHelper.getURIBase(xamlForClass);
Bpl.Constant uriConstant = sink.FindOrCreateConstant(uriName);
PhoneCodeHelper.instance().setBoogieStringPageNameForPageClass(fullyQualifiedName, uriConstant.Name);
}
}
}
/*
private void translateAnonymousControlsForPage(ITypeDefinition typeDef) {
if (PhoneCodeHelper.instance().PhonePlugin != null && typeDef.isPhoneApplicationPageClass(sink.host)) {
IEnumerable pageCtrls= PhoneCodeHelper.instance().PhonePlugin.getControlsForPage(typeDef.ToString());
foreach (ControlInfoStructure ctrlInfo in pageCtrls) {
if (ctrlInfo.Name.Contains(PhoneControlsPlugin.BOOGIE_DUMMY_CONTROL) || ctrlInfo.Name == Dummy.Name.Value) {
string anonymousControlName = ctrlInfo.Name;
IFieldDefinition fieldDef = new FieldDefinition() {
ContainingTypeDefinition = typeDef,
Name = sink.host.NameTable.GetNameFor(anonymousControlName),
InternFactory = sink.host.InternFactory,
Visibility = TypeMemberVisibility.Public,
Type = sink.host.PlatformType.SystemObject,
IsStatic = false,
};
(typeDef as Microsoft.Cci.MutableCodeModel.NamespaceTypeDefinition).Fields.Add(fieldDef);
//sink.FindOrCreateFieldVariable(fieldDef);
}
}
}
}
*/
private void CreateDefaultStructConstructor(ITypeDefinition typeDefinition) {
Contract.Requires(typeDefinition.IsStruct);
var proc = this.sink.FindOrCreateProcedureForDefaultStructCtor(typeDefinition);
this.sink.BeginMethod(typeDefinition);
var stmtTranslator = this.Factory.MakeStatementTraverser(this.sink, this.PdbReader, false);
var stmts = new List();
foreach (var f in typeDefinition.Fields) {
if (f.IsStatic) continue;
var s = new ExpressionStatement() {
Expression = new Assignment() {
Source = new DefaultValue() { DefaultValueType = f.Type, Type = f.Type, },
Target = new TargetExpression() {
Definition = f,
Instance = new ThisReference() { Type = typeDefinition, },
Type = f.Type,
},
Type = f.Type,
},
};
stmts.Add(s);
}
stmtTranslator.Traverse(stmts);
var translatedStatements = stmtTranslator.StmtBuilder.Collect(Bpl.Token.NoToken);
var lit = Bpl.Expr.Literal(1);
lit.Type = Bpl.Type.Int;
var args = new List