From d5bf8e1275ae1cc79ddb7048d2015160bdf2bddc Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 8 Jul 2011 16:29:38 -0700 Subject: phone injecting code traverser --- BCT/BytecodeTranslator/BytecodeTranslator.csproj | 1 + BCT/BytecodeTranslator/Phone/PhoneTraverser.cs | 130 +++++++++++++++++++++ BCT/BytecodeTranslator/Program.cs | 12 +- BCT/BytecodeTranslator/Sink.cs | 9 -- .../PhoneControlsExtractor.py | 3 +- BCT/TranslationPlugins/PhoneControlsPlugin.cs | 6 + 6 files changed, 144 insertions(+), 17 deletions(-) create mode 100644 BCT/BytecodeTranslator/Phone/PhoneTraverser.cs 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 @@ + 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 { + + /// + /// Traverse code looking for phone specific points of interest, possibly injecting necessary code in-between + /// + + 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 + } + } + + /// + /// Traverse metadata looking only for PhoneApplicationPage's constructors + /// + 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); + } + + /// + /// Check if the type being defined is a PhoneApplicationPage, uninteresting otherwise + /// + /// + 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; + } + + /// + /// Check if it is traversing a constructor. If so, place necessary code after InitializeComponent() call + /// + 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 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 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(); StreamReader fileStream = null; @@ -172,6 +177,7 @@ namespace TranslationPlugins { controlInfoStr.setHandler(Event.Unchecked, uncheckedHandler); pageStr.setControlInfo(controlName, controlInfoStr); + pageStructureInfo[pageClass] = pageStr; configLine = configStream.ReadLine(); } -- cgit v1.2.3