diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/SimpleNameLookupTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/SimpleNameLookupTests.cs index 0ff2a51dca..f99f6c45c6 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/SimpleNameLookupTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/SimpleNameLookupTests.cs @@ -175,5 +175,42 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver Assert.AreEqual("System.String", result.Type.FullName); } + + [Test] + public void UnknownTypeTest() + { + string program = @"class A { + void Method($StringBuilder$ b) { + } +} +"; + UnknownIdentifierResolveResult result = Resolve(program); + Assert.AreEqual("StringBuilder", result.Identifier); + + Assert.AreSame(SharedTypes.UnknownType, result.Type); + } + + [Test, Ignore("not yet implemented (depends on distuishing types and expressions)")] + public void PropertyNameAmbiguousWithTypeName() + { + string program = @"class A { + public Color Color { get; set; } + + void Method() { + $ + } +} +class Color { public static readonly Color Empty = null; } +"; + TypeResolveResult trr = Resolve(program.Replace("$", "$Color$ c;")); + Assert.AreEqual("Color", trr.Type.Name); + + MemberResolveResult mrr = Resolve(program.Replace("$", "x = $Color$;")); + Assert.AreEqual("Color", mrr.Member.Name); + + Resolve(program.Replace("$", "$Color$ = Color.Empty;")); + Resolve(program.Replace("$", "Color = $Color$.Empty;")); + Resolve(program.Replace("$", "x = $Color$.ToString();")); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Dom/ComposedType.cs b/ICSharpCode.NRefactory/CSharp/Dom/ComposedType.cs index 339d57ca79..fcfad944e1 100644 --- a/ICSharpCode.NRefactory/CSharp/Dom/ComposedType.cs +++ b/ICSharpCode.NRefactory/CSharp/Dom/ComposedType.cs @@ -74,7 +74,7 @@ namespace ICSharpCode.NRefactory.CSharp b.Append('*', this.PointerRank); foreach (var arraySpecifier in this.ArraySpecifiers) { b.Append('['); - b.Append(',', arraySpecifier.Rank); + b.Append(',', arraySpecifier.Dimensions - 1); b.Append(']'); } return b.ToString(); @@ -92,8 +92,8 @@ namespace ICSharpCode.NRefactory.CSharp get { return (CSharpTokenNode)GetChildByRole (Roles.LBracket); } } - public int Rank { - get { return GetChildrenByRole(Roles.Comma).Count(); } + public int Dimensions { + get { return 1 + GetChildrenByRole(Roles.Comma).Count(); } } public CSharpTokenNode RBracket { diff --git a/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/AbstractMember.cs b/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/AbstractMember.cs index 0e42fa2b00..134068e76c 100644 --- a/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/AbstractMember.cs +++ b/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/AbstractMember.cs @@ -1,4 +1,4 @@ -// +// // AbstractMember.cs // // Author: @@ -28,7 +28,7 @@ namespace ICSharpCode.NRefactory.CSharp { public abstract class AbstractMember : AbstractMemberBase { - const int PrivateImplementationTypeRole = 100; + public const int PrivateImplementationTypeRole = 100; public DomNode ReturnType { get { diff --git a/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/EventDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/EventDeclaration.cs index 9c2eb19622..da253f649f 100644 --- a/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/EventDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/EventDeclaration.cs @@ -1,4 +1,4 @@ -// +// // EventDeclaration.cs // // Author: @@ -28,8 +28,9 @@ namespace ICSharpCode.NRefactory.CSharp { public class EventDeclaration : AbstractMember { - public const int EventAddRole = 100; - public const int EventRemoveRole = 101; + // AbstractMember.PrivateImplementationTypeRole is 100 + public const int EventAddRole = 101; + public const int EventRemoveRole = 102; public CSharpTokenNode LBrace { get { diff --git a/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/OperatorDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/OperatorDeclaration.cs index 3e58b82dec..52e58a3daf 100644 --- a/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/OperatorDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/OperatorDeclaration.cs @@ -1,4 +1,4 @@ -// +// // OperatorDeclaration.cs // // Author: @@ -68,8 +68,9 @@ namespace ICSharpCode.NRefactory.CSharp public class OperatorDeclaration : AbstractMember { - public const int OperatorKeywordRole = 100; - public const int OperatorTypeRole = 101; + // AbstractMember.PrivateImplementationTypeRole is 100 + public const int OperatorKeywordRole = 101; + public const int OperatorTypeRole = 102; public OperatorType OperatorType { get; diff --git a/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/PropertyDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/PropertyDeclaration.cs index fa777da524..4ab719a117 100644 --- a/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/PropertyDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Dom/TypeMembers/PropertyDeclaration.cs @@ -1,4 +1,4 @@ -// +// // PropertyDeclaration.cs // // Author: @@ -28,8 +28,9 @@ namespace ICSharpCode.NRefactory.CSharp { public class PropertyDeclaration : AbstractMember { - public const int PropertyGetRole = 100; - public const int PropertySetRole = 101; + // AbstractMember.PrivateImplementationTypeRole is 100 + public const int PropertyGetRole = 101; + public const int PropertySetRole = 102; public CSharpTokenNode LBrace { get { diff --git a/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs b/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs index d51e6c6f37..bafabf2d22 100644 --- a/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs @@ -3,8 +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; @@ -74,23 +74,18 @@ namespace ICSharpCode.NRefactory.CSharp public override IEntity VisitUsingDeclaration(UsingDeclaration usingDeclaration, object data) { - ITypeOrNamespaceReference r = null; - /*foreach (Identifier identifier in usingDeclaration.NameIdentifier.NameParts) { - if (r == null) { - // TODO: alias? - r = new SimpleTypeOrNamespaceReference(identifier.Name, null, currentTypeDefinition, usingScope, true); - } else { - r = new MemberTypeOrNamespaceReference(r, identifier.Name, null, currentTypeDefinition, usingScope); - } - }*/throw new NotImplementedException(); - if (r != null) - usingScope.Usings.Add(r); + ITypeOrNamespaceReference u = ConvertType(usingDeclaration.Import, true) as ITypeOrNamespaceReference; + if (u != null) + usingScope.Usings.Add(u); return null; } public override IEntity VisitUsingAliasDeclaration(UsingAliasDeclaration usingDeclaration, object data) { - throw new NotImplementedException(); + ITypeOrNamespaceReference u = ConvertType(usingDeclaration.Import, true) as ITypeOrNamespaceReference; + if (u != null) + usingScope.UsingAliases.Add(new KeyValuePair(usingDeclaration.Alias, u)); + return null; } #endregion @@ -275,7 +270,7 @@ namespace ICSharpCode.NRefactory.CSharp field.ReturnType = currentTypeDefinition; field.Accessibility = Accessibility.Public; field.IsStatic = true; - if (enumMemberDeclaration.Initializer != null) { + if (!enumMemberDeclaration.Initializer.IsNull) { field.ConstantValue = ConvertConstantValue(currentTypeDefinition, enumMemberDeclaration.Initializer); } else { throw new NotImplementedException(); @@ -304,7 +299,7 @@ namespace ICSharpCode.NRefactory.CSharp m.IsExtensionMethod = methodDeclaration.IsExtensionMethod; ConvertParameters(m.Parameters, methodDeclaration.Parameters); - if (methodDeclaration.PrivateImplementationType != null) { + if (!methodDeclaration.PrivateImplementationType.IsNull) { m.Accessibility = Accessibility.None; m.InterfaceImplementations.Add(ConvertInterfaceImplementation(methodDeclaration.PrivateImplementationType, m.Name)); } @@ -349,7 +344,7 @@ namespace ICSharpCode.NRefactory.CSharp DefaultMethod ctor = new DefaultMethod(currentTypeDefinition, isStatic ? ".cctor" : ".ctor"); ctor.EntityType = EntityType.Constructor; ctor.Region = MakeRegion(constructorDeclaration); - if (constructorDeclaration.Initializer != null) { + if (!constructorDeclaration.Initializer.IsNull) { ctor.BodyRegion = MakeRegion(constructorDeclaration.Initializer.StartLocation, constructorDeclaration.EndLocation); } else { ctor.BodyRegion = MakeRegion(constructorDeclaration.Body); @@ -403,7 +398,7 @@ namespace ICSharpCode.NRefactory.CSharp ApplyModifiers(p, propertyDeclaration.Modifiers); p.ReturnType = ConvertType(propertyDeclaration.ReturnType); ConvertAttributes(p.Attributes, propertyDeclaration.Attributes); - if (propertyDeclaration.PrivateImplementationType != null) { + if (!propertyDeclaration.PrivateImplementationType.IsNull) { p.Accessibility = Accessibility.None; p.InterfaceImplementations.Add(ConvertInterfaceImplementation(propertyDeclaration.PrivateImplementationType, p.Name)); } @@ -441,7 +436,7 @@ namespace ICSharpCode.NRefactory.CSharp e.ReturnType = ConvertType(eventDeclaration.ReturnType); ConvertAttributes(e.Attributes, eventDeclaration.Attributes); - if (eventDeclaration.PrivateImplementationType != null) { + if (!eventDeclaration.PrivateImplementationType.IsNull) { e.Accessibility = Accessibility.None; e.InterfaceImplementations.Add(ConvertInterfaceImplementation(eventDeclaration.PrivateImplementationType, e.Name)); } @@ -505,21 +500,96 @@ namespace ICSharpCode.NRefactory.CSharp #region Types static readonly GetClassTypeReference voidReference = new GetClassTypeReference("System.Void", 0); - internal static ITypeReference ConvertType(DomNode node) + ITypeReference ConvertType(DomNode node, bool isInUsingDeclaration = false) { - PrimitiveType f = node as PrimitiveType; - if (f != null) { - switch (f.Keyword) { + return ConvertType(node, currentTypeDefinition, currentMethod, usingScope, isInUsingDeclaration); + } + + internal static ITypeReference ConvertType(DomNode node, ITypeDefinition parentTypeDefinition, IMethod parentMethodDefinition, UsingScope parentUsingScope, bool isInUsingDeclaration) + { + SimpleType s = node as SimpleType; + if (s != null) { + List typeArguments = new List(); + foreach (var ta in s.TypeArguments) { + typeArguments.Add(ConvertType(ta, parentTypeDefinition, parentMethodDefinition, parentUsingScope, isInUsingDeclaration)); + } + if (s.IsQualifiedWithAlias) { + AliasNamespaceReference ar = new AliasNamespaceReference(s.AliasIdentifier.Name, parentUsingScope); + return new MemberTypeOrNamespaceReference(ar, s.Identifier, typeArguments, parentTypeDefinition, parentUsingScope); + } else { + if (typeArguments.Count == 0 && parentMethodDefinition != null) { + // SimpleTypeOrNamespaceReference doesn't support method type parameters, + // so we directly handle them here. + foreach (ITypeParameter tp in parentMethodDefinition.TypeParameters) { + if (tp.Name == s.Identifier) + return tp; + } + } + return new SimpleTypeOrNamespaceReference(s.Identifier, typeArguments, parentTypeDefinition, parentUsingScope, isInUsingDeclaration); + } + } + PrimitiveType p = node as PrimitiveType; + if (p != null) { + switch (p.Keyword) { case "string": return TypeCode.String.ToTypeReference(); case "int": return TypeCode.Int32.ToTypeReference(); case "uint": return TypeCode.UInt32.ToTypeReference(); + case "object": + return TypeCode.Object.ToTypeReference(); + case "bool": + return TypeCode.Boolean.ToTypeReference(); + case "sbyte": + return TypeCode.SByte.ToTypeReference(); + case "byte": + return TypeCode.Byte.ToTypeReference(); + case "short": + return TypeCode.Int16.ToTypeReference(); + case "ushort": + return TypeCode.UInt16.ToTypeReference(); + case "long": + return TypeCode.Int64.ToTypeReference(); + case "ulong": + return TypeCode.UInt64.ToTypeReference(); + case "float": + return TypeCode.Single.ToTypeReference(); + case "double": + return TypeCode.Double.ToTypeReference(); + case "decimal": + return TypeCode.Decimal.ToTypeReference(); case "void": return voidReference; + default: + return SharedTypes.UnknownType; + } + } + MemberType m = node as MemberType; + if (m != null) { + ITypeOrNamespaceReference t = ConvertType(m.Target, parentTypeDefinition, parentMethodDefinition, parentUsingScope, isInUsingDeclaration) as ITypeOrNamespaceReference; + if (t == null) + return SharedTypes.UnknownType; + List typeArguments = new List(); + foreach (var ta in m.TypeArguments) { + typeArguments.Add(ConvertType(ta, parentTypeDefinition, parentMethodDefinition, parentUsingScope, isInUsingDeclaration)); + } + return new MemberTypeOrNamespaceReference(t, m.Identifier, typeArguments, parentTypeDefinition, parentUsingScope); + } + ComposedType c = node as ComposedType; + if (c != null) { + ITypeReference t = ConvertType(c.BaseType, parentTypeDefinition, parentMethodDefinition, parentUsingScope, isInUsingDeclaration); + if (c.HasNullableSpecifier) { + t = NullableType.Create(t); + } + for (int i = 0; i < c.PointerRank; i++) { + t = PointerTypeReference.Create(t); + } + foreach (var a in c.ArraySpecifiers.Reverse()) { + t = ArrayTypeReference.Create(t, a.Dimensions); } } + Debug.WriteLine("Unknown node used as type: " + node); return SharedTypes.UnknownType; } #endregion diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs index f0c0ff800d..a67fc0dd81 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs @@ -945,10 +945,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver if (initializerExpression != null && IsVar(type)) { return new VarTypeReference(this, resolver.Clone(), initializerExpression, isForEach); } else { - return TypeSystemConvertVisitor.ConvertType(type); + return MakeTypeReference(type); } } + ITypeReference MakeTypeReference(DomNode type) + { + return TypeSystemConvertVisitor.ConvertType(type, resolver.CurrentTypeDefinition, resolver.CurrentMember as IMethod, resolver.UsingScope, false); + } + static bool IsVar(DomNode returnType) { return returnType is IdentifierExpression && ((IdentifierExpression)returnType).Identifier == "var"; @@ -1055,12 +1060,26 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver #region Type References public override ResolveResult VisitPrimitiveType(PrimitiveType primitiveType, object data) { - return null; + ScanChildren(primitiveType); + return new TypeResolveResult(MakeTypeReference(primitiveType).Resolve(resolver.Context)); + } + + public override ResolveResult VisitSimpleType(SimpleType simpleType, object data) + { + ScanChildren(simpleType); + return new TypeResolveResult(MakeTypeReference(simpleType).Resolve(resolver.Context)); + } + + public override ResolveResult VisitMemberType(MemberType memberType, object data) + { + ScanChildren(memberType); + return new TypeResolveResult(MakeTypeReference(memberType).Resolve(resolver.Context)); } public override ResolveResult VisitComposedType(ComposedType composedType, object data) { - return null; + ScanChildren(composedType); + return new TypeResolveResult(MakeTypeReference(composedType).Resolve(resolver.Context)); } #endregion