.NET Decompiler with support for PDB generation, ReadyToRun, Metadata (&more) - cross-platform!
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.
 
 
 
 

856 lines
33 KiB

// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
// created on 04.08.2003 at 17:49
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Linq;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Visitors;
using ICSharpCode.SharpDevelop.Dom.VBNet;
using AST = ICSharpCode.NRefactory.Ast;
using RefParser = ICSharpCode.NRefactory;
namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
{
public class NRefactoryASTConvertVisitor : AbstractAstVisitor
{
DefaultCompilationUnit cu;
DefaultUsingScope currentNamespace;
Stack<DefaultClass> currentClass = new Stack<DefaultClass>();
public string VBRootNamespace { get; set; }
public ICompilationUnit Cu {
get {
return cu;
}
}
public NRefactoryASTConvertVisitor(IProjectContent projectContent, SupportedLanguage language)
{
if (language == SupportedLanguage.VBNet)
cu = new VBNetCompilationUnit(projectContent);
else
cu = new DefaultCompilationUnit(projectContent);
}
DefaultClass GetCurrentClass()
{
return currentClass.Count == 0 ? null : currentClass.Peek();
}
ModifierEnum ConvertModifier(AST.Modifiers m)
{
if (this.IsVisualBasic)
return ConvertModifier(m, ModifierEnum.Public);
else if (currentClass.Count > 0 && currentClass.Peek().ClassType == ClassType.Interface)
return ConvertModifier(m, ModifierEnum.Public);
else
return ConvertModifier(m, ModifierEnum.Private);
}
ModifierEnum ConvertTypeModifier(AST.Modifiers m)
{
if (this.IsVisualBasic)
return ConvertModifier(m, ModifierEnum.Public);
if (currentClass.Count > 0)
return ConvertModifier(m, ModifierEnum.Private);
else
return ConvertModifier(m, ModifierEnum.Internal);
}
ModifierEnum ConvertModifier(AST.Modifiers m, ModifierEnum defaultVisibility)
{
ModifierEnum r = (ModifierEnum)m;
if ((r & ModifierEnum.VisibilityMask) == ModifierEnum.None)
return r | defaultVisibility;
else
return r;
}
List<RefParser.ISpecial> specials;
/// <summary>
/// Gets/Sets the list of specials used to read the documentation.
/// The list must be sorted by the start position of the specials!
/// </summary>
public List<RefParser.ISpecial> Specials {
get {
return specials;
}
set {
specials = value;
}
}
string GetDocumentation(int line, IList<AST.AttributeSection> attributes)
{
foreach (AST.AttributeSection att in attributes) {
if (att.StartLocation.Y > 0 && att.StartLocation.Y < line)
line = att.StartLocation.Y;
}
List<string> lines = new List<string>();
int length = 0;
while (line > 0) {
line--;
string doku = null;
bool foundPreprocessing = false;
var specialsOnLine = GetSpecialsFromLine(line);
foreach (RefParser.ISpecial special in specialsOnLine) {
RefParser.Comment comment = special as RefParser.Comment;
if (comment != null && comment.CommentType == RefParser.CommentType.Documentation) {
doku = comment.CommentText;
break;
} else if (special is RefParser.PreprocessingDirective) {
foundPreprocessing = true;
}
}
if (doku == null && !foundPreprocessing)
break;
if (doku != null) {
length += 2 + doku.Length;
lines.Add(doku);
}
}
StringBuilder b = new StringBuilder(length);
for (int i = lines.Count - 1; i >= 0; --i) {
b.AppendLine(lines[i]);
}
return b.ToString();
}
string GetDocumentationFromLine(int line)
{
foreach (RefParser.ISpecial special in GetSpecialsFromLine(line)) {
RefParser.Comment comment = special as RefParser.Comment;
if (comment != null && comment.CommentType == RefParser.CommentType.Documentation) {
return comment.CommentText;
}
}
return null;
}
IEnumerable<RefParser.ISpecial> GetSpecialsFromLine(int line)
{
List<RefParser.ISpecial> result = new List<RefParser.ISpecial>();
if (specials == null) return result;
if (line < 0) return result;
// specials is a sorted list: use interpolation search
int left = 0;
int right = specials.Count - 1;
int m;
while (left <= right) {
int leftLine = specials[left].StartPosition.Y;
if (line < leftLine)
break;
int rightLine = specials[right].StartPosition.Y;
if (line > rightLine)
break;
if (leftLine == rightLine) {
if (leftLine == line)
m = left;
else
break;
} else {
m = (int)(left + Math.BigMul((line - leftLine), (right - left)) / (rightLine - leftLine));
}
int mLine = specials[m].StartPosition.Y;
if (mLine < line) { // found line smaller than line we are looking for
left = m + 1;
} else if (mLine > line) {
right = m - 1;
} else {
// correct line found,
// look for first special in that line
while (--m >= 0 && specials[m].StartPosition.Y == line);
// look at all specials in that line: find doku-comment
while (++m < specials.Count && specials[m].StartPosition.Y == line) {
result.Add(specials[m]);
}
break;
}
}
return result;
}
public override object VisitCompilationUnit(AST.CompilationUnit compilationUnit, object data)
{
if (compilationUnit == null) {
return null;
}
currentNamespace = new DefaultUsingScope();
if (!string.IsNullOrEmpty(VBRootNamespace)) {
foreach (string name in VBRootNamespace.Split('.')) {
currentNamespace = new DefaultUsingScope {
Parent = currentNamespace,
NamespaceName = PrependCurrentNamespace(name),
};
currentNamespace.Parent.ChildScopes.Add(currentNamespace);
}
}
cu.UsingScope = currentNamespace;
compilationUnit.AcceptChildren(this, data);
return cu;
}
public override object VisitUsingDeclaration(AST.UsingDeclaration usingDeclaration, object data)
{
DefaultUsing us = new DefaultUsing(cu.ProjectContent, GetRegion(usingDeclaration.StartLocation, usingDeclaration.EndLocation));
foreach (AST.Using u in usingDeclaration.Usings) {
u.AcceptVisitor(this, us);
}
currentNamespace.Usings.Add(us);
return data;
}
public override object VisitUsing(AST.Using u, object data)
{
Debug.Assert(data is DefaultUsing);
DefaultUsing us = (DefaultUsing)data;
if (u.IsAlias) {
IReturnType rt = CreateReturnType(u.Alias);
if (rt != null) {
us.AddAlias(u.Name, rt);
}
} else {
us.Usings.Add(u.Name);
}
return data;
}
public override object VisitOptionDeclaration(ICSharpCode.NRefactory.Ast.OptionDeclaration optionDeclaration, object data)
{
if (cu is VBNetCompilationUnit) {
VBNetCompilationUnit provider = cu as VBNetCompilationUnit;
switch (optionDeclaration.OptionType) {
case ICSharpCode.NRefactory.Ast.OptionType.Explicit:
provider.OptionExplicit = optionDeclaration.OptionValue;
break;
case ICSharpCode.NRefactory.Ast.OptionType.Strict:
provider.OptionStrict = optionDeclaration.OptionValue;
break;
case ICSharpCode.NRefactory.Ast.OptionType.CompareBinary:
provider.OptionCompare = CompareKind.Binary;
break;
case ICSharpCode.NRefactory.Ast.OptionType.CompareText:
provider.OptionCompare = CompareKind.Text;
break;
case ICSharpCode.NRefactory.Ast.OptionType.Infer:
provider.OptionInfer = optionDeclaration.OptionValue;
break;
}
return null;
}
return base.VisitOptionDeclaration(optionDeclaration, data);
}
void ConvertAttributes(AST.AttributedNode from, AbstractEntity to)
{
if (from.Attributes.Count == 0) {
to.Attributes = DefaultAttribute.EmptyAttributeList;
} else {
ICSharpCode.NRefactory.Location location = from.Attributes[0].StartLocation;
ClassFinder context;
if (to is IClass) {
context = new ClassFinder((IClass)to, location.Line, location.Column);
} else {
context = new ClassFinder(to.DeclaringType, location.Line, location.Column);
}
to.Attributes = VisitAttributes(from.Attributes, context);
}
}
List<IAttribute> VisitAttributes(IList<AST.AttributeSection> attributes, ClassFinder context)
{
// TODO Expressions???
List<IAttribute> result = new List<IAttribute>();
foreach (AST.AttributeSection section in attributes) {
AttributeTarget target = AttributeTarget.None;
if (section.AttributeTarget != null && section.AttributeTarget != "") {
switch (section.AttributeTarget.ToUpperInvariant()) {
case "ASSEMBLY":
target = AttributeTarget.Assembly;
break;
case "FIELD":
target = AttributeTarget.Field;
break;
case "EVENT":
target = AttributeTarget.Event;
break;
case "METHOD":
target = AttributeTarget.Method;
break;
case "MODULE":
target = AttributeTarget.Module;
break;
case "PARAM":
target = AttributeTarget.Param;
break;
case "PROPERTY":
target = AttributeTarget.Property;
break;
case "RETURN":
target = AttributeTarget.Return;
break;
case "TYPE":
target = AttributeTarget.Type;
break;
default:
target = AttributeTarget.None;
break;
}
}
foreach (AST.Attribute attribute in section.Attributes) {
List<object> positionalArguments = new List<object>();
foreach (AST.Expression positionalArgument in attribute.PositionalArguments) {
positionalArguments.Add(ConvertAttributeArgument(positionalArgument));
}
Dictionary<string, object> namedArguments = new Dictionary<string, object>();
foreach (AST.NamedArgumentExpression namedArgumentExpression in attribute.NamedArguments) {
namedArguments.Add(namedArgumentExpression.Name, ConvertAttributeArgument(namedArgumentExpression.Expression));
}
result.Add(new DefaultAttribute(new AttributeReturnType(context, attribute.Name),
target, positionalArguments, namedArguments)
{
CompilationUnit = cu,
Region = GetRegion(attribute.StartLocation, attribute.EndLocation)
});
}
}
return result;
}
static object ConvertAttributeArgument(AST.Expression expression)
{
AST.PrimitiveExpression pe = expression as AST.PrimitiveExpression;
if (pe != null)
return pe.Value;
else
return null;
}
public override object VisitAttributeSection(ICSharpCode.NRefactory.Ast.AttributeSection attributeSection, object data)
{
if (GetCurrentClass() == null) {
ClassFinder cf = new ClassFinder(new DefaultClass(cu, "DummyClass"), attributeSection.StartLocation.Line, attributeSection.StartLocation.Column);
cu.Attributes.AddRange(VisitAttributes(new[] { attributeSection }, cf));
}
return null;
}
string PrependCurrentNamespace(string name)
{
if (string.IsNullOrEmpty(currentNamespace.NamespaceName))
return name;
else
return currentNamespace.NamespaceName + "." + name;
}
public override object VisitNamespaceDeclaration(AST.NamespaceDeclaration namespaceDeclaration, object data)
{
DefaultUsingScope oldNamespace = currentNamespace;
foreach (string name in namespaceDeclaration.Name.Split('.')) {
currentNamespace = new DefaultUsingScope {
Parent = currentNamespace,
NamespaceName = PrependCurrentNamespace(name),
};
currentNamespace.Parent.ChildScopes.Add(currentNamespace);
}
object ret = namespaceDeclaration.AcceptChildren(this, data);
currentNamespace = oldNamespace;
return ret;
}
ClassType TranslateClassType(AST.ClassType type)
{
switch (type) {
case AST.ClassType.Enum:
return ClassType.Enum;
case AST.ClassType.Interface:
return ClassType.Interface;
case AST.ClassType.Struct:
return ClassType.Struct;
case AST.ClassType.Module:
return ClassType.Module;
default:
return ClassType.Class;
}
}
static DomRegion GetRegion(RefParser.Location start, RefParser.Location end)
{
return DomRegion.FromLocation(start, end);
}
public override object VisitTypeDeclaration(AST.TypeDeclaration typeDeclaration, object data)
{
DomRegion region = GetRegion(typeDeclaration.StartLocation, typeDeclaration.EndLocation);
DomRegion bodyRegion = GetRegion(typeDeclaration.BodyStartLocation, typeDeclaration.EndLocation);
DefaultClass c = new DefaultClass(cu, TranslateClassType(typeDeclaration.Type), ConvertTypeModifier(typeDeclaration.Modifier), region, GetCurrentClass());
if (c.IsStatic) {
// static classes are also abstract and sealed at the same time
c.Modifiers |= ModifierEnum.Abstract | ModifierEnum.Sealed;
}
c.BodyRegion = bodyRegion;
ConvertAttributes(typeDeclaration, c);
c.Documentation = GetDocumentation(region.BeginLine, typeDeclaration.Attributes);
DefaultClass outerClass = GetCurrentClass();
if (outerClass != null) {
outerClass.InnerClasses.Add(c);
c.FullyQualifiedName = outerClass.FullyQualifiedName + '.' + typeDeclaration.Name;
} else {
c.FullyQualifiedName = PrependCurrentNamespace(typeDeclaration.Name);
cu.Classes.Add(c);
}
c.UsingScope = currentNamespace;
currentClass.Push(c);
ConvertTemplates(outerClass, typeDeclaration.Templates, c); // resolve constrains in context of the class
// templates must be converted before base types because base types may refer to generic types
if (c.ClassType != ClassType.Enum && typeDeclaration.BaseTypes != null) {
foreach (AST.TypeReference type in typeDeclaration.BaseTypes) {
IReturnType rt = CreateReturnType(type, null, TypeVisitor.ReturnTypeOptions.BaseTypeReference);
if (rt != null) {
c.BaseTypes.Add(rt);
}
}
}
object ret = typeDeclaration.AcceptChildren(this, data);
currentClass.Pop();
if (c.ClassType == ClassType.Module) {
foreach (DefaultField f in c.Fields) {
f.Modifiers |= ModifierEnum.Static;
}
foreach (DefaultMethod m in c.Methods) {
m.Modifiers |= ModifierEnum.Static;
}
foreach (DefaultProperty p in c.Properties) {
p.Modifiers |= ModifierEnum.Static;
}
foreach (DefaultEvent e in c.Events) {
e.Modifiers |= ModifierEnum.Static;
}
}
return ret;
}
void ConvertTemplates(DefaultClass outerClass, IList<AST.TemplateDefinition> templateList, DefaultClass c)
{
int outerClassTypeParameterCount = outerClass != null ? outerClass.TypeParameters.Count : 0;
if (templateList.Count == 0 && outerClassTypeParameterCount == 0) {
c.TypeParameters = DefaultTypeParameter.EmptyTypeParameterList;
} else {
Debug.Assert(c.TypeParameters.Count == 0);
int index = 0;
if (outerClassTypeParameterCount > 0) {
foreach (DefaultTypeParameter outerTypeParamter in outerClass.TypeParameters) {
DefaultTypeParameter p = new DefaultTypeParameter(c, outerTypeParamter.Name, index++);
p.HasConstructableConstraint = outerTypeParamter.HasConstructableConstraint;
p.HasReferenceTypeConstraint = outerTypeParamter.HasReferenceTypeConstraint;
p.HasValueTypeConstraint = outerTypeParamter.HasValueTypeConstraint;
p.Attributes.AddRange(outerTypeParamter.Attributes);
p.Constraints.AddRange(outerTypeParamter.Constraints);
c.TypeParameters.Add(p);
}
}
foreach (AST.TemplateDefinition template in templateList) {
c.TypeParameters.Add(new DefaultTypeParameter(c, template.Name, index++));
}
// converting the constraints requires that the type parameters are already present
for (int i = 0; i < templateList.Count; i++) {
ConvertConstraints(templateList[i], (DefaultTypeParameter)c.TypeParameters[i + outerClassTypeParameterCount]);
}
}
}
void ConvertTemplates(List<AST.TemplateDefinition> templateList, DefaultMethod m)
{
int index = 0;
if (templateList.Count == 0) {
m.TypeParameters = DefaultTypeParameter.EmptyTypeParameterList;
} else {
Debug.Assert(m.TypeParameters.Count == 0);
foreach (AST.TemplateDefinition template in templateList) {
m.TypeParameters.Add(new DefaultTypeParameter(m, template.Name, index++));
}
// converting the constraints requires that the type parameters are already present
for (int i = 0; i < templateList.Count; i++) {
ConvertConstraints(templateList[i], (DefaultTypeParameter)m.TypeParameters[i]);
}
}
}
void ConvertConstraints(AST.TemplateDefinition template, DefaultTypeParameter typeParameter)
{
foreach (AST.TypeReference typeRef in template.Bases) {
if (typeRef == AST.TypeReference.NewConstraint) {
typeParameter.HasConstructableConstraint = true;
} else if (typeRef == AST.TypeReference.ClassConstraint) {
typeParameter.HasReferenceTypeConstraint = true;
} else if (typeRef == AST.TypeReference.StructConstraint) {
typeParameter.HasValueTypeConstraint = true;
} else {
IReturnType rt = CreateReturnType(typeRef, typeParameter.Method, TypeVisitor.ReturnTypeOptions.None);
if (rt != null) {
typeParameter.Constraints.Add(rt);
}
}
}
}
public override object VisitDelegateDeclaration(AST.DelegateDeclaration delegateDeclaration, object data)
{
DomRegion region = GetRegion(delegateDeclaration.StartLocation, delegateDeclaration.EndLocation);
DefaultClass c = new DefaultClass(cu, ClassType.Delegate, ConvertTypeModifier(delegateDeclaration.Modifier), region, GetCurrentClass());
c.Documentation = GetDocumentation(region.BeginLine, delegateDeclaration.Attributes);
ConvertAttributes(delegateDeclaration, c);
CreateDelegate(c, delegateDeclaration.Name, delegateDeclaration.ReturnType,
delegateDeclaration.Templates, delegateDeclaration.Parameters);
return c;
}
void CreateDelegate(DefaultClass c, string name, AST.TypeReference returnType, IList<AST.TemplateDefinition> templates, IList<AST.ParameterDeclarationExpression> parameters)
{
c.BaseTypes.Add(c.ProjectContent.SystemTypes.MulticastDelegate);
DefaultClass outerClass = GetCurrentClass();
if (outerClass != null) {
outerClass.InnerClasses.Add(c);
c.FullyQualifiedName = outerClass.FullyQualifiedName + '.' + name;
} else {
c.FullyQualifiedName = PrependCurrentNamespace(name);
cu.Classes.Add(c);
}
c.UsingScope = currentNamespace;
currentClass.Push(c); // necessary for CreateReturnType
ConvertTemplates(outerClass, templates, c);
List<IParameter> p = new List<IParameter>();
if (parameters != null) {
foreach (AST.ParameterDeclarationExpression param in parameters) {
p.Add(CreateParameter(param));
}
}
AnonymousMethodReturnType.AddDefaultDelegateMethod(c, CreateReturnType(returnType), p);
currentClass.Pop();
}
IParameter CreateParameter(AST.ParameterDeclarationExpression par)
{
return CreateParameter(par, null);
}
IParameter CreateParameter(AST.ParameterDeclarationExpression par, IMethod method)
{
return CreateParameter(par, method, GetCurrentClass(), cu);
}
internal static IParameter CreateParameter(AST.ParameterDeclarationExpression par, IMethod method, IClass currentClass, ICompilationUnit cu)
{
IReturnType parType = CreateReturnType(par.TypeReference, method, currentClass, cu, TypeVisitor.ReturnTypeOptions.None);
DefaultParameter p = new DefaultParameter(par.ParameterName, parType, GetRegion(par.StartLocation, par.EndLocation));
p.Modifiers = (ParameterModifiers)par.ParamModifier;
return p;
}
public override object VisitMethodDeclaration(AST.MethodDeclaration methodDeclaration, object data)
{
DomRegion region = GetRegion(methodDeclaration.StartLocation, methodDeclaration.EndLocation);
DomRegion bodyRegion = GetRegion(methodDeclaration.EndLocation, methodDeclaration.Body != null ? methodDeclaration.Body.EndLocation : RefParser.Location.Empty);
DefaultClass currentClass = GetCurrentClass();
DefaultMethod method = new DefaultMethod(methodDeclaration.Name, null, ConvertModifier(methodDeclaration.Modifier), region, bodyRegion, currentClass);
method.Documentation = GetDocumentation(region.BeginLine, methodDeclaration.Attributes);
ConvertTemplates(methodDeclaration.Templates, method);
method.ReturnType = CreateReturnType(methodDeclaration.TypeReference, method, TypeVisitor.ReturnTypeOptions.None);
ConvertAttributes(methodDeclaration, method);
method.IsExtensionMethod = methodDeclaration.IsExtensionMethod
|| method.Attributes.Any(att => att.AttributeType != null && att.AttributeType.FullyQualifiedName == "System.Runtime.CompilerServices.ExtensionAttribute");
if (methodDeclaration.Parameters.Count > 0) {
foreach (AST.ParameterDeclarationExpression par in methodDeclaration.Parameters) {
method.Parameters.Add(CreateParameter(par, method));
}
} else {
method.Parameters = DefaultParameter.EmptyParameterList;
}
if (methodDeclaration.HandlesClause.Count > 0) {
foreach (string handlesClause in methodDeclaration.HandlesClause) {
if (handlesClause.ToLowerInvariant().StartsWith("me."))
method.HandlesClauses.Add(handlesClause.Substring(3));
else if (handlesClause.ToLowerInvariant().StartsWith("mybase."))
method.HandlesClauses.Add(handlesClause.Substring(7));
else
method.HandlesClauses.Add(handlesClause);
}
} else {
method.HandlesClauses = EmptyList<string>.Instance;
}
AddInterfaceImplementations(method, methodDeclaration);
currentClass.Methods.Add(method);
return null;
}
public override object VisitDeclareDeclaration(AST.DeclareDeclaration declareDeclaration, object data)
{
DefaultClass currentClass = GetCurrentClass();
DomRegion region = GetRegion(declareDeclaration.StartLocation, declareDeclaration.EndLocation);
DefaultMethod method = new DefaultMethod(declareDeclaration.Name, null, ConvertModifier(declareDeclaration.Modifier), region, DomRegion.Empty, currentClass);
method.Documentation = GetDocumentation(region.BeginLine, declareDeclaration.Attributes);
method.Modifiers |= ModifierEnum.Extern | ModifierEnum.Static;
method.ReturnType = CreateReturnType(declareDeclaration.TypeReference, method, TypeVisitor.ReturnTypeOptions.None);
ConvertAttributes(declareDeclaration, method);
foreach (AST.ParameterDeclarationExpression par in declareDeclaration.Parameters) {
method.Parameters.Add(CreateParameter(par, method));
}
currentClass.Methods.Add(method);
return null;
}
public override object VisitOperatorDeclaration(AST.OperatorDeclaration operatorDeclaration, object data)
{
DefaultClass c = GetCurrentClass();
DomRegion region = GetRegion(operatorDeclaration.StartLocation, operatorDeclaration.EndLocation);
DomRegion bodyRegion = GetRegion(operatorDeclaration.EndLocation, operatorDeclaration.Body != null ? operatorDeclaration.Body.EndLocation : RefParser.Location.Empty);
DefaultMethod method = new DefaultMethod(operatorDeclaration.Name, CreateReturnType(operatorDeclaration.TypeReference), ConvertModifier(operatorDeclaration.Modifier), region, bodyRegion, c);
method.Documentation = GetDocumentation(region.BeginLine, operatorDeclaration.Attributes);
ConvertAttributes(operatorDeclaration, method);
if(operatorDeclaration.Parameters != null)
{
foreach (AST.ParameterDeclarationExpression par in operatorDeclaration.Parameters) {
method.Parameters.Add(CreateParameter(par, method));
}
}
AddInterfaceImplementations(method, operatorDeclaration);
c.Methods.Add(method);
return null;
}
public override object VisitConstructorDeclaration(AST.ConstructorDeclaration constructorDeclaration, object data)
{
DomRegion region = GetRegion(constructorDeclaration.StartLocation, constructorDeclaration.EndLocation);
DomRegion bodyRegion = GetRegion(constructorDeclaration.EndLocation, constructorDeclaration.Body != null ? constructorDeclaration.Body.EndLocation : RefParser.Location.Empty);
DefaultClass c = GetCurrentClass();
Constructor constructor = new Constructor(ConvertModifier(constructorDeclaration.Modifier), region, bodyRegion, GetCurrentClass());
constructor.Documentation = GetDocumentation(region.BeginLine, constructorDeclaration.Attributes);
ConvertAttributes(constructorDeclaration, constructor);
if (constructorDeclaration.Parameters != null) {
foreach (AST.ParameterDeclarationExpression par in constructorDeclaration.Parameters) {
constructor.Parameters.Add(CreateParameter(par));
}
}
if (constructor.Modifiers.HasFlag(ModifierEnum.Static))
constructor.Modifiers = ConvertModifier(constructorDeclaration.Modifier, ModifierEnum.None);
c.Methods.Add(constructor);
return null;
}
public override object VisitDestructorDeclaration(AST.DestructorDeclaration destructorDeclaration, object data)
{
DomRegion region = GetRegion(destructorDeclaration.StartLocation, destructorDeclaration.EndLocation);
DomRegion bodyRegion = GetRegion(destructorDeclaration.EndLocation, destructorDeclaration.Body != null ? destructorDeclaration.Body.EndLocation : RefParser.Location.Empty);
DefaultClass c = GetCurrentClass();
Destructor destructor = new Destructor(region, bodyRegion, c);
ConvertAttributes(destructorDeclaration, destructor);
c.Methods.Add(destructor);
return null;
}
bool IsVisualBasic {
get {
return cu.ProjectContent.Language == LanguageProperties.VBNet;
}
}
public override object VisitFieldDeclaration(AST.FieldDeclaration fieldDeclaration, object data)
{
DomRegion region = GetRegion(fieldDeclaration.StartLocation, fieldDeclaration.EndLocation);
DefaultClass c = GetCurrentClass();
ModifierEnum modifier = ConvertModifier(fieldDeclaration.Modifier,
(c.ClassType == ClassType.Struct && this.IsVisualBasic)
? ModifierEnum.Public : ModifierEnum.Private);
string doku = GetDocumentation(region.BeginLine, fieldDeclaration.Attributes);
if (currentClass.Count > 0) {
for (int i = 0; i < fieldDeclaration.Fields.Count; ++i) {
AST.VariableDeclaration field = (AST.VariableDeclaration)fieldDeclaration.Fields[i];
IReturnType retType;
if (c.ClassType == ClassType.Enum) {
retType = c.DefaultReturnType;
} else {
retType = CreateReturnType(fieldDeclaration.GetTypeForField(i));
if (!field.FixedArrayInitialization.IsNull)
retType = new ArrayReturnType(cu.ProjectContent, retType, 1);
}
DefaultField f = new DefaultField(retType, field.Name, modifier, region, c);
ConvertAttributes(fieldDeclaration, f);
f.Documentation = doku;
if (c.ClassType == ClassType.Enum) {
f.Modifiers = ModifierEnum.Const | ModifierEnum.Public;
}
c.Fields.Add(f);
}
}
return null;
}
public override object VisitPropertyDeclaration(AST.PropertyDeclaration propertyDeclaration, object data)
{
DomRegion region = GetRegion(propertyDeclaration.StartLocation, propertyDeclaration.EndLocation);
DomRegion bodyRegion = GetRegion(propertyDeclaration.BodyStart, propertyDeclaration.BodyEnd);
IReturnType type = CreateReturnType(propertyDeclaration.TypeReference);
DefaultClass c = GetCurrentClass();
DefaultProperty property = new DefaultProperty(propertyDeclaration.Name, type, ConvertModifier(propertyDeclaration.Modifier), region, bodyRegion, GetCurrentClass());
if (propertyDeclaration.HasGetRegion) {
property.GetterRegion = GetRegion(propertyDeclaration.GetRegion.StartLocation, propertyDeclaration.GetRegion.EndLocation);
property.CanGet = true;
property.GetterModifiers = ConvertModifier(propertyDeclaration.GetRegion.Modifier, ModifierEnum.None);
}
if (propertyDeclaration.HasSetRegion) {
property.SetterRegion = GetRegion(propertyDeclaration.SetRegion.StartLocation, propertyDeclaration.SetRegion.EndLocation);
property.CanSet = true;
property.SetterModifiers = ConvertModifier(propertyDeclaration.SetRegion.Modifier, ModifierEnum.None);
}
property.Documentation = GetDocumentation(region.BeginLine, propertyDeclaration.Attributes);
ConvertAttributes(propertyDeclaration, property);
property.IsIndexer = propertyDeclaration.IsIndexer;
if (propertyDeclaration.Parameters != null) {
foreach (AST.ParameterDeclarationExpression par in propertyDeclaration.Parameters) {
property.Parameters.Add(CreateParameter(par));
}
}
// If an IndexerNameAttribute is specified, use the specified name
// for the indexer instead of the default name.
IAttribute indexerNameAttribute = property.Attributes.LastOrDefault(this.IsIndexerNameAttribute);
if (indexerNameAttribute != null && indexerNameAttribute.PositionalArguments.Count > 0) {
string name = indexerNameAttribute.PositionalArguments[0] as string;
if (!String.IsNullOrEmpty(name)) {
property.FullyQualifiedName = String.Concat(property.DeclaringType.FullyQualifiedName, ".", name);
}
}
AddInterfaceImplementations(property, propertyDeclaration);
c.Properties.Add(property);
return null;
}
bool IsIndexerNameAttribute(IAttribute att)
{
if (att == null || att.AttributeType == null)
return false;
string indexerNameAttributeFullName = typeof(System.Runtime.CompilerServices.IndexerNameAttribute).FullName;
IClass indexerNameAttributeClass = this.Cu.ProjectContent.GetClass(indexerNameAttributeFullName, 0, LanguageProperties.CSharp, GetClassOptions.Default | GetClassOptions.ExactMatch);
if (indexerNameAttributeClass == null) {
return String.Equals(att.AttributeType.FullyQualifiedName, indexerNameAttributeFullName, StringComparison.Ordinal);
}
return att.AttributeType.Equals(indexerNameAttributeClass.DefaultReturnType);
}
public override object VisitEventDeclaration(AST.EventDeclaration eventDeclaration, object data)
{
DomRegion region = GetRegion(eventDeclaration.StartLocation, eventDeclaration.EndLocation);
DomRegion bodyRegion = GetRegion(eventDeclaration.BodyStart, eventDeclaration.BodyEnd);
DefaultClass c = GetCurrentClass();
IReturnType type;
if (eventDeclaration.TypeReference.IsNull) {
DefaultClass del = new DefaultClass(cu, ClassType.Delegate,
ConvertModifier(eventDeclaration.Modifier),
region, c);
del.Modifiers |= ModifierEnum.Synthetic;
CreateDelegate(del, eventDeclaration.Name + "EventHandler",
new AST.TypeReference("System.Void", true),
new AST.TemplateDefinition[0],
eventDeclaration.Parameters);
type = del.DefaultReturnType;
} else {
type = CreateReturnType(eventDeclaration.TypeReference);
}
DefaultEvent e = new DefaultEvent(eventDeclaration.Name, type, ConvertModifier(eventDeclaration.Modifier), region, bodyRegion, c);
ConvertAttributes(eventDeclaration, e);
AddInterfaceImplementations(e, eventDeclaration);
c.Events.Add(e);
e.Documentation = GetDocumentation(region.BeginLine, eventDeclaration.Attributes);
if (eventDeclaration.HasAddRegion) {
e.AddMethod = new DefaultMethod(e.DeclaringType, "add_" + e.Name) {
Parameters = { new DefaultParameter("value", e.ReturnType, DomRegion.Empty) },
Region = GetRegion(eventDeclaration.AddRegion.StartLocation, eventDeclaration.AddRegion.EndLocation),
BodyRegion = GetRegion(eventDeclaration.AddRegion.Block.StartLocation, eventDeclaration.AddRegion.Block.EndLocation)
};
}
if (eventDeclaration.HasRemoveRegion) {
e.RemoveMethod = new DefaultMethod(e.DeclaringType, "remove_" + e.Name) {
Parameters = { new DefaultParameter("value", e.ReturnType, DomRegion.Empty) },
Region = GetRegion(eventDeclaration.RemoveRegion.StartLocation, eventDeclaration.RemoveRegion.EndLocation),
BodyRegion = GetRegion(eventDeclaration.RemoveRegion.Block.StartLocation, eventDeclaration.RemoveRegion.Block.EndLocation)
};
}
return null;
}
void AddInterfaceImplementations(AbstractMember member, AST.MemberNode memberNode)
{
member.InterfaceImplementations.AddRange(
memberNode.InterfaceImplementations
.Select(x => new ExplicitInterfaceImplementation(CreateReturnType(x.InterfaceType), x.MemberName))
);
if (!IsVisualBasic && member.InterfaceImplementations.Any()) {
member.Modifiers = ConvertModifier(memberNode.Modifier, ModifierEnum.None);
}
}
IReturnType CreateReturnType(AST.TypeReference reference, IMethod method, TypeVisitor.ReturnTypeOptions options)
{
return CreateReturnType(reference, method, GetCurrentClass(), cu, options);
}
static IReturnType CreateReturnType(AST.TypeReference reference, IMethod method, IClass currentClass, ICompilationUnit cu, TypeVisitor.ReturnTypeOptions options)
{
if (currentClass == null) {
return TypeVisitor.CreateReturnType(reference, new DefaultClass(cu, "___DummyClass"), method, 1, 1, cu.ProjectContent, options | TypeVisitor.ReturnTypeOptions.Lazy);
} else {
return TypeVisitor.CreateReturnType(reference, currentClass, method, currentClass.Region.BeginLine + 1, 1, cu.ProjectContent, options | TypeVisitor.ReturnTypeOptions.Lazy);
}
}
IReturnType CreateReturnType(AST.TypeReference reference)
{
return CreateReturnType(reference, null, TypeVisitor.ReturnTypeOptions.None);
}
}
}