diff options
-rw-r--r-- | BCT/BytecodeTranslator/BytecodeTranslator.csproj | 1 | ||||
-rw-r--r-- | BCT/BytecodeTranslator/Phone/PhoneTraverser.cs | 130 | ||||
-rw-r--r-- | BCT/BytecodeTranslator/Program.cs | 12 | ||||
-rw-r--r-- | BCT/BytecodeTranslator/Sink.cs | 9 | ||||
-rw-r--r-- | BCT/PhoneControlsExtractor/PhoneControlsExtractor.py | 3 | ||||
-rw-r--r-- | BCT/TranslationPlugins/PhoneControlsPlugin.cs | 6 |
6 files changed, 144 insertions, 17 deletions
diff --git a/BCT/BytecodeTranslator/BytecodeTranslator.csproj b/BCT/BytecodeTranslator/BytecodeTranslator.csproj index 51729cce..0393913a 100644 --- a/BCT/BytecodeTranslator/BytecodeTranslator.csproj +++ b/BCT/BytecodeTranslator/BytecodeTranslator.csproj @@ -125,6 +125,7 @@ <Compile Include="Heap.cs" />
<Compile Include="HeapFactory.cs" />
<Compile Include="MetadataTraverser.cs" />
+ <Compile Include="Phone\PhoneTraverser.cs" />
<Compile Include="Prelude.cs" />
<Compile Include="ExpressionTraverser.cs" />
<Compile Include="Sink.cs" />
diff --git a/BCT/BytecodeTranslator/Phone/PhoneTraverser.cs b/BCT/BytecodeTranslator/Phone/PhoneTraverser.cs new file mode 100644 index 00000000..98aa4461 --- /dev/null +++ b/BCT/BytecodeTranslator/Phone/PhoneTraverser.cs @@ -0,0 +1,130 @@ +//-----------------------------------------------------------------------------
+//
+// 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;
+
+
+namespace BytecodeTranslator {
+
+ /// <summary>
+ /// Traverse code looking for phone specific points of interest, possibly injecting necessary code in-between
+ /// </summary>
+
+ public class PhoneCodeTraverser : BaseCodeTraverser {
+ private readonly IMethodDefinition methodBeingTraversed;
+ private static bool initializationEncountered;
+
+ public PhoneCodeTraverser(IMethodDefinition traversedMethod) : base() {
+ this.methodBeingTraversed = traversedMethod;
+ }
+
+ public void injectPhoneControlsCode(BlockStatement block) {
+ this.Visit(block);
+ }
+
+ private void injectPhoneInitializationCode(IBlockStatement block, IStatement statementAfter) {
+ }
+
+ public override void Visit(IBlockStatement block) {
+ initializationEncountered = false;
+ foreach (IStatement statement in block.Statements) {
+ this.Visit(statement);
+ if (initializationEncountered) {
+ injectPhoneInitializationCode(block, statement);
+ break;
+ }
+ }
+ }
+
+ public override void Visit(IMethodCall methodCall) {
+ if (methodCall.IsStaticCall ||
+ !methodCall.MethodToCall.ContainingType.ResolvedType.Equals(methodBeingTraversed.Container) ||
+ methodCall.MethodToCall.Name.Value != "InitializeComponent" ||
+ methodCall.Arguments.Any())
+ return;
+
+ // otherwise we need to insert the desired code after this call
+ // TODO make sure I am dealing with the MUTABLE code model
+ }
+ }
+
+ /// <summary>
+ /// Traverse metadata looking only for PhoneApplicationPage's constructors
+ /// </summary>
+ public class PhoneMetadataTraverser : BaseMetadataTraverser {
+
+ public PhoneMetadataTraverser()
+ : base() {
+ }
+
+ public override void Visit(IModule module) {
+ base.Visit(module);
+ }
+
+ public override void Visit(IAssembly assembly) {
+ base.Visit(assembly);
+ }
+
+ /// <summary>
+ /// Check if the type being defined is a PhoneApplicationPage, uninteresting otherwise
+ /// </summary>
+ ///
+ public override void Visit(ITypeDefinition typeDefinition) {
+ if (typeDefinition.IsClass && isPhoneApplicationPage(typeDefinition)) {
+ base.Visit(typeDefinition);
+ }
+ }
+
+ private bool isPhoneApplicationPage(ITypeDefinition typeDefinition) {
+ ITypeReference baseClass = typeDefinition.BaseClasses.FirstOrDefault();
+ ITypeDefinition baseClassDef;
+ while (baseClass != null) {
+ baseClassDef = baseClass.ResolvedType;
+ if (baseClassDef is INamespaceTypeDefinition) {
+ if (((INamespaceTypeDefinition) baseClassDef).Name.Value == "PhoneApplicationPage" &&
+ ((INamespaceTypeDefinition) baseClassDef).Container.ToString() == "Microsoft.Phone.Controls") {
+ return true;
+ }
+ }
+ baseClass = baseClass.ResolvedType.BaseClasses.FirstOrDefault();
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Check if it is traversing a constructor. If so, place necessary code after InitializeComponent() call
+ /// </summary>
+ public override void Visit(IMethodDefinition method) {
+ if (!method.IsConstructor)
+ return;
+
+ PhoneCodeTraverser codeTraverser = new PhoneCodeTraverser(method);
+ var methodBody = method.Body as ISourceMethodBody;
+ if (methodBody == null)
+ return;
+ var block = methodBody.Block as BlockStatement;
+ codeTraverser.injectPhoneControlsCode(block);
+ }
+
+ public virtual void InjectPhoneCodeAssemblies(IEnumerable<IUnit> assemblies) {
+ foreach (var a in assemblies) {
+ a.Dispatch(this);
+ }
+ }
+ }
+}
\ No newline at end of file diff --git a/BCT/BytecodeTranslator/Program.cs b/BCT/BytecodeTranslator/Program.cs index 05366fc5..7ce0c37a 100644 --- a/BCT/BytecodeTranslator/Program.cs +++ b/BCT/BytecodeTranslator/Program.cs @@ -174,18 +174,18 @@ namespace BytecodeTranslator { var primaryModule = modules[0];
+ if (phoneControlsConfigFile != null && phoneControlsConfigFile != "") {
+ PhoneMetadataTraverser tr = new PhoneMetadataTraverser();
+ tr.InjectPhoneCodeAssemblies(modules);
+ }
+
TraverserFactory traverserFactory;
if (wholeProgram)
traverserFactory = new WholeProgram();
else
traverserFactory = new CLRSemantics();
- Sink sink;
- if (phoneControlsConfigFile != null && phoneControlsConfigFile != "") {
- sink = new Sink(host, traverserFactory, heapFactory, phoneControlsConfigFile);
- } else {
- sink = new Sink(host, traverserFactory, heapFactory);
- }
+ Sink sink= new Sink(host, traverserFactory, heapFactory);
TranslationHelper.tmpVarCounter = 0;
MetadataTraverser translator = traverserFactory.MakeMetadataTraverser(sink, contractExtractors, pdbReaders);
diff --git a/BCT/BytecodeTranslator/Sink.cs b/BCT/BytecodeTranslator/Sink.cs index f81581c9..b5c01fc1 100644 --- a/BCT/BytecodeTranslator/Sink.cs +++ b/BCT/BytecodeTranslator/Sink.cs @@ -22,20 +22,11 @@ namespace BytecodeTranslator { public class Sink {
- private TranslationPlugins.PhoneControlsPlugin phonePlugin;
-
public TraverserFactory Factory {
get { return this.factory; }
}
readonly TraverserFactory factory;
- public Sink(IContractAwareHost host, TraverserFactory factory, HeapFactory heapFactory, string phoneControlsConfigFile)
- : this(host, factory, heapFactory) {
- // TODO I'm loading the config file here, it would be best to create the sink and then register callback plugins from outside
-
- phonePlugin = new TranslationPlugins.PhoneControlsPlugin(phoneControlsConfigFile);
- }
-
public Sink(IContractAwareHost host, TraverserFactory factory, HeapFactory heapFactory) {
Contract.Requires(host != null);
Contract.Requires(factory != null);
diff --git a/BCT/PhoneControlsExtractor/PhoneControlsExtractor.py b/BCT/PhoneControlsExtractor/PhoneControlsExtractor.py index 46f5aaf7..8ca29036 100644 --- a/BCT/PhoneControlsExtractor/PhoneControlsExtractor.py +++ b/BCT/PhoneControlsExtractor/PhoneControlsExtractor.py @@ -117,8 +117,7 @@ def outputPhoneControls(outputFileName): outputFile.close()
def extractPhoneControls(sourceDir):
- fileList= [os.path.normcase(fileName) for fileName in os.listdir(sourceDir)]
- fileList= [os.path.join(sourceDir, fileName) for fileName in fileList if os.path.splitext(fileName)[1] == ".xaml"]
+ fileList= [os.path.join(sourceDir, fileName) for fileName in os.listdir(sourceDir) if os.path.splitext(fileName)[1] == ".xaml"]
for fileName in fileList:
extractPhoneControlsFromPage(fileName)
diff --git a/BCT/TranslationPlugins/PhoneControlsPlugin.cs b/BCT/TranslationPlugins/PhoneControlsPlugin.cs index d63b6489..9ed1c7df 100644 --- a/BCT/TranslationPlugins/PhoneControlsPlugin.cs +++ b/BCT/TranslationPlugins/PhoneControlsPlugin.cs @@ -98,6 +98,11 @@ namespace TranslationPlugins { private IDictionary<string, PageStructure> pageStructureInfo;
+ public static string getFullyQualifiedControlClass(string controlClass) {
+ // TODO do an actual API discovery. The problem will be differencing 7.0 apps from 7.1 apps
+ return "System.Windows.Controls." + controlClass;
+ }
+
public PhoneControlsPlugin(string configFile) {
pageStructureInfo = new Dictionary<string, PageStructure>();
StreamReader fileStream = null;
@@ -172,6 +177,7 @@ namespace TranslationPlugins { controlInfoStr.setHandler(Event.Unchecked, uncheckedHandler);
pageStr.setControlInfo(controlName, controlInfoStr);
+ pageStructureInfo[pageClass] = pageStr;
configLine = configStream.ReadLine();
}
|