diff options
-rw-r--r-- | BCT/BytecodeTranslator/Phone/PhoneTraverser.cs | 236 | ||||
-rw-r--r-- | BCT/BytecodeTranslator/Program.cs | 4 | ||||
-rw-r--r-- | BCT/TranslationPlugins/PhoneControlsPlugin.cs | 9 |
3 files changed, 232 insertions, 17 deletions
diff --git a/BCT/BytecodeTranslator/Phone/PhoneTraverser.cs b/BCT/BytecodeTranslator/Phone/PhoneTraverser.cs index 98aa4461..5f4680a8 100644 --- a/BCT/BytecodeTranslator/Phone/PhoneTraverser.cs +++ b/BCT/BytecodeTranslator/Phone/PhoneTraverser.cs @@ -12,10 +12,10 @@ 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;
namespace BytecodeTranslator {
@@ -23,28 +23,235 @@ 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;
+ private static bool initializationFound= false;
+ private PhoneControlsPlugin phonePlugin;
+ private MetadataReaderHost host;
+
+ private IAssemblyReference coreAssemblyRef;
+ private IAssemblyReference phoneAssembly;
+ private IAssemblyReference phoneSystemWindowsAssembly;
+ private INamespaceTypeReference checkBoxType;
+ private INamespaceTypeReference radioButtonType;
+ private INamespaceTypeReference buttonType;
+ private INamespaceTypeReference buttonBaseType;
+ private INamespaceTypeReference toggleButtonType;
+ private INamespaceTypeReference controlType;
+ private INamespaceTypeReference uiElementType;
+
+ private CompileTimeConstant trueConstant;
+ private CompileTimeConstant falseConstant;
- public PhoneCodeTraverser(IMethodDefinition traversedMethod) : base() {
+ private IMethodReference isEnabledSetter;
+ private IMethodReference isEnabledGetter;
+ private IMethodReference isCheckedSetter;
+ private IMethodReference isCheckedGetter;
+ private IMethodReference visibilitySetter;
+ private IMethodReference visibilityGetter;
+ private IMethodReference clickHandlerAdder;
+ private IMethodReference clickHandlerRemover;
+ private IMethodReference checkedHandlerAdder;
+ private IMethodReference checkedHandlerRemover;
+ private IMethodReference uncheckedHandlerAdder;
+ private IMethodReference uncheckedHandlerRemover;
+
+ private ITypeReference getTypeForClassname(String classname) {
+ if (classname == "Button") {
+ return buttonType;
+ } else if (classname == "RadioButton") {
+ return radioButtonType;
+ } else if (classname == "CheckBox") {
+ return checkBoxType;
+ } else {
+ // TODO avoid throwing exceptions, just log
+ throw new NotImplementedException("Type " + classname + " is not being monitored yet for phone controls");
+ }
+ }
+
+ public PhoneCodeTraverser(MetadataReaderHost host, IMethodDefinition traversedMethod, PhoneControlsPlugin phonePlugin) : base() {
this.methodBeingTraversed = traversedMethod;
+ this.phonePlugin = phonePlugin;
+ this.host = host;
+ InitializeTraverser();
+ }
+
+ private void InitializeTraverser() {
+ Microsoft.Cci.Immutable.PlatformType platform = host.PlatformType as Microsoft.Cci.Immutable.PlatformType;
+ coreAssemblyRef = platform.CoreAssemblyRef;
+
+ // TODO obtain version, culture and signature data dynamically
+ AssemblyIdentity MSPhoneAssemblyId =
+ new AssemblyIdentity(host.NameTable.GetNameFor("Microsoft.Phone"), "", new Version("7.0.0.0"),
+ new byte[] { 0x24, 0xEE, 0xC0, 0xD8, 0xC8, 0x6C, 0xDA, 0x1E }, "");
+ AssemblyIdentity MSPhoneSystemWindowsAssemblyId =
+ new AssemblyIdentity(host.NameTable.GetNameFor("System.Windows"), coreAssemblyRef.Culture, coreAssemblyRef.Version,
+ coreAssemblyRef.PublicKeyToken, "");
+
+ phoneAssembly = host.FindAssembly(MSPhoneAssemblyId);
+ phoneSystemWindowsAssembly = host.FindAssembly(MSPhoneSystemWindowsAssemblyId);
+
+ // TODO determine the needed types dynamically
+ checkBoxType = platform.CreateReference(phoneSystemWindowsAssembly, "System", "Windows", "Controls", "CheckBox");
+ radioButtonType = platform.CreateReference(phoneSystemWindowsAssembly, "System", "Windows", "Controls", "RadioButton");
+ buttonType = platform.CreateReference(phoneSystemWindowsAssembly, "System", "Windows", "Controls", "Button");
+ buttonBaseType = platform.CreateReference(phoneSystemWindowsAssembly, "System", "Windows", "Controls", "Primitives", "ButtonBase");
+ toggleButtonType = platform.CreateReference(phoneSystemWindowsAssembly, "System", "Windows", "Controls", "Primitives", "ToggleButton");
+ controlType = platform.CreateReference(phoneSystemWindowsAssembly, "System", "Windows", "Controls", "Control");
+ uiElementType = platform.CreateReference(phoneSystemWindowsAssembly, "System", "Windows", "UIElement");
+
+ trueConstant = new CompileTimeConstant() {
+ Type = platform.SystemBoolean,
+ Value = true
+ };
+ falseConstant = new CompileTimeConstant() {
+ Type = platform.SystemBoolean,
+ Value = false
+ };
+
+ IEnumerable<IPropertyDefinition> controlProperties = controlType.ResolvedType.Properties;
+ IEnumerable<IPropertyDefinition> toggleButtonProperties = toggleButtonType.ResolvedType.Properties;
+ IEnumerable<IPropertyDefinition> uiElementProperties = uiElementType.ResolvedType.Properties;
+
+ IPropertyDefinition prop = controlProperties.Single(p => p.Name.Value == "IsEnabled");
+ isEnabledSetter = prop.Setter;
+ isEnabledGetter = prop.Getter;
+ prop = toggleButtonProperties.Single(p => p.Name.Value == "IsChecked");
+ isCheckedSetter = prop.Setter;
+ isCheckedGetter = prop.Getter;
+ prop = uiElementProperties.Single(p => p.Name.Value == "Visibility");
+ visibilitySetter = prop.Setter;
+ visibilityGetter = prop.Getter;
+
+ IEnumerable<IEventDefinition> buttonBaseEvents = buttonBaseType.ResolvedType.Events;
+ IEnumerable<IEventDefinition> toggleButtonEvents = toggleButtonType.ResolvedType.Events;
+ IEventDefinition evt = buttonBaseEvents.Single(e => e.Name.Value == "Click");
+ clickHandlerAdder = evt.Adder;
+ clickHandlerRemover = evt.Remover;
+ evt = toggleButtonEvents.Single(e => e.Name.Value == "Checked");
+ checkedHandlerAdder = evt.Adder;
+ checkedHandlerRemover = evt.Remover;
+ evt = toggleButtonEvents.Single(e => e.Name.Value == "Unchecked");
+ uncheckedHandlerAdder = evt.Adder;
+ uncheckedHandlerRemover = evt.Remover;
}
public void injectPhoneControlsCode(BlockStatement block) {
this.Visit(block);
}
- private void injectPhoneInitializationCode(IBlockStatement block, IStatement statementAfter) {
+ private Assignment MakeFieldAssigment(string assignType, string objectName, string objectType, string fieldName, string sourceObjName, string sourceObjType, string sourceObjFieldName) {
+ /* TODO */
+ return null;
+ }
+
+ private void injectPhoneInitializationCode(BlockStatement block, Statement statementAfter) {
+ // TODO check page name against container name
+ IEnumerable<ControlInfoStructure> controls= phonePlugin.getControlsForPage(methodBeingTraversed.Container.ToString());
+ IEnumerable<IStatement> injectedStatements = new List<IStatement>();
+ foreach (ControlInfoStructure controlInfo in controls) {
+ injectedStatements = injectedStatements.Concat(getCodeForSettingEnabledness(controlInfo));
+ injectedStatements = injectedStatements.Concat(getCodeForSettingCheckedState(controlInfo));
+ injectedStatements = injectedStatements.Concat(getCodeForSettingVisibility(controlInfo));
+ injectedStatements = injectedStatements.Concat(getCodeForSettingEventHandlers(controlInfo, "Click"));
+ injectedStatements = injectedStatements.Concat(getCodeForSettingEventHandlers(controlInfo, "Checked"));
+ injectedStatements = injectedStatements.Concat(getCodeForSettingEventHandlers(controlInfo, "Unchecked"));
+ }
+
+ int stmtPos= block.Statements.IndexOf(statementAfter);
+ block.Statements.InsertRange(stmtPos+1, injectedStatements);
+ }
+
+ private BoundExpression makeBoundControlFromControlInfo(ControlInfoStructure controlInfo) {
+ return new BoundExpression() {
+ Definition = new FieldDefinition() {
+ ContainingTypeDefinition = methodBeingTraversed.Container,
+ Name = host.NameTable.GetNameFor(controlInfo.Name),
+ Type = getTypeForClassname(controlInfo.ClassName),
+ IsStatic = false,
+ },
+ Instance = new ThisReference() { Type = methodBeingTraversed.Container },
+ };
+ }
+
+ private IEnumerable<IStatement> getCodeForSettingVisibility(ControlInfoStructure controlInfo) {
+ // TODO I do not want to import System.Windows into this project...and using the underlying uint won't work
+ /*
+ IList<IStatement> code = new List<IStatement>();
+ BoundExpression boundControl = makeBoundControlFromControlInfo(controlInfo);
+ MethodCall setVisibilityCall= new MethodCall() {
+ IsStaticCall = false,
+ IsVirtualCall = true,
+ IsTailCall = false,
+ Type = ((Microsoft.Cci.Immutable.PlatformType) host.PlatformType).SystemVoid,
+ MethodToCall = visibilitySetter,
+ ThisArgument = boundControl,
+ };
+
+ ITypeReference visibilityType= ((Microsoft.Cci.Immutable.PlatformType) host.PlatformType).CreateReference(phoneSystemWindowsAssembly, "System", "Windows", "Visibility");
+
+ switch (controlInfo.Visible) {
+ case Visibility.Visible:
+ setVisibilityCall.Arguments.Add(new CompileTimeConstant() {
+ Type = visibilityType,
+ Value = 0,
+ } ); // Visible
+ break;
+ case Visibility.Collapsed:
+ setVisibilityCall.Arguments.Add(new CompileTimeConstant() {
+ Type = visibilityType,
+ Value = 1,
+ } ); // Collapsed
+ break;
+ default:
+ throw new ArgumentException("Invalid visibility value for control " + controlInfo.Name + ": " + controlInfo.Visible);
+ }
+
+ ExpressionStatement callStmt = new ExpressionStatement() {
+ Expression = setVisibilityCall,
+ };
+ code.Add(callStmt);
+ return code;
+ * */
+ return new List<IStatement>();
+ }
+
+ private IEnumerable<IStatement> getCodeForSettingEnabledness(ControlInfoStructure controlInfo) {
+ IList<IStatement> code = new List<IStatement>();
+ BoundExpression boundControl = makeBoundControlFromControlInfo(controlInfo);
+ MethodCall setEnablednessCall = new MethodCall() {
+ IsStaticCall = false,
+ IsVirtualCall = true,
+ IsTailCall = false,
+ Type = ((Microsoft.Cci.Immutable.PlatformType) host.PlatformType).SystemVoid,
+ MethodToCall = isEnabledSetter,
+ ThisArgument = boundControl,
+ };
+
+ setEnablednessCall.Arguments.Add(controlInfo.IsEnabled ? trueConstant : falseConstant);
+ ExpressionStatement callStmt = new ExpressionStatement() {
+ Expression = setEnablednessCall,
+ };
+ code.Add(callStmt);
+ return code;
+ }
+
+ private IEnumerable<IStatement> getCodeForSettingCheckedState(ControlInfoStructure controlInfo) {
+ // TODO not implemented yet
+ return new List<IStatement>();
+ }
+
+ private IEnumerable<IStatement> getCodeForSettingEventHandlers(ControlInfoStructure controlInfo, string eventName) {
+ // TODO not implemented yet
+ return new List<IStatement>();
}
public override void Visit(IBlockStatement block) {
- initializationEncountered = false;
foreach (IStatement statement in block.Statements) {
this.Visit(statement);
- if (initializationEncountered) {
- injectPhoneInitializationCode(block, statement);
+ if (initializationFound) {
+ injectPhoneInitializationCode(block as BlockStatement, statement as Statement);
+ initializationFound = false;
break;
}
}
@@ -57,8 +264,7 @@ namespace BytecodeTranslator { 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
+ initializationFound= true;
}
}
@@ -66,9 +272,13 @@ namespace BytecodeTranslator { /// Traverse metadata looking only for PhoneApplicationPage's constructors
/// </summary>
public class PhoneMetadataTraverser : BaseMetadataTraverser {
+ private PhoneControlsPlugin phoneControlsInfo;
+ private MetadataReaderHost host;
- public PhoneMetadataTraverser()
+ public PhoneMetadataTraverser(PhoneControlsPlugin phonePlugin, MetadataReaderHost host)
: base() {
+ this.phoneControlsInfo = phonePlugin;
+ this.host = host;
}
public override void Visit(IModule module) {
@@ -113,8 +323,8 @@ namespace BytecodeTranslator { if (!method.IsConstructor)
return;
- PhoneCodeTraverser codeTraverser = new PhoneCodeTraverser(method);
- var methodBody = method.Body as ISourceMethodBody;
+ PhoneCodeTraverser codeTraverser = new PhoneCodeTraverser(host, method, phoneControlsInfo);
+ var methodBody = method.Body as SourceMethodBody;
if (methodBody == null)
return;
var block = methodBody.Block as BlockStatement;
diff --git a/BCT/BytecodeTranslator/Program.cs b/BCT/BytecodeTranslator/Program.cs index 7ce0c37a..28149cbd 100644 --- a/BCT/BytecodeTranslator/Program.cs +++ b/BCT/BytecodeTranslator/Program.cs @@ -17,6 +17,7 @@ using Microsoft.Cci.MutableContracts; using Bpl = Microsoft.Boogie;
using System.Diagnostics.Contracts;
using Microsoft.Cci.MutableCodeModel.Contracts;
+using TranslationPlugins;
namespace BytecodeTranslator {
@@ -175,7 +176,7 @@ namespace BytecodeTranslator { var primaryModule = modules[0];
if (phoneControlsConfigFile != null && phoneControlsConfigFile != "") {
- PhoneMetadataTraverser tr = new PhoneMetadataTraverser();
+ PhoneMetadataTraverser tr = new PhoneMetadataTraverser(new PhoneControlsPlugin(phoneControlsConfigFile), host);
tr.InjectPhoneCodeAssemblies(modules);
}
@@ -187,7 +188,6 @@ namespace BytecodeTranslator { Sink sink= new Sink(host, traverserFactory, heapFactory);
TranslationHelper.tmpVarCounter = 0;
-
MetadataTraverser translator = traverserFactory.MakeMetadataTraverser(sink, contractExtractors, pdbReaders);
translator.TranslateAssemblies(modules);
diff --git a/BCT/TranslationPlugins/PhoneControlsPlugin.cs b/BCT/TranslationPlugins/PhoneControlsPlugin.cs index 9ed1c7df..ac017d38 100644 --- a/BCT/TranslationPlugins/PhoneControlsPlugin.cs +++ b/BCT/TranslationPlugins/PhoneControlsPlugin.cs @@ -26,7 +26,7 @@ namespace TranslationPlugins { public string[] ParameterTypes;
}
- class ControlInfoStructure {
+ public class ControlInfoStructure {
public string Name;
public string ClassName;
public bool IsEnabled;
@@ -80,6 +80,10 @@ namespace TranslationPlugins { public void setControlInfo(string controlName, ControlInfoStructure controlInfo) {
controlsInfo[controlName] = controlInfo;
}
+
+ public IEnumerable<ControlInfoStructure> getAllControlsInfo() {
+ return controlsInfo.Values.AsEnumerable();
+ }
}
public class PhoneControlsPlugin : TranslationPlugin {
@@ -186,7 +190,8 @@ namespace TranslationPlugins { }
}
- public void getControlsForPage(string pageClass) {
+ public IEnumerable<ControlInfoStructure> getControlsForPage(string pageClass) {
+ return pageStructureInfo[pageClass].getAllControlsInfo();
}
public string getXAMLForPage(string pageClass) {
|