// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision: 1965 $</version>
// </file>
using System;
using System.CodeDom;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using ICSharpCode.NRefactory.Ast;
namespace ICSharpCode.NRefactory.Visitors
{
public class CodeDomVisitor : AbstractAstVisitor
{
Stack<CodeNamespace> namespaceDeclarations = new Stack<CodeNamespace>();
Stack<CodeTypeDeclaration> typeDeclarations = new Stack<CodeTypeDeclaration>();
Stack<CodeStatementCollection> codeStack = new Stack<CodeStatementCollection>();
List<CodeVariableDeclarationStatement> variables = new List<CodeVariableDeclarationStatement>();
List<CodeParameterDeclarationExpression> parameters = new List<CodeParameterDeclarationExpression>();
Stack<Breakable> breakableStack = new Stack<Breakable>();
TypeDeclaration currentTypeDeclaration = null;
IEnvironmentInformationProvider environmentInformationProvider = new DummyEnvironmentInformationProvider();
// track break and continue statements
class Breakable
{
public static int NextId = 0;
public int Id = 0;
public bool IsBreak = false;
public bool IsContinue = false;
public bool AllowContinue = true;
public Breakable()
{
Id = ++NextId;
}
public Breakable(bool allowContinue)
: this()
{
AllowContinue = allowContinue;
}
}
public IEnvironmentInformationProvider EnvironmentInformationProvider {
get {
return environmentInformationProvider;
}
set {
environmentInformationProvider = value;
}
}
// dummy collection used to swallow statements
CodeStatementCollection NullStmtCollection = new CodeStatementCollection();
public CodeCompileUnit codeCompileUnit = new CodeCompileUnit();
// RG
//
// Initialise Scope Variables for Current Method
void InitMethodScope()
{
usingId = 0;
foreachId = 0;
switchId = 0;
doId = 0;
Breakable.NextId = 0;
variables.Clear();
parameters.Clear();
}
CodeTypeReference ConvType(TypeReference type)
{
if (type == null) {
throw new ArgumentNullException("type");
}
if (string.IsNullOrEmpty(type.SystemType)) {
throw new InvalidOperationException("empty type");
}
CodeTypeReference t = new CodeTypeReference(type.SystemType);
foreach (TypeReference gt in type.GenericTypes) {
t.TypeArguments.Add(ConvType(gt));
}
if (type.IsArrayType) {
t = new CodeTypeReference(t, type.RankSpecifier.Length);
}
return t;
}
void AddStmt(CodeStatement stmt)
{
if (codeStack.Count == 0)
return;
CodeStatementCollection stmtCollection = codeStack.Peek();
if (stmtCollection != null) {
stmtCollection.Add(stmt);
}
}
// FIXME: map all modifiers correctly
static MemberAttributes ConvMemberAttributes(Modifiers modifier)
{
MemberAttributes attr = (MemberAttributes)0;
if ((modifier & Modifiers.Abstract) != 0)
attr |= MemberAttributes.Abstract;
if ((modifier & Modifiers.Const) != 0)
attr |= MemberAttributes.Const;
if ((modifier & Modifiers.Sealed) != 0)
attr |= MemberAttributes.Final;
if ((modifier & Modifiers.New) != 0)
attr |= MemberAttributes.New;
if ((modifier & Modifiers.Virtual) != 0)
attr |= MemberAttributes.Overloaded;
if ((modifier & Modifiers.Override) != 0)
attr |= MemberAttributes.Override;
if ((modifier & Modifiers.Static) != 0)
attr |= MemberAttributes.Static;
if ((modifier & Modifiers.Public) != 0)
attr |= MemberAttributes.Public;
else if ((modifier & Modifiers.Internal) != 0 && (modifier & Modifiers.Protected) != 0)
attr |= MemberAttributes.FamilyOrAssembly;
else if ((modifier & Modifiers.Internal) != 0)
attr |= MemberAttributes.Assembly;
else if ((modifier & Modifiers.Protected) != 0)
attr |= MemberAttributes.Family;
else if ((modifier & Modifiers.Private) != 0)
attr |= MemberAttributes.Private;
return attr;
}
#region ICSharpCode.SharpRefactory.Parser.IASTVisitor interface implementation
public override object VisitCompilationUnit(CompilationUnit compilationUnit, object data)
{
if (compilationUnit == null) {
throw new ArgumentNullException("compilationUnit");
}
CodeNamespace globalNamespace = new CodeNamespace("Global");
//namespaces.Add(globalNamespace);
namespaceDeclarations.Push(globalNamespace);
compilationUnit.AcceptChildren(this, data);
codeCompileUnit.Namespaces.Add(globalNamespace);
return globalNamespace;
}
public override object VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration, object data)
{
CodeNamespace currentNamespace = new CodeNamespace(namespaceDeclaration.Name);
//namespaces.Add(currentNamespace);
// add imports from mother namespace
foreach (CodeNamespaceImport import in ((CodeNamespace)namespaceDeclarations.Peek()).Imports) {
currentNamespace.Imports.Add(import);
}
namespaceDeclarations.Push(currentNamespace);
namespaceDeclaration.AcceptChildren(this, data);
namespaceDeclarations.Pop();
codeCompileUnit.Namespaces.Add(currentNamespace);
// TODO : Nested namespaces allowed in CodeDOM ? Doesn't seem so :(
return null;
}
public override object VisitUsingDeclaration(UsingDeclaration usingDeclaration, object data)
{
foreach (Using u in usingDeclaration.Usings) {
namespaceDeclarations.Peek().Imports.Add(new CodeNamespaceImport(u.Name));
}
return null;
}
// RG
public override object VisitEventDeclaration(EventDeclaration eventDeclaration, object data)
{
CodeMemberEvent evt = new CodeMemberEvent();
evt.Type = ConvType(eventDeclaration.TypeReference);
evt.Name = eventDeclaration.Name;
evt.Attributes = ConvMemberAttributes(eventDeclaration.Modifier);
typeDeclarations.Peek().Members.Add(evt);
return null;
}
public override object VisitAttributeSection(AttributeSection attributeSection, object data)
{
return null;
}
// RG: CodeTypeReferenceExpression
public override object VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression, object data)
{
return new CodeTypeReferenceExpression(ConvType(typeReferenceExpression.TypeReference));
}
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
{
TypeDeclaration oldTypeDeclaration = currentTypeDeclaration;
this.currentTypeDeclaration = typeDeclaration;
CodeTypeDeclaration codeTypeDeclaration = new CodeTypeDeclaration(typeDeclaration.Name);
codeTypeDeclaration.IsClass = typeDeclaration.Type == ClassType.Class;
codeTypeDeclaration.IsEnum = typeDeclaration.Type == ClassType.Enum;
codeTypeDeclaration.IsInterface = typeDeclaration.Type == ClassType.Interface;
codeTypeDeclaration.IsStruct = typeDeclaration.Type == ClassType.Struct;
if (typeDeclaration.BaseTypes != null) {
foreach (TypeReference typeRef in typeDeclaration.BaseTypes) {
codeTypeDeclaration.BaseTypes.Add(ConvType(typeRef));
}
}
typeDeclarations.Push(codeTypeDeclaration);
typeDeclaration.AcceptChildren(this, data);
typeDeclarations.Pop();
if (typeDeclarations.Count > 0) {
typeDeclarations.Peek().Members.Add(codeTypeDeclaration);
} else {
namespaceDeclarations.Peek().Types.Add(codeTypeDeclaration);
}
currentTypeDeclaration = oldTypeDeclaration;
return null;
}
public override object VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration, object data)
{
CodeTypeDelegate codeTypeDelegate = new CodeTypeDelegate(delegateDeclaration.Name);
codeTypeDelegate.Attributes = ConvMemberAttributes(delegateDeclaration.Modifier);
codeTypeDelegate.ReturnType = ConvType(delegateDeclaration.ReturnType);
foreach (ParameterDeclarationExpression parameter in delegateDeclaration.Parameters)
{
codeTypeDelegate.Parameters.Add((CodeParameterDeclarationExpression)VisitParameterDeclarationExpression(parameter, data));
}
if (typeDeclarations.Count > 0)
{
typeDeclarations.Peek().Members.Add(codeTypeDelegate);
}
else
{
namespaceDeclarations.Peek().Types.Add(codeTypeDelegate);
}
return null;
}
public override object VisitVariableDeclaration(VariableDeclaration variableDeclaration, object data)
{
return null;
}
public override object VisitFieldDeclaration(FieldDeclaration fieldDeclaration, object data)
{
for (int i = 0; i < fieldDeclaration.Fields.Count; ++i) {
VariableDeclaration field = (VariableDeclaration)fieldDeclaration.Fields[i];
if ((fieldDeclaration.Modifier & Modifiers.WithEvents) != 0) {
//this.withEventsFields.Add(field);
}
TypeReference fieldType = fieldDeclaration.GetTypeForField(i);
if (fieldType.IsNull) {
fieldType = new TypeReference(typeDeclarations.Peek().Name);
}
CodeMemberField memberField = new CodeMemberField(ConvType(fieldType), field.Name);
memberField.Attributes = ConvMemberAttributes(fieldDeclaration.Modifier);
if (!field.Initializer.IsNull) {
memberField.InitExpression = (CodeExpression)field.Initializer.AcceptVisitor(this, data);
}
typeDeclarations.Peek().Members.Add(memberField);
}
return null;
}
public override object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data)
{
InitMethodScope();
CodeMemberMethod memberMethod = new CodeMemberMethod();
memberMethod.Name = methodDeclaration.Name;
memberMethod.Attributes = ConvMemberAttributes(methodDeclaration.Modifier);
// RG: Private Interface Decl
if ((memberMethod.Attributes & MemberAttributes.Public) != MemberAttributes.Public &&
methodDeclaration.InterfaceImplementations.Count > 0)
{
memberMethod.PrivateImplementationType = ConvType(methodDeclaration.InterfaceImplementations[0].InterfaceType);
}
codeStack.Push(memberMethod.Statements);
typeDeclarations.Peek().Members.Add(memberMethod);
// Add Method Parameters
parameters.Clear();
foreach (ParameterDeclarationExpression parameter in methodDeclaration.Parameters)
{
memberMethod.Parameters.Add((CodeParameterDeclarationExpression)VisitParameterDeclarationExpression(parameter, data));
}
usingId = 0; // RG
foreachId = 0;
switchId = 0;
doId = 0;
Breakable.NextId = 0;
variables.Clear();
methodDeclaration.Body.AcceptChildren(this, data);
codeStack.Pop();
return null;
}
// RG
public override object VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration, object data)
{
CodeMemberProperty memberProperty = new CodeMemberProperty();
memberProperty.Name = propertyDeclaration.Name;
memberProperty.Attributes = ConvMemberAttributes(propertyDeclaration.Modifier);
memberProperty.HasGet = propertyDeclaration.HasGetRegion;
memberProperty.HasSet = propertyDeclaration.HasSetRegion;
memberProperty.Type = ConvType(propertyDeclaration.TypeReference);
typeDeclarations.Peek().Members.Add(memberProperty);
// Add Method Parameters
foreach (ParameterDeclarationExpression parameter in propertyDeclaration.Parameters)
{
memberProperty.Parameters.Add((CodeParameterDeclarationExpression)VisitParameterDeclarationExpression(parameter, data));
}
if (memberProperty.HasGet)
{
codeStack.Push(memberProperty.GetStatements);
propertyDeclaration.GetRegion.Block.AcceptChildren(this, data);
codeStack.Pop();
}
if (memberProperty.HasSet)
{
codeStack.Push(memberProperty.SetStatements);
propertyDeclaration.SetRegion.Block.AcceptChildren(this, data);
codeStack.Pop();
}
return null;
}
public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data)
{
InitMethodScope();
CodeConstructor memberMethod = new CodeConstructor();
memberMethod.Attributes = ConvMemberAttributes(constructorDeclaration.Modifier);
typeDeclarations.Peek().Members.Add(memberMethod);
codeStack.Push(NullStmtCollection);
foreach (ParameterDeclarationExpression parameter in constructorDeclaration.Parameters)
{
memberMethod.Parameters.Add((CodeParameterDeclarationExpression)VisitParameterDeclarationExpression(parameter, data));
}
if (constructorDeclaration.ConstructorInitializer != null)
{
if (constructorDeclaration.ConstructorInitializer.ConstructorInitializerType == ConstructorInitializerType.Base)
{
if (constructorDeclaration.ConstructorInitializer.Arguments.Count == 0)
{
memberMethod.BaseConstructorArgs.Add(new CodeSnippetExpression());
}
foreach (Expression o in constructorDeclaration.ConstructorInitializer.Arguments)
{
memberMethod.BaseConstructorArgs.Add((CodeExpression)o.AcceptVisitor(this, data));
}
}
if (constructorDeclaration.ConstructorInitializer.ConstructorInitializerType == ConstructorInitializerType.This)
{
if (constructorDeclaration.ConstructorInitializer.Arguments.Count == 0)
{
memberMethod.ChainedConstructorArgs.Add(new CodeSnippetExpression());
}
foreach (Expression o in constructorDeclaration.ConstructorInitializer.Arguments)
{
memberMethod.ChainedConstructorArgs.Add((CodeExpression)o.AcceptVisitor(this, data));
}
}
}
codeStack.Pop();
codeStack.Push(memberMethod.Statements);
constructorDeclaration.Body.AcceptChildren(this, data);
codeStack.Pop();
return null;
}
public override object VisitBlockStatement(BlockStatement blockStatement, object data)
{
blockStatement.AcceptChildren(this, data);
return null;
}
public override object VisitExpressionStatement(ExpressionStatement expressionStatement, object data)
{
object exp = expressionStatement.Expression.AcceptVisitor(this, data);
if (exp is CodeExpression) {
AddStmt(new CodeExpressionStatement((CodeExpression)exp));
}
return exp;
}
public override object VisitLocalVariableDeclaration(LocalVariableDeclaration localVariableDeclaration, object data)
{
CodeVariableDeclarationStatement declStmt = null;
for (int i = 0; i < localVariableDeclaration.Variables.Count; ++i) {
CodeTypeReference type = ConvType(localVariableDeclaration.GetTypeForVariable(i) ?? new TypeReference("object"));
VariableDeclaration var = (VariableDeclaration)localVariableDeclaration.Variables[i];
if (!var.Initializer.IsNull) {
declStmt = new CodeVariableDeclarationStatement(type,
var.Name,
(CodeExpression)((INode)var.Initializer).AcceptVisitor(this, data));
} else {
declStmt = new CodeVariableDeclarationStatement(type,
var.Name);
}
variables.Add(declStmt);
AddStmt(declStmt);
}
return declStmt;
}
public override object VisitEmptyStatement(EmptyStatement emptyStatement, object data)
{
CodeSnippetStatement emptyStmt = new CodeSnippetStatement();
AddStmt(emptyStmt);
return emptyStmt;
}
public override object VisitReturnStatement(ReturnStatement returnStatement, object data)
{
CodeMethodReturnStatement returnStmt;
if (returnStatement.Expression.IsNull)
returnStmt = new CodeMethodReturnStatement();
else
returnStmt = new CodeMethodReturnStatement((CodeExpression)returnStatement.Expression.AcceptVisitor(this,data));
AddStmt(returnStmt);
return returnStmt;
}
public override object VisitIfElseStatement(IfElseStatement ifElseStatement, object data)
{
CodeConditionStatement ifStmt = new CodeConditionStatement();
ifStmt.Condition = (CodeExpression)ifElseStatement.Condition.AcceptVisitor(this, data);
codeStack.Push(ifStmt.TrueStatements);
foreach (Statement stmt in ifElseStatement.TrueStatement) {
if (stmt is BlockStatement) {
stmt.AcceptChildren(this, data);
} else {
stmt.AcceptVisitor(this, data);
}
}
codeStack.Pop();
codeStack.Push(ifStmt.FalseStatements);
foreach (Statement stmt in ifElseStatement.FalseStatement) {
if (stmt is BlockStatement) {
stmt.AcceptChildren(this, data);
} else {
stmt.AcceptVisitor(this, data);
}
}
codeStack.Pop();
AddStmt(ifStmt);
return ifStmt;
}
int foreachId = 0; // in case of nested foreach statments
public override object VisitForeachStatement(ForeachStatement foreachStatement, object data)
{
// RG:
// foreach (T t in x)
// {
// stmts;
// }
//
// Emulate with
//
// for (System.Collections.IEnumerator _it = x.GetEnumerator(); _it.MoveNext(); )
// {
// T t = ((T)_it.Current);
//
// stmts;
// }
foreachId++;
string name = "_it" + foreachId.ToString();
CodeIterationStatement _for1 = new CodeIterationStatement();
breakableStack.Push(new Breakable());
// init
CodeVariableDeclarationStatement _decl2 = new CodeVariableDeclarationStatement();
CodeMethodInvokeExpression _invoke1 = new CodeMethodInvokeExpression();
CodeMethodReferenceExpression _GetEnumerator_method1 = new CodeMethodReferenceExpression();
_GetEnumerator_method1.MethodName = "GetEnumerator";
//CodeCastExpression _cast1 = new CodeCastExpression();
//codeStack.Push(NullStmtCollection);
//_cast1.Expression = (CodeExpression)foreachStatement.Expression.AcceptVisitor(this, data);
//codeStack.Pop();
//CodeTypeReference _IEnumerable_type1 = new CodeTypeReference("System.Collections.IEnumerable");
//_cast1.TargetType = _IEnumerable_type1;
//_GetEnumerator_method1.TargetObject = _cast1;
codeStack.Push(NullStmtCollection);
_GetEnumerator_method1.TargetObject = (CodeExpression)foreachStatement.Expression.AcceptVisitor(this, data);
codeStack.Pop();
_invoke1.Method = _GetEnumerator_method1;
_decl2.InitExpression = _invoke1;
_decl2.Name = name;
CodeTypeReference _IEnumerator_type1 = new CodeTypeReference("System.Collections.IEnumerator");
_decl2.Type = _IEnumerator_type1;
_for1.InitStatement = _decl2;
// Condition
CodeMethodInvokeExpression _invoke2 = new CodeMethodInvokeExpression();
CodeMethodReferenceExpression _MoveNext_method1 = new CodeMethodReferenceExpression();
_MoveNext_method1.MethodName = "MoveNext";
CodeVariableReferenceExpression _arg2 = new CodeVariableReferenceExpression();
_arg2.VariableName = name;
_MoveNext_method1.TargetObject = _arg2;
_invoke2.Method = _MoveNext_method1;
_for1.TestExpression = _invoke2;
// Empty Increment
_for1.IncrementStatement = new CodeExpressionStatement(new CodeSnippetExpression());
// T t = ((T)_it.Current);
CodeVariableDeclarationStatement _decl3 = new CodeVariableDeclarationStatement();
CodeCastExpression _cast2 = new CodeCastExpression();
CodePropertyReferenceExpression _prop1 = new CodePropertyReferenceExpression();
_prop1.PropertyName = "Current";
CodeVariableReferenceExpression _arg3 = new CodeVariableReferenceExpression();
_arg3.VariableName = name;
_prop1.TargetObject = _arg3;
_cast2.Expression = _prop1;
CodeTypeReference _System_String_type5 = ConvType(foreachStatement.TypeReference);
_cast2.TargetType = _System_String_type5;
_decl3.InitExpression = _cast2;
_decl3.Name = foreachStatement.VariableName;
CodeTypeReference _System_String_type6 = ConvType(foreachStatement.TypeReference);
_decl3.Type = _System_String_type6;
_for1.Statements.Add(_decl3);
_for1.Statements.Add(new CodeSnippetStatement());
codeStack.Push(_for1.Statements);
foreachStatement.EmbeddedStatement.AcceptVisitor(this, data);
codeStack.Pop();
Breakable breakable = breakableStack.Pop();
if (breakable.IsContinue)
{
_for1.Statements.Add(new CodeSnippetStatement());
_for1.Statements.Add(new CodeLabeledStatement("continue" + breakable.Id, new CodeExpressionStatement(new CodeSnippetExpression())));
}
AddStmt(_for1);
if (breakable.IsBreak)
{
AddStmt(new CodeLabeledStatement("break" + breakable.Id, new CodeExpressionStatement(new CodeSnippetExpression())));
}
return _for1;
}
int doId = 0;
// RG:
public override object VisitDoLoopStatement(DoLoopStatement doLoopStatement, object data)
{
CodeIterationStatement forLoop = new CodeIterationStatement();
breakableStack.Push(new Breakable());
codeStack.Push(NullStmtCollection);
if (doLoopStatement.ConditionPosition == ConditionPosition.End)
{
// do { } while (expr);
//
// emulate with:
// for (bool _do = true; _do; _do = expr) {}
//
doId++;
string name = "_do" + doId;
forLoop.InitStatement = new CodeVariableDeclarationStatement(typeof(System.Boolean), name, new CodePrimitiveExpression(true));
forLoop.TestExpression = new CodeVariableReferenceExpression(name);
forLoop.IncrementStatement = new CodeAssignStatement(new CodeVariableReferenceExpression(name),
doLoopStatement.Condition == null ? new CodePrimitiveExpression(true) : (CodeExpression)doLoopStatement.Condition.AcceptVisitor(this, data));
}
else
{
// while (expr) {}
//
// emulate with:
// for (; expr;) {}
//
// Empty Init and Increment Statements
forLoop.InitStatement = new CodeExpressionStatement(new CodeSnippetExpression());
forLoop.IncrementStatement = new CodeExpressionStatement(new CodeSnippetExpression());
if (doLoopStatement.Condition == null)
{
forLoop.TestExpression = new CodePrimitiveExpression(true);
}
else
{
forLoop.TestExpression = (CodeExpression)doLoopStatement.Condition.AcceptVisitor(this, data);
}
}
codeStack.Pop();
codeStack.Push(forLoop.Statements);
doLoopStatement.EmbeddedStatement.AcceptVisitor(this, data);
codeStack.Pop();
if (forLoop.Statements.Count == 0)
{
forLoop.Statements.Add(new CodeSnippetStatement());
}
Breakable breakable = breakableStack.Pop();
if (breakable.IsContinue)
{
forLoop.Statements.Add(new CodeSnippetStatement());
forLoop.Statements.Add(new CodeLabeledStatement("continue" + breakable.Id, new CodeExpressionStatement(new CodeSnippetExpression())));
}
AddStmt(forLoop);
if (breakable.IsBreak)
{
AddStmt(new CodeLabeledStatement("break" + breakable.Id, new CodeExpressionStatement(new CodeSnippetExpression())));
}
return forLoop;
}
public override object VisitForStatement(ForStatement forStatement, object data)
{
CodeIterationStatement forLoop = new CodeIterationStatement();
breakableStack.Push(new Breakable());
codeStack.Push(NullStmtCollection);
if (forStatement.Initializers.Count > 0)
{
if (forStatement.Initializers.Count > 1)
{
throw new NotSupportedException("CodeDom does not support Multiple For-Loop Initializer Statements");
}
foreach (object o in forStatement.Initializers)
{
if (o is Expression)
{
forLoop.InitStatement = new CodeExpressionStatement((CodeExpression)((Expression)o).AcceptVisitor(this, data));
}
if (o is Statement)
{
forLoop.InitStatement = (CodeStatement)((Statement)o).AcceptVisitor(this, data);
}
}
}
else
{
// RG: need to handle empty InitStatement
forLoop.InitStatement = new CodeExpressionStatement(new CodeSnippetExpression());
}
if (forStatement.Condition == null) {
forLoop.TestExpression = new CodePrimitiveExpression(true);
} else {
forLoop.TestExpression = (CodeExpression)forStatement.Condition.AcceptVisitor(this, data);
}
codeStack.Push(forLoop.Statements);
forStatement.EmbeddedStatement.AcceptVisitor(this, data);
codeStack.Pop();
if (forStatement.Iterator.Count > 0)
{
if (forStatement.Initializers.Count > 1)
{
throw new NotSupportedException("CodeDom does not support Multiple For-Loop Iterator Statements");
}
foreach (Statement stmt in forStatement.Iterator)
{
forLoop.IncrementStatement = (CodeStatement)stmt.AcceptVisitor(this, data);
}
}
else
{
// RG: need to handle empty IncrementStatement
forLoop.IncrementStatement = new CodeExpressionStatement(new CodeSnippetExpression());
}
codeStack.Pop();
Breakable breakable = breakableStack.Pop();
if (breakable.IsContinue)
{
forLoop.Statements.Add(new CodeSnippetStatement());
forLoop.Statements.Add(new CodeLabeledStatement("continue" + breakable.Id, new CodeExpressionStatement(new CodeSnippetExpression())));
}
AddStmt(forLoop);
if (breakable.IsBreak)
{
AddStmt(new CodeLabeledStatement("break" + breakable.Id, new CodeExpressionStatement(new CodeSnippetExpression())));
}
return forLoop;
}
public override object VisitLabelStatement(LabelStatement labelStatement, object data)
{
System.CodeDom.CodeLabeledStatement labelStmt = new CodeLabeledStatement(labelStatement.Label,(CodeStatement)labelStatement.AcceptVisitor(this, data));
// Add Statement to Current Statement Collection
AddStmt(labelStmt);
return labelStmt;
}
public override object VisitGotoStatement(GotoStatement gotoStatement, object data)
{
System.CodeDom.CodeGotoStatement gotoStmt = new CodeGotoStatement(gotoStatement.Label);
// Add Statement to Current Statement Collection
AddStmt(gotoStmt);
return gotoStmt;
}
// RG
int switchId = 0;
public override object VisitSwitchStatement(SwitchStatement switchStatement, object data)
{
// switch(arg) { case label1: expr1; case label2: expr2; default: expr3; }
//
// Emulate With:
//
// object _switch1 = arg;
// if (arg.Equals(label1))
// {
// expr1;
// }
// else
// {
// if (arg.Equals(label2))
// {
// expr2;
// }
// else
// {
// expr3;
// }
// }
//
switchId++; // in case nested switch() statements
string name = "_switch" + switchId.ToString();
breakableStack.Push(new Breakable(false));
bool isSwitchArg = false;
CodeVariableReferenceExpression switchArg = null;
SwitchSection defaultSection = null;
// get default section
foreach (SwitchSection section in switchStatement.SwitchSections)
{
foreach (CaseLabel label in section.SwitchLabels)
{
if (label.IsDefault)
{
defaultSection = section;
break;
}
}
if (defaultSection != null)
break;
}
CodeConditionStatement _if = null;
// get default section
foreach (SwitchSection section in switchStatement.SwitchSections)
{
if (section != defaultSection)
{
if (!isSwitchArg)
{
isSwitchArg = true;
codeStack.Push(NullStmtCollection);
CodeVariableDeclarationStatement switchStmt = new CodeVariableDeclarationStatement("System.Object", name, (CodeExpression)switchStatement.SwitchExpression.AcceptVisitor(this, data));
codeStack.Pop();
switchArg = new CodeVariableReferenceExpression(name);
AddStmt(switchStmt);
AddStmt(new CodeSnippetStatement());
}
codeStack.Push(NullStmtCollection);
CodeExpression condition = null;
foreach (CaseLabel label in section.SwitchLabels)
{
CodeMethodInvokeExpression cond = new CodeMethodInvokeExpression(switchArg, "Equals", (CodeExpression)label.Label.AcceptVisitor(this, data));
if (condition == null)
{
condition = cond;
}
else
{
condition = new CodeBinaryOperatorExpression(condition, CodeBinaryOperatorType.BooleanOr, cond);
}
}
codeStack.Pop();
if (_if == null)
{
_if = new CodeConditionStatement();
_if.Condition = condition;
AddStmt(_if);
}
else
{
CodeConditionStatement _if2 = new CodeConditionStatement();
_if2.Condition = condition;
_if.FalseStatements.Add(_if2);
_if = _if2;
}
codeStack.Push(_if.TrueStatements);
for (int i = 0; i < section.Children.Count; i++)
{
INode stmt = section.Children[i];
if (i == section.Children.Count - 1 && stmt is BreakStatement)
break;
stmt.AcceptVisitor(this, data);
}
codeStack.Pop();
}
}
if (defaultSection != null)
{
if (_if != null)
codeStack.Push(_if.FalseStatements);
for (int i = 0; i < defaultSection.Children.Count; i++)
{
INode stmt = defaultSection.Children[i];
if (i == defaultSection.Children.Count - 1 && stmt is BreakStatement)
break;
stmt.AcceptVisitor(this, data);
}
if (_if != null)
codeStack.Pop();
}
Breakable breakable = breakableStack.Pop();
if (breakable.IsContinue)
{
throw new Exception("Continue Inside Switch Not Supported");
}
if (breakable.IsBreak)
{
AddStmt(new CodeLabeledStatement("break" + breakable.Id, new CodeExpressionStatement(new CodeSnippetExpression())));
}
return null;
}
public override object VisitTryCatchStatement(TryCatchStatement tryCatchStatement, object data)
{
// add a try-catch-finally
CodeTryCatchFinallyStatement tryStmt = new CodeTryCatchFinallyStatement();
codeStack.Push(tryStmt.TryStatements);
tryCatchStatement.StatementBlock.AcceptChildren(this, data);
codeStack.Pop();
if (!tryCatchStatement.FinallyBlock.IsNull) {
codeStack.Push(tryStmt.FinallyStatements);
tryCatchStatement.FinallyBlock.AcceptChildren(this,data);
codeStack.Pop();
}
foreach (CatchClause clause in tryCatchStatement.CatchClauses)
{
CodeCatchClause catchClause = new CodeCatchClause(clause.VariableName);
catchClause.CatchExceptionType = ConvType(clause.TypeReference);
tryStmt.CatchClauses.Add(catchClause);
codeStack.Push(catchClause.Statements);
clause.StatementBlock.AcceptChildren(this, data);
codeStack.Pop();
}
// Add Statement to Current Statement Collection
AddStmt(tryStmt);
return tryStmt;
}
public override object VisitThrowStatement(ThrowStatement throwStatement, object data)
{
CodeThrowExceptionStatement throwStmt = new CodeThrowExceptionStatement((CodeExpression)throwStatement.Expression.AcceptVisitor(this, data));
// Add Statement to Current Statement Collection
AddStmt(throwStmt);
return throwStmt;
}
public override object VisitFixedStatement(FixedStatement fixedStatement, object data)
{
throw new NotSupportedException("CodeDom does not support Fixed Statement");
}
#region Expressions
public override object VisitPrimitiveExpression(PrimitiveExpression primitiveExpression, object data)
{
return new CodePrimitiveExpression(primitiveExpression.Value);
}
public override object VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data)
{
CodeBinaryOperatorType op = CodeBinaryOperatorType.Add;
switch (binaryOperatorExpression.Op) {
case BinaryOperatorType.Add:
op = CodeBinaryOperatorType.Add;
break;
case BinaryOperatorType.BitwiseAnd:
op = CodeBinaryOperatorType.BitwiseAnd;
break;
case BinaryOperatorType.BitwiseOr:
op = CodeBinaryOperatorType.BitwiseOr;
break;
case BinaryOperatorType.LogicalAnd:
op = CodeBinaryOperatorType.BooleanAnd;
break;
case BinaryOperatorType.LogicalOr:
op = CodeBinaryOperatorType.BooleanOr;
break;
case BinaryOperatorType.Divide:
case BinaryOperatorType.DivideInteger:
op = CodeBinaryOperatorType.Divide;
break;
case BinaryOperatorType.GreaterThan:
op = CodeBinaryOperatorType.GreaterThan;
break;
case BinaryOperatorType.GreaterThanOrEqual:
op = CodeBinaryOperatorType.GreaterThanOrEqual;
break;
case BinaryOperatorType.Equality:
op = CodeBinaryOperatorType.IdentityEquality;
break;
case BinaryOperatorType.InEquality:
op = CodeBinaryOperatorType.IdentityInequality;
break;
case BinaryOperatorType.LessThan:
op = CodeBinaryOperatorType.LessThan;
break;
case BinaryOperatorType.LessThanOrEqual:
op = CodeBinaryOperatorType.LessThanOrEqual;
break;
case BinaryOperatorType.Modulus:
op = CodeBinaryOperatorType.Modulus;
break;
case BinaryOperatorType.Multiply:
op = CodeBinaryOperatorType.Multiply;
break;
case BinaryOperatorType.Subtract:
op = CodeBinaryOperatorType.Subtract;
break;
//case BinaryOperatorType.ValueEquality:
// op = CodeBinaryOperatorType.ValueEquality;
// break;
case BinaryOperatorType.ShiftLeft:
case BinaryOperatorType.ShiftRight:
// CodeDOM suxx
op = CodeBinaryOperatorType.Multiply;
break;
case BinaryOperatorType.ReferenceEquality:
op = CodeBinaryOperatorType.IdentityEquality;
break;
case BinaryOperatorType.ReferenceInequality:
op = CodeBinaryOperatorType.IdentityInequality;
break;
case BinaryOperatorType.ExclusiveOr:
// TODO ExclusiveOr
op = CodeBinaryOperatorType.BitwiseAnd;
break;
}
System.Diagnostics.Debug.Assert(!binaryOperatorExpression.Left.IsNull);
System.Diagnostics.Debug.Assert(!binaryOperatorExpression.Right.IsNull);
return new CodeBinaryOperatorExpression((CodeExpression)binaryOperatorExpression.Left.AcceptVisitor(this, data),
op,
(CodeExpression)binaryOperatorExpression.Right.AcceptVisitor(this, data));
}
public override object VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, object data)
{
return parenthesizedExpression.Expression.AcceptVisitor(this, data);
}
public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data)
{
Expression target = invocationExpression.TargetObject;
CodeExpression targetExpr;
string methodName = null;
if (target == null) {
targetExpr = new CodeThisReferenceExpression();
} else if (target is FieldReferenceExpression) {
FieldReferenceExpression fRef = (FieldReferenceExpression)target;
targetExpr = null;
if (fRef.TargetObject is FieldReferenceExpression) {
if (IsPossibleTypeReference((FieldReferenceExpression)fRef.TargetObject)) {
targetExpr = ConvertToTypeReference((FieldReferenceExpression)fRef.TargetObject);
}
}
if (targetExpr == null)
targetExpr = (CodeExpression)fRef.TargetObject.AcceptVisitor(this, data);
methodName = fRef.FieldName;
// HACK for : Microsoft.VisualBasic.ChrW(NUMBER)
if (methodName == "ChrW") {
return new CodeCastExpression("System.Char", GetExpressionList(invocationExpression.Arguments)[0]);
}
} else if (target is IdentifierExpression) {
targetExpr = new CodeThisReferenceExpression();
methodName = ((IdentifierExpression)target).Identifier;
} else {
targetExpr = (CodeExpression)target.AcceptVisitor(this, data);
}
return new CodeMethodInvokeExpression(targetExpr, methodName, GetExpressionList(invocationExpression.Arguments));
}
public override object VisitIdentifierExpression(IdentifierExpression identifierExpression, object data)
{
if (!IsLocalVariable(identifierExpression.Identifier) && IsField(identifierExpression.Identifier)) {
return new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), identifierExpression.Identifier);
}
return new CodeVariableReferenceExpression(identifierExpression.Identifier);
}
public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data)
{
CodeExpression var;
CodeAssignStatement assign;
switch (unaryOperatorExpression.Op) {
case UnaryOperatorType.Minus:
if (unaryOperatorExpression.Expression is PrimitiveExpression) {
PrimitiveExpression expression = (PrimitiveExpression)unaryOperatorExpression.Expression;
if (expression.Value is int) {
return new CodePrimitiveExpression(- (int)expression.Value);
}
if (expression.Value is System.UInt32 || expression.Value is System.UInt16) {
return new CodePrimitiveExpression(Int32.Parse("-" + expression.StringValue));
}
if (expression.Value is long) {
return new CodePrimitiveExpression(- (long)expression.Value);
}
if (expression.Value is double) {
return new CodePrimitiveExpression(- (double)expression.Value);
}
if (expression.Value is float) {
return new CodePrimitiveExpression(- (float)expression.Value);
}
}
return new CodeBinaryOperatorExpression(new CodePrimitiveExpression(0),
CodeBinaryOperatorType.Subtract,
(CodeExpression)unaryOperatorExpression.Expression.AcceptVisitor(this, data));
case UnaryOperatorType.Plus:
return unaryOperatorExpression.Expression.AcceptVisitor(this, data);
case UnaryOperatorType.PostIncrement:
// emulate i++, with i = i + 1
var = (CodeExpression)unaryOperatorExpression.Expression.AcceptVisitor(this, data);
assign = new CodeAssignStatement(var,
new CodeBinaryOperatorExpression(var,
CodeBinaryOperatorType.Add,
new CodePrimitiveExpression(1)));
AddStmt(assign);
return assign;
//return new CodeAssignStatement(var,
// new CodeBinaryOperatorExpression(var,
// CodeBinaryOperatorType.Add,
// new CodePrimitiveExpression(1)));
// RG: needs to return an Expression - Not a Statement
//return new CodeBinaryOperatorExpression(var,
// CodeBinaryOperatorType.Assign,
// new CodeBinaryOperatorExpression(var,
// CodeBinaryOperatorType.Add,
// new CodePrimitiveExpression(1)));
case UnaryOperatorType.PostDecrement:
// emulate i--, with i = i - 1
var = (CodeExpression)unaryOperatorExpression.Expression.AcceptVisitor(this, data);
assign = new CodeAssignStatement(var,
new CodeBinaryOperatorExpression(var,
CodeBinaryOperatorType.Subtract,
new CodePrimitiveExpression(1)));
AddStmt(assign);
return assign;
//return new CodeAssignStatement(var,
// new CodeBinaryOperatorExpression(var,
// CodeBinaryOperatorType.Subtract,
// new CodePrimitiveExpression(1)));
// RG: needs to return an Expression - Not a Statement
//return new CodeBinaryOperatorExpression(var,
// CodeBinaryOperatorType.Assign,
// new CodeBinaryOperatorExpression(var,
// CodeBinaryOperatorType.Subtract,
// new CodePrimitiveExpression(1)));
case UnaryOperatorType.Decrement:
// emulate --i, with i = i - 1
var = (CodeExpression)unaryOperatorExpression.Expression.AcceptVisitor(this, data);
assign = new CodeAssignStatement(var,
new CodeBinaryOperatorExpression(var,
CodeBinaryOperatorType.Subtract,
new CodePrimitiveExpression(1)));
AddStmt(assign);
return assign;
//return new CodeAssignStatement(var,
// new CodeBinaryOperatorExpression(var,
// CodeBinaryOperatorType.Subtract,
// new CodePrimitiveExpression(1)));
//return new CodeBinaryOperatorExpression(var,
// CodeBinaryOperatorType.Assign,
// new CodeBinaryOperatorExpression(var,
// CodeBinaryOperatorType.Subtract,
// new CodePrimitiveExpression(1)));
case UnaryOperatorType.Increment:
// emulate ++i, with i = i + 1
var = (CodeExpression)unaryOperatorExpression.Expression.AcceptVisitor(this, data);
assign = new CodeAssignStatement(var,
new CodeBinaryOperatorExpression(var,
CodeBinaryOperatorType.Add,
new CodePrimitiveExpression(1)));
AddStmt(assign);
return assign;
//return new CodeAssignStatement(var,
// new CodeBinaryOperatorExpression(var,
// CodeBinaryOperatorType.Add,
// new CodePrimitiveExpression(1)));
//return new CodeBinaryOperatorExpression(var,
// CodeBinaryOperatorType.Assign,
// new CodeBinaryOperatorExpression(var,
// CodeBinaryOperatorType.Add,
// new CodePrimitiveExpression(1)));
// RG:
case UnaryOperatorType.Not:
// emulate !a with a == false
var = (CodeExpression)unaryOperatorExpression.Expression.AcceptVisitor(this, data);
return new CodeBinaryOperatorExpression(var,CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false));
default:
throw new NotSupportedException("CodeDom does not support Unary Operators");
}
}
bool methodReference = false;
void AddEventHandler(Expression eventExpr, Expression handler, object data)
{
methodReference = true;
CodeExpression methodInvoker = (CodeExpression)handler.AcceptVisitor(this, data);
methodReference = false;
if (!(methodInvoker is CodeObjectCreateExpression)) {
// we need to create an event handler here
methodInvoker = new CodeObjectCreateExpression(new CodeTypeReference("System.EventHandler"), methodInvoker);
}
if (eventExpr is IdentifierExpression) {
AddStmt(new CodeAttachEventStatement(new CodeEventReferenceExpression(new CodeThisReferenceExpression(), ((IdentifierExpression)eventExpr).Identifier),
methodInvoker));
} else {
FieldReferenceExpression fr = (FieldReferenceExpression)eventExpr;
AddStmt(new CodeAttachEventStatement(new CodeEventReferenceExpression((CodeExpression)fr.TargetObject.AcceptVisitor(this, data), fr.FieldName),
methodInvoker));
}
}
public override object VisitAssignmentExpression(AssignmentExpression assignmentExpression, object data)
{
if (assignmentExpression.Op == AssignmentOperatorType.Add) {
AddEventHandler(assignmentExpression.Left, assignmentExpression.Right, data);
} else {
if (assignmentExpression.Left is IdentifierExpression) {
AddStmt(new CodeAssignStatement((CodeExpression)assignmentExpression.Left.AcceptVisitor(this, null), (CodeExpression)assignmentExpression.Right.AcceptVisitor(this, null)));
} else {
AddStmt(new CodeAssignStatement((CodeExpression)assignmentExpression.Left.AcceptVisitor(this, null), (CodeExpression)assignmentExpression.Right.AcceptVisitor(this, null)));
}
}
return null;
}
public override object VisitAddHandlerStatement(AddHandlerStatement addHandlerStatement, object data)
{
AddEventHandler(addHandlerStatement.EventExpression, addHandlerStatement.HandlerExpression, data);
return null;
}
public override object VisitAddressOfExpression(AddressOfExpression addressOfExpression, object data)
{
return addressOfExpression.Expression.AcceptVisitor(this, data);
}
public override object VisitUsing(Using @using, object data)
{
return base.VisitUsing(@using, data);
}
// RG
int usingId = 0;
public override object VisitUsingStatement(UsingStatement usingStatement, object data)
{
// using (new expr) { stmts; }
//
// emulate with
// object _dispose;
// try
// {
// _dispose = new expr;
//
// stmts;
// }
// finally
// {
// if (((_dispose != null)
// && (typeof(System.IDisposable).IsInstanceOfType(_dispose) == true)))
// {
// ((System.IDisposable)(_dispose)).Dispose();
// }
// }
//
usingId++; // in case nested using() statements
string name = "_dispose" + usingId.ToString();
CodeVariableDeclarationStatement disposable = new CodeVariableDeclarationStatement("System.Object", name, new CodePrimitiveExpression(null));
AddStmt(disposable);
CodeTryCatchFinallyStatement tryStmt = new CodeTryCatchFinallyStatement();
CodeVariableReferenceExpression left1 = new CodeVariableReferenceExpression(name);
codeStack.Push(NullStmtCollection); // send statements to nul Statement collection
CodeExpression right1 = (CodeExpression)usingStatement.ResourceAcquisition.AcceptVisitor(this, data);
codeStack.Pop();
CodeAssignStatement assign1 = new CodeAssignStatement(left1, right1);
tryStmt.TryStatements.Add(assign1);
tryStmt.TryStatements.Add(new CodeSnippetStatement());
codeStack.Push(tryStmt.TryStatements);
usingStatement.EmbeddedStatement.AcceptChildren(this, data);
codeStack.Pop();
CodeMethodInvokeExpression isInstanceOfType = new CodeMethodInvokeExpression(new CodeTypeOfExpression(typeof(IDisposable)), "IsInstanceOfType", new CodeExpression[] { left1 });
CodeConditionStatement if1 = new CodeConditionStatement();
if1.Condition = new CodeBinaryOperatorExpression(new CodeBinaryOperatorExpression(left1, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression(null)),
CodeBinaryOperatorType.BooleanAnd,
new CodeBinaryOperatorExpression(isInstanceOfType, CodeBinaryOperatorType.IdentityEquality, new CodePrimitiveExpression(true)));
if1.TrueStatements.Add(new CodeMethodInvokeExpression(new CodeCastExpression(typeof(IDisposable),left1), "Dispose", new CodeExpression[] { }));
tryStmt.FinallyStatements.Add(if1);
// Add Statement to Current Statement Collection
AddStmt(tryStmt);
return null;
}
public override object VisitTypeOfExpression(TypeOfExpression typeOfExpression, object data)
{
return new CodeTypeOfExpression(ConvType(typeOfExpression.TypeReference));
}
public override object VisitCastExpression(CastExpression castExpression, object data)
{
CodeTypeReference typeRef = ConvType(castExpression.CastTo);
return new CodeCastExpression(typeRef, (CodeExpression)castExpression.Expression.AcceptVisitor(this, data));
}
public override object VisitIndexerExpression(IndexerExpression indexerExpression, object data)
{
return new CodeIndexerExpression((CodeExpression)indexerExpression.TargetObject.AcceptVisitor(this, data), GetExpressionList(indexerExpression.Indexes));
}
public override object VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression, object data)
{
return new CodeThisReferenceExpression();
}
public override object VisitBaseReferenceExpression(BaseReferenceExpression baseReferenceExpression, object data)
{
return new CodeBaseReferenceExpression();
}
public override object VisitArrayCreateExpression(ArrayCreateExpression arrayCreateExpression, object data)
{
if (arrayCreateExpression.ArrayInitializer == null) {
return new CodeArrayCreateExpression(ConvType(arrayCreateExpression.CreateType),
arrayCreateExpression.Arguments[0].AcceptVisitor(this, data) as CodeExpression);
}
return new CodeArrayCreateExpression(ConvType(arrayCreateExpression.CreateType),
GetExpressionList(arrayCreateExpression.ArrayInitializer.CreateExpressions));
}
public override object VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression, object data)
{
return new CodeObjectCreateExpression(ConvType(objectCreateExpression.CreateType),
objectCreateExpression.Parameters == null ? null : GetExpressionList(objectCreateExpression.Parameters));
}
public override object VisitParameterDeclarationExpression(ParameterDeclarationExpression parameterDeclarationExpression, object data)
{
CodeParameterDeclarationExpression parameter = new CodeParameterDeclarationExpression(ConvType(parameterDeclarationExpression.TypeReference), parameterDeclarationExpression.ParameterName);
parameters.Add(parameter);
return parameter;
}
public override object VisitBreakStatement(BreakStatement breakStatement, object data)
{
// RG:
// break;
//
// emulate with:
// goto break1;
//
Breakable breakable = breakableStack.Peek();
breakable.IsBreak = true;
CodeGotoStatement breakStmt = new CodeGotoStatement("break" + breakable.Id);
AddStmt(breakStmt);
return breakStmt;
}
public override object VisitContinueStatement(ContinueStatement continueStatement, object data)
{
// RG:
// continue;
//
// emulate with:
// goto continue1;
//
Breakable breakable = breakableStack.Peek();
// Is continuable?
if (!breakable.AllowContinue)
{
// walk stack to find first continuable item
Breakable[] stack = breakableStack.ToArray();
foreach (Breakable b in stack)
{
if (b.AllowContinue)
{
breakable = b;
break;
}
}
}
breakable.IsContinue = true;
CodeGotoStatement continueStmt = new CodeGotoStatement("continue" + breakable.Id);
AddStmt(continueStmt);
return continueStmt;
}
bool IsField(string type, string fieldName)
{
bool isField = environmentInformationProvider.HasField(type, fieldName);
if (!isField) {
int idx = type.LastIndexOf('.');
if (idx >= 0) {
type = type.Substring(0, idx) + "+" + type.Substring(idx + 1);
isField = IsField(type, fieldName);
}
}
return isField;
}
bool IsFieldReferenceExpression(FieldReferenceExpression fieldReferenceExpression)
{
if (fieldReferenceExpression.TargetObject is ThisReferenceExpression
|| fieldReferenceExpression.TargetObject is BaseReferenceExpression)
{
//field detection for fields\props inherited from base classes
return IsField(fieldReferenceExpression.FieldName);
}
return false;
}
public override object VisitFieldReferenceExpression(FieldReferenceExpression fieldReferenceExpression, object data)
{
if (methodReference) {
methodReference = false;
return new CodeMethodReferenceExpression((CodeExpression)fieldReferenceExpression.TargetObject.AcceptVisitor(this, data), fieldReferenceExpression.FieldName);
}
if (IsFieldReferenceExpression(fieldReferenceExpression)) {
return new CodeFieldReferenceExpression((CodeExpression)fieldReferenceExpression.TargetObject.AcceptVisitor(this, data),
fieldReferenceExpression.FieldName);
} else {
if (fieldReferenceExpression.TargetObject is FieldReferenceExpression) {
if (IsPossibleTypeReference((FieldReferenceExpression)fieldReferenceExpression.TargetObject)) {
CodeTypeReferenceExpression typeRef = ConvertToTypeReference((FieldReferenceExpression)fieldReferenceExpression.TargetObject);
if (IsField(typeRef.Type.BaseType, fieldReferenceExpression.FieldName)) {
return new CodeFieldReferenceExpression(typeRef,
fieldReferenceExpression.FieldName);
} else {
return new CodePropertyReferenceExpression(typeRef,
fieldReferenceExpression.FieldName);
}
}
}
CodeExpression codeExpression = (CodeExpression)fieldReferenceExpression.TargetObject.AcceptVisitor(this, data);
return new CodePropertyReferenceExpression(codeExpression,
fieldReferenceExpression.FieldName);
}
}
#endregion
#endregion
bool IsPossibleTypeReference(FieldReferenceExpression fieldReferenceExpression)
{
while (fieldReferenceExpression.TargetObject is FieldReferenceExpression) {
fieldReferenceExpression = (FieldReferenceExpression)fieldReferenceExpression.TargetObject;
}
IdentifierExpression identifier = fieldReferenceExpression.TargetObject as IdentifierExpression;
if (identifier != null)
return !IsField(identifier.Identifier) && !IsLocalVariable(identifier.Identifier);
TypeReferenceExpression tre = fieldReferenceExpression.TargetObject as TypeReferenceExpression;
if (tre != null)
return true;
return false;
}
bool IsLocalVariable(string identifier)
{
foreach (CodeVariableDeclarationStatement variable in variables) {
if (variable.Name == identifier)
return true;
}
foreach (CodeParameterDeclarationExpression parameter in parameters)
{
if (parameter.Name == identifier)
return true;
}
return false;
}
bool IsField(string identifier)
{
if (currentTypeDeclaration == null) // e.g. in unit tests
return false;
foreach (INode node in currentTypeDeclaration.Children) {
if (node is FieldDeclaration) {
FieldDeclaration fd = (FieldDeclaration)node;
if (fd.GetVariableDeclaration(identifier) != null) {
return true;
}
}
}
//field detection for fields\props inherited from base classes
if (currentTypeDeclaration.BaseTypes.Count > 0) {
return IsField(currentTypeDeclaration.BaseTypes[0].ToString(), identifier);
}
return false;
}
static CodeTypeReferenceExpression ConvertToTypeReference(FieldReferenceExpression fieldReferenceExpression)
{
StringBuilder type = new StringBuilder("");
while (fieldReferenceExpression.TargetObject is FieldReferenceExpression) {
type.Insert(0,'.');
type.Insert(1,fieldReferenceExpression.FieldName.ToCharArray());
fieldReferenceExpression = (FieldReferenceExpression)fieldReferenceExpression.TargetObject;
}
type.Insert(0,'.');
type.Insert(1,fieldReferenceExpression.FieldName.ToCharArray());
if (fieldReferenceExpression.TargetObject is IdentifierExpression) {
type.Insert(0, ((IdentifierExpression)fieldReferenceExpression.TargetObject).Identifier.ToCharArray());
string oldType = type.ToString();
int idx = oldType.LastIndexOf('.');
while (idx > 0) {
if (Type.GetType(type.ToString()) != null) {
break;
}
string stype = type.ToString().Substring(idx + 1);
type = new StringBuilder(type.ToString().Substring(0, idx));
type.Append("+");
type.Append(stype);
idx = type.ToString().LastIndexOf('.');
}
if (Type.GetType(type.ToString()) == null) {
type = new StringBuilder(oldType);
}
return new CodeTypeReferenceExpression(type.ToString());
} else if (fieldReferenceExpression.TargetObject is TypeReferenceExpression) {
type.Insert(0, ((TypeReferenceExpression)fieldReferenceExpression.TargetObject).TypeReference.SystemType);
return new CodeTypeReferenceExpression(type.ToString());
} else {
return null;
}
}
CodeExpression[] GetExpressionList(IList expressionList)
{
if (expressionList == null) {
return new CodeExpression[0];
}
CodeExpression[] list = new CodeExpression[expressionList.Count];
for (int i = 0; i < expressionList.Count; ++i) {
list[i] = (CodeExpression)((Expression)expressionList[i]).AcceptVisitor(this, null);
if (list[i] == null) {
list[i] = new CodePrimitiveExpression(0);
}
}
return list;
}
}
}