📄 vbnetconstructsconvertvisitor.cs
字号:
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision: 2200 $</version>
// </file>
using System;
using System.Collections.Generic;
using System.Reflection;
using ICSharpCode.NRefactory.Ast;
using Attribute = ICSharpCode.NRefactory.Ast.Attribute;
namespace ICSharpCode.NRefactory.Visitors
{
/// <summary>
/// Converts special VB constructs to use more general AST classes.
/// </summary>
public class VBNetConstructsConvertVisitor : AbstractAstTransformer
{
// The following conversions are implemented:
// MyBase.New() and MyClass.New() calls inside the constructor are converted to :base() and :this()
// Add Public Modifier to inner types, methods, properties and fields in structures
// Override Finalize => Destructor
// IIF(cond, true, false) => ConditionalExpression
// Built-in methods => Prefix with class name
// Function A() \n A = SomeValue \n End Function -> convert to return statement
// Array creation => add 1 to upper bound to get array length
Dictionary<string, string> usings;
List<UsingDeclaration> addedUsings;
TypeDeclaration currentTypeDeclaration;
public override object VisitCompilationUnit(CompilationUnit compilationUnit, object data)
{
usings = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
addedUsings = new List<UsingDeclaration>();
base.VisitCompilationUnit(compilationUnit, data);
int i;
for (i = 0; i < compilationUnit.Children.Count; i++) {
if (!(compilationUnit.Children[i] is UsingDeclaration))
break;
}
foreach (UsingDeclaration decl in addedUsings) {
decl.Parent = compilationUnit;
compilationUnit.Children.Insert(i++, decl);
}
usings = null;
addedUsings = null;
return null;
}
public override object VisitUsing(Using @using, object data)
{
if (usings != null && !@using.IsAlias) {
usings[@using.Name] = @using.Name;
}
return base.VisitUsing(@using, data);
}
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
{
// fix default visibility of inner classes
if (currentTypeDeclaration != null && (typeDeclaration.Modifier & Modifiers.Visibility) == 0)
typeDeclaration.Modifier |= Modifiers.Public;
TypeDeclaration oldTypeDeclaration = currentTypeDeclaration;
currentTypeDeclaration = typeDeclaration;
base.VisitTypeDeclaration(typeDeclaration, data);
currentTypeDeclaration = oldTypeDeclaration;
return null;
}
public override object VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration, object data)
{
// fix default visibility of inner classes
if (currentTypeDeclaration != null && (delegateDeclaration.Modifier & Modifiers.Visibility) == 0)
delegateDeclaration.Modifier |= Modifiers.Public;
return base.VisitDelegateDeclaration(delegateDeclaration, data);
}
bool IsClassType(ClassType c)
{
if (currentTypeDeclaration == null) return false;
return currentTypeDeclaration.Type == c;
}
public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data)
{
// make constructor public if visiblity is not set (unless constructor is static)
if ((constructorDeclaration.Modifier & (Modifiers.Visibility | Modifiers.Static)) == 0)
constructorDeclaration.Modifier |= Modifiers.Public;
// MyBase.New() and MyClass.New() calls inside the constructor are converted to :base() and :this()
BlockStatement body = constructorDeclaration.Body;
if (body != null && body.Children.Count > 0) {
ExpressionStatement se = body.Children[0] as ExpressionStatement;
if (se != null) {
InvocationExpression ie = se.Expression as InvocationExpression;
if (ie != null) {
FieldReferenceExpression fre = ie.TargetObject as FieldReferenceExpression;
if (fre != null && "New".Equals(fre.FieldName, StringComparison.InvariantCultureIgnoreCase)) {
if (fre.TargetObject is BaseReferenceExpression || fre.TargetObject is ClassReferenceExpression || fre.TargetObject is ThisReferenceExpression) {
body.Children.RemoveAt(0);
ConstructorInitializer ci = new ConstructorInitializer();
ci.Arguments = ie.Arguments;
if (fre.TargetObject is BaseReferenceExpression)
ci.ConstructorInitializerType = ConstructorInitializerType.Base;
else
ci.ConstructorInitializerType = ConstructorInitializerType.This;
constructorDeclaration.ConstructorInitializer = ci;
}
}
}
}
}
return base.VisitConstructorDeclaration(constructorDeclaration, data);
}
public override object VisitDeclareDeclaration(DeclareDeclaration declareDeclaration, object data)
{
if (usings != null && !usings.ContainsKey("System.Runtime.InteropServices")) {
UsingDeclaration @using = new UsingDeclaration("System.Runtime.InteropServices");
addedUsings.Add(@using);
base.VisitUsingDeclaration(@using, data);
}
MethodDeclaration method = new MethodDeclaration(declareDeclaration.Name, declareDeclaration.Modifier,
declareDeclaration.TypeReference, declareDeclaration.Parameters,
declareDeclaration.Attributes);
if ((method.Modifier & Modifiers.Visibility) == 0)
method.Modifier |= Modifiers.Public;
method.Modifier |= Modifiers.Extern | Modifiers.Static;
if (method.TypeReference.IsNull) {
method.TypeReference = new TypeReference("System.Void");
}
Attribute att = new Attribute("DllImport", null, null);
att.PositionalArguments.Add(CreateStringLiteral(declareDeclaration.Library));
if (declareDeclaration.Alias.Length > 0) {
att.NamedArguments.Add(new NamedArgumentExpression("EntryPoint", CreateStringLiteral(declareDeclaration.Alias)));
}
switch (declareDeclaration.Charset) {
case CharsetModifier.Auto:
att.NamedArguments.Add(new NamedArgumentExpression("CharSet",
new FieldReferenceExpression(new IdentifierExpression("CharSet"),
"Auto")));
break;
case CharsetModifier.Unicode:
att.NamedArguments.Add(new NamedArgumentExpression("CharSet",
new FieldReferenceExpression(new IdentifierExpression("CharSet"),
"Unicode")));
break;
default:
att.NamedArguments.Add(new NamedArgumentExpression("CharSet",
new FieldReferenceExpression(new IdentifierExpression("CharSet"),
"Ansi")));
break;
}
att.NamedArguments.Add(new NamedArgumentExpression("SetLastError", new PrimitiveExpression(true, true.ToString())));
att.NamedArguments.Add(new NamedArgumentExpression("ExactSpelling", new PrimitiveExpression(true, true.ToString())));
AttributeSection sec = new AttributeSection(null, null);
sec.Attributes.Add(att);
method.Attributes.Add(sec);
ReplaceCurrentNode(method);
return base.VisitMethodDeclaration(method, data);
}
static PrimitiveExpression CreateStringLiteral(string text)
{
return new PrimitiveExpression(text, text);
}
public override object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data)
{
if (!IsClassType(ClassType.Interface) && (methodDeclaration.Modifier & Modifiers.Visibility) == 0)
methodDeclaration.Modifier |= Modifiers.Public;
if ("Finalize".Equals(methodDeclaration.Name, StringComparison.InvariantCultureIgnoreCase)
&& methodDeclaration.Parameters.Count == 0
&& methodDeclaration.Modifier == (Modifiers.Protected | Modifiers.Override)
&& methodDeclaration.Body.Children.Count == 1)
{
TryCatchStatement tcs = methodDeclaration.Body.Children[0] as TryCatchStatement;
if (tcs != null
&& tcs.StatementBlock is BlockStatement
&& tcs.CatchClauses.Count == 0
&& tcs.FinallyBlock is BlockStatement
&& tcs.FinallyBlock.Children.Count == 1)
{
ExpressionStatement se = tcs.FinallyBlock.Children[0] as ExpressionStatement;
if (se != null) {
InvocationExpression ie = se.Expression as InvocationExpression;
if (ie != null
&& ie.Arguments.Count == 0
&& ie.TargetObject is FieldReferenceExpression
&& (ie.TargetObject as FieldReferenceExpression).TargetObject is BaseReferenceExpression
&& "Finalize".Equals((ie.TargetObject as FieldReferenceExpression).FieldName, StringComparison.InvariantCultureIgnoreCase))
{
DestructorDeclaration des = new DestructorDeclaration("Destructor", Modifiers.None, methodDeclaration.Attributes);
ReplaceCurrentNode(des);
des.Body = (BlockStatement)tcs.StatementBlock;
return base.VisitDestructorDeclaration(des, data);
}
}
}
}
if ((methodDeclaration.Modifier & (Modifiers.Static | Modifiers.Extern)) == Modifiers.Static
&& methodDeclaration.Body.Children.Count == 0)
{
foreach (AttributeSection sec in methodDeclaration.Attributes) {
foreach (Attribute att in sec.Attributes) {
if ("DllImport".Equals(att.Name, StringComparison.InvariantCultureIgnoreCase)) {
methodDeclaration.Modifier |= Modifiers.Extern;
methodDeclaration.Body = null;
}
}
}
}
if (methodDeclaration.TypeReference.SystemType != "System.Void" && methodDeclaration.Body.Children.Count > 0) {
if (IsAssignmentTo(methodDeclaration.Body.Children[methodDeclaration.Body.Children.Count - 1], methodDeclaration.Name))
{
ReturnStatement rs = new ReturnStatement(GetAssignmentFromStatement(methodDeclaration.Body.Children[methodDeclaration.Body.Children.Count - 1]).Right);
methodDeclaration.Body.Children.RemoveAt(methodDeclaration.Body.Children.Count - 1);
methodDeclaration.Body.AddChild(rs);
} else {
ReturnStatementForFunctionAssignment visitor = new ReturnStatementForFunctionAssignment(methodDeclaration.Name);
methodDeclaration.Body.AcceptVisitor(visitor, null);
if (visitor.replacementCount > 0) {
Expression init;
switch (methodDeclaration.TypeReference.SystemType) {
case "System.Int16":
case "System.Int32":
case "System.Int64":
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -