mirror of https://github.com/icsharpcode/ILSpy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
229 lines
9.4 KiB
229 lines
9.4 KiB
// <file> |
|
// <copyright see="prj:///doc/copyright.txt"/> |
|
// <license see="prj:///doc/license.txt"/> |
|
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/> |
|
// <version>$Revision$</version> |
|
// </file> |
|
|
|
using System; |
|
using ICSharpCode.NRefactory.Ast; |
|
|
|
namespace ICSharpCode.NRefactory.Visitors |
|
{ |
|
/// <summary> |
|
/// Converts special C# constructs to use more general AST classes. |
|
/// </summary> |
|
public class CSharpConstructsConvertVisitor : ConvertVisitorBase |
|
{ |
|
// The following conversions are implemented: |
|
// a == null -> a Is Nothing |
|
// a != null -> a Is Not Nothing |
|
// i++ / ++i as statement: convert to i += 1 |
|
// i-- / --i as statement: convert to i -= 1 |
|
// ForStatement -> ForNextStatement when for-loop is simple |
|
// if (Event != null) Event(this, bla); -> RaiseEvent Event(this, bla) |
|
// Casts to value types are marked as conversions |
|
|
|
public override object VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data) |
|
{ |
|
if (binaryOperatorExpression.Op == BinaryOperatorType.Equality || binaryOperatorExpression.Op == BinaryOperatorType.InEquality) { |
|
if (IsNullLiteralExpression(binaryOperatorExpression.Left)) { |
|
Expression tmp = binaryOperatorExpression.Left; |
|
binaryOperatorExpression.Left = binaryOperatorExpression.Right; |
|
binaryOperatorExpression.Right = tmp; |
|
} |
|
if (IsNullLiteralExpression(binaryOperatorExpression.Right)) { |
|
if (binaryOperatorExpression.Op == BinaryOperatorType.Equality) { |
|
binaryOperatorExpression.Op = BinaryOperatorType.ReferenceEquality; |
|
} else { |
|
binaryOperatorExpression.Op = BinaryOperatorType.ReferenceInequality; |
|
} |
|
} |
|
} |
|
return base.VisitBinaryOperatorExpression(binaryOperatorExpression, data); |
|
} |
|
|
|
static bool IsNullLiteralExpression(Expression expr) |
|
{ |
|
PrimitiveExpression pe = expr as PrimitiveExpression; |
|
if (pe == null) return false; |
|
return pe.Value == null; |
|
} |
|
|
|
|
|
public override object VisitExpressionStatement(ExpressionStatement expressionStatement, object data) |
|
{ |
|
UnaryOperatorExpression uoe = expressionStatement.Expression as UnaryOperatorExpression; |
|
if (uoe != null) { |
|
switch (uoe.Op) { |
|
case UnaryOperatorType.Increment: |
|
case UnaryOperatorType.PostIncrement: |
|
expressionStatement.Expression = new AssignmentExpression(uoe.Expression, AssignmentOperatorType.Add, new PrimitiveExpression(1, "1")); |
|
break; |
|
case UnaryOperatorType.Decrement: |
|
case UnaryOperatorType.PostDecrement: |
|
expressionStatement.Expression = new AssignmentExpression(uoe.Expression, AssignmentOperatorType.Subtract, new PrimitiveExpression(1, "1")); |
|
break; |
|
} |
|
} |
|
return base.VisitExpressionStatement(expressionStatement, data); |
|
} |
|
|
|
public override object VisitIfElseStatement(IfElseStatement ifElseStatement, object data) |
|
{ |
|
BinaryOperatorExpression boe = ifElseStatement.Condition as BinaryOperatorExpression; |
|
// the BinaryOperatorExpression might be inside a ParenthesizedExpression |
|
if (boe == null && ifElseStatement.Condition is ParenthesizedExpression) { |
|
boe = (ifElseStatement.Condition as ParenthesizedExpression).Expression as BinaryOperatorExpression; |
|
} |
|
if (ifElseStatement.ElseIfSections.Count == 0 |
|
&& ifElseStatement.FalseStatement.Count == 0 |
|
&& ifElseStatement.TrueStatement.Count == 1 |
|
&& boe != null |
|
&& boe.Op == BinaryOperatorType.InEquality |
|
&& (IsNullLiteralExpression(boe.Left) || IsNullLiteralExpression(boe.Right)) |
|
) |
|
{ |
|
string ident = GetPossibleEventName(boe.Left) ?? GetPossibleEventName(boe.Right); |
|
ExpressionStatement se = ifElseStatement.TrueStatement[0] as ExpressionStatement; |
|
if (se == null) { |
|
BlockStatement block = ifElseStatement.TrueStatement[0] as BlockStatement; |
|
if (block != null && block.Children.Count == 1) { |
|
se = block.Children[0] as ExpressionStatement; |
|
} |
|
} |
|
if (ident != null && se != null) { |
|
InvocationExpression ie = se.Expression as InvocationExpression; |
|
if (ie != null && GetPossibleEventName(ie.TargetObject) == ident) { |
|
ReplaceCurrentNode(new RaiseEventStatement(ident, ie.Arguments)); |
|
} |
|
} |
|
} |
|
return base.VisitIfElseStatement(ifElseStatement, data); |
|
} |
|
|
|
string GetPossibleEventName(Expression expression) |
|
{ |
|
IdentifierExpression ident = expression as IdentifierExpression; |
|
if (ident != null) |
|
return ident.Identifier; |
|
MemberReferenceExpression fre = expression as MemberReferenceExpression; |
|
if (fre != null && fre.TargetObject is ThisReferenceExpression) |
|
return fre.MemberName; |
|
return null; |
|
} |
|
|
|
public override object VisitForStatement(ForStatement forStatement, object data) |
|
{ |
|
base.VisitForStatement(forStatement, data); |
|
ConvertForStatement(forStatement); |
|
return null; |
|
} |
|
|
|
void ConvertForStatement(ForStatement forStatement) |
|
{ |
|
// ForStatement -> ForNextStatement when for-loop is simple |
|
|
|
// only the following forms of the for-statement are allowed: |
|
// for (TypeReference name = start; name < oneAfterEnd; name += step) |
|
// for (name = start; name < oneAfterEnd; name += step) |
|
// for (TypeReference name = start; name <= end; name += step) |
|
// for (name = start; name <= end; name += step) |
|
// for (TypeReference name = start; name > oneAfterEnd; name -= step) |
|
// for (name = start; name > oneAfterEnd; name -= step) |
|
// for (TypeReference name = start; name >= end; name -= step) |
|
// for (name = start; name >= end; name -= step) |
|
|
|
// check if the form is valid and collect TypeReference, name, start, end and step |
|
if (forStatement.Initializers.Count != 1) |
|
return; |
|
if (forStatement.Iterator.Count != 1) |
|
return; |
|
ExpressionStatement statement = forStatement.Iterator[0] as ExpressionStatement; |
|
if (statement == null) |
|
return; |
|
AssignmentExpression iterator = statement.Expression as AssignmentExpression; |
|
if (iterator == null || (iterator.Op != AssignmentOperatorType.Add && iterator.Op != AssignmentOperatorType.Subtract)) |
|
return; |
|
IdentifierExpression iteratorIdentifier = iterator.Left as IdentifierExpression; |
|
if (iteratorIdentifier == null) |
|
return; |
|
PrimitiveExpression stepExpression = iterator.Right as PrimitiveExpression; |
|
if (stepExpression == null || !(stepExpression.Value is int)) |
|
return; |
|
int step = (int)stepExpression.Value; |
|
if (iterator.Op == AssignmentOperatorType.Subtract) |
|
step = -step; |
|
|
|
BinaryOperatorExpression condition = forStatement.Condition as BinaryOperatorExpression; |
|
if (condition == null || !(condition.Left is IdentifierExpression)) |
|
return; |
|
if ((condition.Left as IdentifierExpression).Identifier != iteratorIdentifier.Identifier) |
|
return; |
|
Expression end; |
|
if (iterator.Op == AssignmentOperatorType.Subtract) { |
|
if (condition.Op == BinaryOperatorType.GreaterThanOrEqual) { |
|
end = condition.Right; |
|
} else if (condition.Op == BinaryOperatorType.GreaterThan) { |
|
end = Expression.AddInteger(condition.Right, 1); |
|
} else { |
|
return; |
|
} |
|
} else { |
|
if (condition.Op == BinaryOperatorType.LessThanOrEqual) { |
|
end = condition.Right; |
|
} else if (condition.Op == BinaryOperatorType.LessThan) { |
|
end = Expression.AddInteger(condition.Right, -1); |
|
} else { |
|
return; |
|
} |
|
} |
|
|
|
Expression start; |
|
TypeReference typeReference = null; |
|
LocalVariableDeclaration varDecl = forStatement.Initializers[0] as LocalVariableDeclaration; |
|
if (varDecl != null) { |
|
if (varDecl.Variables.Count != 1 |
|
|| varDecl.Variables[0].Name != iteratorIdentifier.Identifier |
|
|| varDecl.Variables[0].Initializer == null) |
|
return; |
|
typeReference = varDecl.GetTypeForVariable(0); |
|
start = varDecl.Variables[0].Initializer; |
|
} else { |
|
statement = forStatement.Initializers[0] as ExpressionStatement; |
|
if (statement == null) |
|
return; |
|
AssignmentExpression assign = statement.Expression as AssignmentExpression; |
|
if (assign == null || assign.Op != AssignmentOperatorType.Assign) |
|
return; |
|
if (!(assign.Left is IdentifierExpression)) |
|
return; |
|
if ((assign.Left as IdentifierExpression).Identifier != iteratorIdentifier.Identifier) |
|
return; |
|
start = assign.Right; |
|
} |
|
|
|
ReplaceCurrentNode(new ForNextStatement(typeReference, iteratorIdentifier.Identifier, |
|
start, end, |
|
(step == 1) ? null : new PrimitiveExpression(step, step.ToString(System.Globalization.NumberFormatInfo.InvariantInfo)), |
|
forStatement.EmbeddedStatement, null)); |
|
} |
|
|
|
public override object VisitCastExpression(CastExpression castExpression, object data) |
|
{ |
|
if (castExpression.CastType == CastType.Cast) { |
|
// Casts to value types are marked as conversions |
|
// this code only supports primitive types, user-defined value types are handled by |
|
// the DOM-aware CSharpToVBNetConvertVisitor |
|
string type; |
|
if (TypeReference.PrimitiveTypesCSharpReverse.TryGetValue(castExpression.CastTo.SystemType, out type)) { |
|
if (type != "object" && type != "string") { |
|
// type is value type |
|
castExpression.CastType = CastType.Conversion; |
|
} |
|
} |
|
} |
|
return base.VisitCastExpression(castExpression, data); |
|
} |
|
} |
|
}
|
|
|