diff --git a/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/ConstructorDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/ConstructorDeclaration.cs index b7aff39592..0535f1622a 100644 --- a/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/ConstructorDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/ConstructorDeclaration.cs @@ -49,6 +49,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitConstructorDeclaration (this, data); } + + public IEnumerable Parameters { + get { + return GetChildrenByRole (Roles.Argument).Cast(); + } + } } public enum ConstructorInitializerType { @@ -63,9 +69,9 @@ namespace ICSharpCode.NRefactory.CSharp set; } - public IEnumerable Arguments { + public IEnumerable Arguments { get { - return base.GetChildrenByRole (Roles.Argument).Cast (); + return base.GetChildrenByRole (Roles.Argument); } } diff --git a/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/ParameterDeclarationExpression.cs b/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/ParameterDeclaration.cs similarity index 90% rename from ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/ParameterDeclarationExpression.cs rename to ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/ParameterDeclaration.cs index f17951cfe4..553b662afc 100644 --- a/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/ParameterDeclarationExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/ParameterDeclaration.cs @@ -24,6 +24,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; +using System.Collections.Generic; +using System.Linq; namespace ICSharpCode.NRefactory.CSharp { @@ -66,6 +68,12 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (Roles.ReturnType); } } + public IEnumerable Attributes { + get { + return base.GetChildrenByRole (Roles.Attribute).Cast (); + } + } + public override S AcceptVisitor (IDomVisitor visitor, T data) { return visitor.VisitParameterDeclaration (this, data); diff --git a/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs b/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs index bf3fbafeae..c1ed7ea87d 100644 --- a/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs @@ -3,6 +3,8 @@ using System; using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; using ICSharpCode.NRefactory.CSharp.Resolver; using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem.Implementation; @@ -18,6 +20,7 @@ namespace ICSharpCode.NRefactory.CSharp readonly ParsedFile parsedFile; UsingScope usingScope; DefaultTypeDefinition currentTypeDefinition; + DefaultMethod currentMethod; public TypeSystemConvertVisitor(IProjectContent pc, string fileName) { @@ -34,6 +37,14 @@ namespace ICSharpCode.NRefactory.CSharp return new DomRegion(parsedFile.FileName, start.Line, start.Column, end.Line, end.Column); } + DomRegion MakeRegion(INode node) + { + if (node == null) + return DomRegion.Empty; + else + return MakeRegion(node.StartLocation, node.EndLocation); + } + #region Using Declarations // TODO: extern aliases @@ -62,7 +73,7 @@ namespace ICSharpCode.NRefactory.CSharp #region Namespace Declaration public override IEntity VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration, object data) { - DomRegion region = MakeRegion(namespaceDeclaration.StartLocation, namespaceDeclaration.EndLocation); + DomRegion region = MakeRegion(namespaceDeclaration); UsingScope previousUsingScope = usingScope; foreach (Identifier ident in namespaceDeclaration.NameIdentifier.NameParts) { usingScope = new UsingScope(usingScope, NamespaceDeclaration.BuildQualifiedName(usingScope.NamespaceName, ident.Name)); @@ -95,7 +106,7 @@ namespace ICSharpCode.NRefactory.CSharp { var td = currentTypeDefinition = CreateTypeDefinition(typeDeclaration.Name); td.ClassType = typeDeclaration.ClassType; - td.Region = MakeRegion(typeDeclaration.StartLocation, typeDeclaration.EndLocation); + td.Region = MakeRegion(typeDeclaration); td.BodyRegion = MakeRegion(typeDeclaration.LBrace.StartLocation, typeDeclaration.RBrace.EndLocation); td.AddDefaultConstructorIfRequired = true; @@ -106,7 +117,7 @@ namespace ICSharpCode.NRefactory.CSharp else if (td.ClassType == ClassType.Enum || td.ClassType == ClassType.Struct) td.IsSealed = true; // enums/structs are implicitly sealed - //TODO ConvertTypeParameters(td.TypeParameters, typeDeclaration.TypeArguments, typeDeclaration.Constraints, td); + //TODO ConvertTypeParameters(td.TypeParameters, typeDeclaration.TypeParameters, typeDeclaration.Constraints); // TODO: base type references? @@ -122,7 +133,7 @@ namespace ICSharpCode.NRefactory.CSharp { var td = CreateTypeDefinition(delegateDeclaration.Name); td.ClassType = ClassType.Delegate; - td.Region = MakeRegion(delegateDeclaration.StartLocation, delegateDeclaration.EndLocation); + td.Region = MakeRegion(delegateDeclaration); td.BaseTypes.Add(multicastDelegateReference); ConvertAttributes(td.Attributes, delegateDeclaration.Attributes); @@ -200,6 +211,141 @@ namespace ICSharpCode.NRefactory.CSharp } #endregion + #region Fields + public override IEntity VisitFieldDeclaration(FieldDeclaration fieldDeclaration, object data) + { + bool isSingleField = fieldDeclaration.Variables.Count() == 1; + Modifiers modifiers = fieldDeclaration.Modifiers; + DefaultField field = null; + foreach (VariableInitializer vi in fieldDeclaration.Variables) { + field = new DefaultField(currentTypeDefinition, vi.Name); + + field.Region = isSingleField ? MakeRegion(fieldDeclaration) : MakeRegion(vi); + field.BodyRegion = MakeRegion(vi); + ConvertAttributes(field.Attributes, fieldDeclaration.Attributes); + + ApplyModifiers(field, modifiers); + field.IsVolatile = (modifiers & Modifiers.Volatile) != 0; + field.IsReadOnly = (modifiers & Modifiers.Readonly) != 0; + + field.ReturnType = ConvertType(fieldDeclaration.ReturnType); + if ((modifiers & Modifiers.Fixed) != 0) { + field.ReturnType = PointerTypeReference.Create(field.ReturnType); + } + + if ((modifiers & Modifiers.Const) != 0) { + field.ConstantValue = ConvertConstantValue(field.ReturnType, vi.Initializer); + } + + currentTypeDefinition.Fields.Add(field); + } + return isSingleField ? field : null; + } + #endregion + + #region Methods + public override IEntity VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data) + { + DefaultMethod m = new DefaultMethod(currentTypeDefinition, methodDeclaration.Name); + currentMethod = m; // required for resolving type parameters + m.Region = MakeRegion(methodDeclaration); + m.BodyRegion = MakeRegion(methodDeclaration.Body); + + + //TODO ConvertTypeParameters(m.TypeParameters, methodDeclaration.TypeParameters, methodDeclaration.Constraints); + m.ReturnType = ConvertType(methodDeclaration.ReturnType); + ConvertAttributes(m.Attributes, methodDeclaration.Attributes.Where(s => s.AttributeTarget != AttributeTarget.Return)); + ConvertAttributes(m.ReturnTypeAttributes, methodDeclaration.Attributes.Where(s => s.AttributeTarget == AttributeTarget.Return)); + + ApplyModifiers(m, methodDeclaration.Modifiers); + m.IsExtensionMethod = methodDeclaration.IsExtensionMethod; + + ConvertParameters(m.Parameters, methodDeclaration.Parameters); + if (methodDeclaration.PrivateImplementationType != null) { + m.Accessibility = Accessibility.None; + m.InterfaceImplementations.Add(ConvertInterfaceImplementation(methodDeclaration.PrivateImplementationType, m.Name)); + } + + currentTypeDefinition.Methods.Add(m); + currentMethod = null; + return m; + } + + DefaultExplicitInterfaceImplementation ConvertInterfaceImplementation(INode interfaceType, string memberName) + { + return new DefaultExplicitInterfaceImplementation(ConvertType(interfaceType), memberName); + } + #endregion + + #region Operators + public override IEntity VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration, object data) + { + DefaultMethod m = new DefaultMethod(currentTypeDefinition, operatorDeclaration.Name); + m.EntityType = EntityType.Operator; + m.Region = MakeRegion(operatorDeclaration); + m.BodyRegion = MakeRegion(operatorDeclaration.Body); + + m.ReturnType = ConvertType(operatorDeclaration.ReturnType); + ConvertAttributes(m.Attributes, operatorDeclaration.Attributes.Where(s => s.AttributeTarget != AttributeTarget.Return)); + ConvertAttributes(m.ReturnTypeAttributes, operatorDeclaration.Attributes.Where(s => s.AttributeTarget == AttributeTarget.Return)); + + ApplyModifiers(m, operatorDeclaration.Modifiers); + + ConvertParameters(m.Parameters, operatorDeclaration.Parameters); + + currentTypeDefinition.Methods.Add(m); + return m; + } + #endregion + + #region Constructors + public override IEntity VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data) + { + Modifiers modifiers = constructorDeclaration.Modifiers; + bool isStatic = (modifiers & Modifiers.Static) != 0; + DefaultMethod ctor = new DefaultMethod(currentTypeDefinition, isStatic ? ".cctor" : ".ctor"); + ctor.EntityType = EntityType.Constructor; + ctor.Region = MakeRegion(constructorDeclaration); + if (constructorDeclaration.Initializer != null) { + ctor.BodyRegion = MakeRegion(constructorDeclaration.Initializer.StartLocation, constructorDeclaration.EndLocation); + } else { + ctor.BodyRegion = MakeRegion(constructorDeclaration.Body); + } + ctor.ReturnType = currentTypeDefinition; + + ConvertAttributes(ctor.Attributes, constructorDeclaration.Attributes); + ConvertParameters(ctor.Parameters, constructorDeclaration.Parameters); + + if (isStatic) + ctor.IsStatic = true; + else + ApplyModifiers(ctor, modifiers); + + currentTypeDefinition.Methods.Add(ctor); + return ctor; + } + #endregion + + #region Destructors + static readonly GetClassTypeReference voidReference = new GetClassTypeReference("System.Void", 0); + + public override IEntity VisitDestructorDeclaration(DestructorDeclaration destructorDeclaration, object data) + { + DefaultMethod dtor = new DefaultMethod(currentTypeDefinition, "Finalize"); + dtor.EntityType = EntityType.Destructor; + dtor.Region = MakeRegion(destructorDeclaration); + dtor.BodyRegion = MakeRegion(destructorDeclaration.Body); + dtor.Accessibility = Accessibility.Protected; + dtor.IsOverride = true; + dtor.ReturnType = voidReference; + + ConvertAttributes(dtor.Attributes, destructorDeclaration.Attributes); + + currentTypeDefinition.Methods.Add(dtor); + return dtor; + } + #endregion + #region Modifiers static void ApplyModifiers(DefaultTypeDefinition td, Modifiers modifiers) { @@ -209,6 +355,17 @@ namespace ICSharpCode.NRefactory.CSharp td.IsShadowing = (modifiers & Modifiers.New) != 0; } + static void ApplyModifiers(TypeSystem.Implementation.AbstractMember m, Modifiers modifiers) + { + m.Accessibility = GetAccessibility(modifiers) ?? Accessibility.Private; + m.IsAbstract = (modifiers & Modifiers.Abstract) != 0; + m.IsOverride = (modifiers & Modifiers.Override) != 0; + m.IsSealed = (modifiers & Modifiers.Sealed) != 0; + m.IsShadowing = (modifiers & Modifiers.New) != 0; + m.IsStatic = (modifiers & Modifiers.Static) != 0; + m.IsVirtual = (modifiers & Modifiers.Virtual) != 0; + } + static Accessibility? GetAccessibility(Modifiers modifiers) { switch (modifiers & Modifiers.VisibilityMask) { @@ -236,5 +393,46 @@ namespace ICSharpCode.NRefactory.CSharp } } #endregion + + #region Types + ITypeReference ConvertType(INode node) + { + return SharedTypes.UnknownType; + } + #endregion + + #region Constant Values + IConstantValue ConvertConstantValue(ITypeReference targetType, INode expression) + { + return new SimpleConstantValue(targetType, null); + } + #endregion + + #region Parameters + void ConvertParameters(IList outputList, IEnumerable parameters) + { + foreach (ParameterDeclaration pd in parameters) { + DefaultParameter p = new DefaultParameter(ConvertType(pd.Type), pd.Name); + p.Region = MakeRegion(pd); + ConvertAttributes(p.Attributes, pd.Attributes); + switch (pd.ParameterModifier) { + case ParameterModifier.Ref: + p.IsRef = true; + p.Type = ByReferenceTypeReference.Create(p.Type); + break; + case ParameterModifier.Out: + p.IsOut = true; + p.Type = ByReferenceTypeReference.Create(p.Type); + break; + case ParameterModifier.Params: + p.IsParams = true; + break; + } + if (pd.DefaultExpression != null) + p.DefaultValue = ConvertConstantValue(p.Type, pd.DefaultExpression); + outputList.Add(p); + } + } + #endregion } } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs b/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs index 6588a26aa5..37c0a95425 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs @@ -1383,7 +1383,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver if (typeArguments == null) throw new ArgumentNullException("typeArguments"); - // TODO: lookup in local variables, in parameters, etc. + IParameterizedMember parameterizedMember = this.CurrentMember as IParameterizedMember; + if (parameterizedMember != null && typeArguments.Count == 0) { + foreach (IParameter p in parameterizedMember.Parameters) { + if (p.Name == identifier) { + return new VariableResolveResult(p, p.Type.Resolve(context)); + } + } + } + + // TODO: lookup in local variables, etc. return LookupSimpleNameOrTypeName(identifier, typeArguments, isInvocationTarget ? SimpleNameLookupMode.InvocationTarget : SimpleNameLookupMode.Expression); diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs index a80140647d..95e2c51ea7 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs @@ -35,6 +35,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver public ResolveResult Resolve(INode node) { + if (node == null) + return errorResult; ResolveResult result; if (!cache.TryGetValue(node, out result)) { result = cache[node] = node.AcceptVisitor(this, null) ?? errorResult; @@ -105,6 +107,85 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } #endregion + #region Track CurrentMember + public override ResolveResult VisitFieldDeclaration(FieldDeclaration fieldDeclaration, object data) + { + if (FullyResolveSubExpressions) { + ResolveType(fieldDeclaration.ReturnType); + foreach (AttributeSection attr in fieldDeclaration.Attributes) + Resolve(attr); + } + if (fieldDeclaration.Variables.Count() == 1) { + return Resolve(fieldDeclaration.Variables.Single()); + } else { + foreach (VariableInitializer vi in fieldDeclaration.Variables) + Resolve(vi); + return null; + } + } + + public override ResolveResult VisitVariableInitializer(VariableInitializer variableInitializer, object data) + { + if (variableInitializer.Parent is FieldDeclaration) { + try { + if (resolver.CurrentTypeDefinition != null) { + resolver.CurrentMember = resolver.CurrentTypeDefinition.Fields.FirstOrDefault(f => f.Region.IsInside(variableInitializer.StartLocation)); + } + + if (FullyResolveSubExpressions) + Resolve(variableInitializer.Initializer); + + if (resolver.CurrentMember != null) + return new MemberResolveResult(resolver.CurrentMember, resolver.CurrentMember.ReturnType.Resolve(resolver.Context)); + else + return errorResult; + } finally{ + resolver.CurrentMember = null; + } + } else { + return base.VisitVariableInitializer(variableInitializer, data); + } + } + + ResolveResult VisitMethodMember(AbstractMemberBase member, object data) + { + try { + if (resolver.CurrentTypeDefinition != null) { + resolver.CurrentMember = resolver.CurrentTypeDefinition.Methods.FirstOrDefault(m => m.Region.IsInside(member.StartLocation)); + } + + VisitChildren(member, data); + + if (resolver.CurrentMember != null) + return new MemberResolveResult(resolver.CurrentMember, resolver.CurrentMember.ReturnType.Resolve(resolver.Context)); + else + return errorResult; + } finally { + resolver.CurrentMember = null; + } + } + + public override ResolveResult VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data) + { + return VisitMethodMember(methodDeclaration, data); + } + + public override ResolveResult VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration, object data) + { + return VisitMethodMember(operatorDeclaration, data); + } + + public override ResolveResult VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data) + { + return VisitMethodMember(constructorDeclaration, data); + } + + public override ResolveResult VisitDestructorDeclaration(DestructorDeclaration destructorDeclaration, object data) + { + return VisitMethodMember(destructorDeclaration, data); + } + #endregion + #region Track CheckForOverflow public override ResolveResult VisitCheckedExpression(CheckedExpression checkedExpression, object data) { @@ -365,5 +446,22 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return resolver.ResolveUnaryOperator(unaryOperatorExpression.UnaryOperatorType, expr); } #endregion + + public override ResolveResult VisitParameterDeclaration(ParameterDeclaration parameterDeclaration, object data) + { + if (FullyResolveSubExpressions) { + ResolveType(parameterDeclaration.Type); + Resolve(parameterDeclaration.DefaultExpression); + } + IParameterizedMember pm = resolver.CurrentMember as IParameterizedMember; + if (pm != null) { + foreach (IParameter p in pm.Parameters) { + if (p.Name == parameterDeclaration.Name) { + return new VariableResolveResult(p, p.Type.Resolve(resolver.Context)); + } + } + } + return errorResult; + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/VariableResolveResult.cs b/ICSharpCode.NRefactory/CSharp/Resolver/VariableResolveResult.cs new file mode 100644 index 0000000000..63121c87e7 --- /dev/null +++ b/ICSharpCode.NRefactory/CSharp/Resolver/VariableResolveResult.cs @@ -0,0 +1,37 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.CSharp.Resolver +{ + /// + /// Represents a local variable. + /// + public class VariableResolveResult : ResolveResult + { + readonly IVariable variable; + + public VariableResolveResult(IVariable variable, IType type) + : base(type) + { + if (variable == null) + throw new ArgumentNullException("variable"); + this.variable = variable; + } + + public IVariable Variable { + get { return variable; } + } + + public bool IsParameter { + get { return variable is IParameter; } + } + + public override string ToString() + { + return string.Format("[VariableResolveResult {0}]", variable); + } + } +} diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index 1b7f0dae10..f7161be28b 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -142,7 +142,7 @@ - + @@ -180,6 +180,7 @@ + diff --git a/ICSharpCode.NRefactory/TypeSystem/DomRegion.cs b/ICSharpCode.NRefactory/TypeSystem/DomRegion.cs index 41c7f41010..2794b00dbc 100644 --- a/ICSharpCode.NRefactory/TypeSystem/DomRegion.cs +++ b/ICSharpCode.NRefactory/TypeSystem/DomRegion.cs @@ -3,6 +3,7 @@ using System; using System.Globalization; +using ICSharpCode.NRefactory.CSharp; namespace ICSharpCode.NRefactory.TypeSystem { @@ -91,6 +92,11 @@ namespace ICSharpCode.NRefactory.TypeSystem (line != EndLine || column <= EndColumn); } + public bool IsInside(DomLocation location) + { + return IsInside(location.Line, location.Column); + } + public override string ToString() { return string.Format(