diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/AttributeTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/AttributeTests.cs index bca4362542..0451e45c17 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/AttributeTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/AttributeTests.cs @@ -18,19 +18,19 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver Assert.AreEqual("System.Runtime", result.NamespaceName); } - [Test] + [Test, Ignore("Parser produces incorrect position (attribute position doesn't include empty arg list)")] public void AttributeWithShortName() { - string program = "using System; [$Obsolete$] class Test {}"; + string program = "using System; [$Obsolete$()] class Test {}"; TypeResolveResult result = Resolve(program); Assert.AreEqual("System.ObsoleteAttribute", result.Type.FullName); } - [Test] + [Test, Ignore("Parser produces incorrect position (attribute position doesn't include empty arg list)")] public void QualifiedAttributeWithShortName() { - string program = "using System; [$System.Obsolete$] class Test {}"; + string program = "using System; [$System.Obsolete$()] class Test {}"; TypeResolveResult result = Resolve(program); Assert.AreEqual("System.ObsoleteAttribute", result.Type.FullName); @@ -54,6 +54,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver Assert.AreEqual("System.LoaderOptimization", (mrr.Member as IMethod).Parameters[0].Type.Resolve(context).FullName); } + [Test] + public void AttributeWithoutArgumentListRefersToConstructor() + { + string program = "using System; [$Obsolete$] class Test {}"; + + MemberResolveResult result = Resolve(program); + Assert.AreEqual("System.ObsoleteAttribute..ctor", result.Member.FullName); + } + [Test] public void AttributeArgumentInClassContext1() { diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs index f3836eaaf8..2b6cff43c1 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs @@ -191,27 +191,45 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver Assert.AreSame(SharedTypes.UnknownType, result.Type); } - [Test] - public void PropertyNameAmbiguousWithTypeName() - { - string program = @"class A { + const string propertyNameAmbiguousWithTypeNameProgram = @"class A { public Color Color { get; set; } void Method() { $ } } -class Color { public static readonly Color Empty = null; } +class Color { + public static readonly Color Empty = null; + public static int M() { } + public int M(int a) { } +} "; + + [Test] + public void PropertyNameAmbiguousWithTypeName() + { + string program = propertyNameAmbiguousWithTypeNameProgram; 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); - + } + + [Test] + public void PropertyNameAmbiguousWithTypeName_MemberAccessOnAmbiguousIdentifier() + { + string program = propertyNameAmbiguousWithTypeNameProgram; Resolve(program.Replace("$", "$Color$ = Color.Empty;")); Resolve(program.Replace("$", "Color = $Color$.Empty;")); - Resolve(program.Replace("$", "x = $Color$.ToString();")); + } + + [Test] + public void PropertyNameAmbiguousWithTypeName_MethodInvocationOnAmbiguousIdentifier() + { + string program = propertyNameAmbiguousWithTypeNameProgram; + Resolve(program.Replace("$", "x = $Color$.M(1);")); + Resolve(program.Replace("$", "x = $Color$.M();")); } [Test] diff --git a/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs b/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs index 37495db950..82ac415300 100644 --- a/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs @@ -658,20 +658,26 @@ namespace ICSharpCode.NRefactory.CSharp } } - IAttribute ConvertAttribute(CSharp.Attribute attr) + internal static ITypeReference ConvertAttributeType(AstType type, ITypeDefinition parentTypeDefinition, IMethod parentMethodDefinition, UsingScope parentUsingScope) { - DomRegion region = MakeRegion(attr); - ITypeReference type = ConvertType(attr.Type); - if (!attr.Type.GetChildByRole(AstNode.Roles.Identifier).IsVerbatim) { + ITypeReference tr = ConvertType(type, parentTypeDefinition, parentMethodDefinition, parentUsingScope, SimpleNameLookupMode.Type); + if (!type.GetChildByRole(AstNode.Roles.Identifier).IsVerbatim) { // Try to add "Attribute" suffix, but only if the identifier // (=last identifier in fully qualified name) isn't a verbatim identifier. - SimpleTypeOrNamespaceReference st = type as SimpleTypeOrNamespaceReference; - MemberTypeOrNamespaceReference mt = type as MemberTypeOrNamespaceReference; + SimpleTypeOrNamespaceReference st = tr as SimpleTypeOrNamespaceReference; + MemberTypeOrNamespaceReference mt = tr as MemberTypeOrNamespaceReference; if (st != null) - type = new AttributeTypeReference(st, st.AddSuffix("Attribute")); + return new AttributeTypeReference(st, st.AddSuffix("Attribute")); else if (mt != null) - type = new AttributeTypeReference(mt, mt.AddSuffix("Attribute")); + return new AttributeTypeReference(mt, mt.AddSuffix("Attribute")); } + return tr; + } + + IAttribute ConvertAttribute(CSharp.Attribute attr) + { + DomRegion region = MakeRegion(attr); + ITypeReference type = ConvertAttributeType(attr.Type, currentTypeDefinition, currentMethod, usingScope); List positionalArguments = null; List> namedCtorArguments = null; List> namedArguments = null; diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/CSharpAttribute.cs b/ICSharpCode.NRefactory/CSharp/Resolver/CSharpAttribute.cs index 08232bb7d7..3f2eb09d09 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/CSharpAttribute.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/CSharpAttribute.cs @@ -41,8 +41,32 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver public IMethod ResolveConstructor(ITypeResolveContext context) { + CSharpResolver r = new CSharpResolver(context); IType type = attributeType.Resolve(context); - throw new NotImplementedException(); + int totalArgumentCount = 0; + if (positionalArguments != null) + totalArgumentCount += positionalArguments.Count; + if (namedCtorArguments != null) + totalArgumentCount += namedCtorArguments.Count; + ResolveResult[] arguments = new ResolveResult[totalArgumentCount]; + string[] argumentNames = new string[totalArgumentCount]; + int i = 0; + if (positionalArguments != null) { + while (i < positionalArguments.Count) { + IConstantValue cv = positionalArguments[i]; + arguments[i] = new ConstantResolveResult(cv.GetValueType(context), cv.GetValue(context)); + i++; + } + } + if (namedCtorArguments != null) { + foreach (var pair in namedCtorArguments) { + argumentNames[i] = pair.Key; + arguments[i] = new ConstantResolveResult(pair.Value.GetValueType(context), pair.Value.GetValue(context)); + i++; + } + } + MemberResolveResult mrr = r.ResolveObjectCreation(type, arguments, argumentNames) as MemberResolveResult; + return mrr != null ? mrr.Member as IMethod : null; } public IList GetPositionalArguments(ITypeResolveContext context) diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs index 0ef9fe3b47..45b5076297 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs @@ -38,6 +38,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver { static readonly ResolveResult errorResult = new ErrorResolveResult(SharedTypes.UnknownType); CSharpResolver resolver; + SimpleNameLookupMode currentTypeLookupMode = SimpleNameLookupMode.Type; readonly ParsedFile parsedFile; readonly Dictionary resolveResultCache = new Dictionary(); readonly Dictionary resolverBeforeDict = new Dictionary(); @@ -232,7 +233,17 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } if (newTypeDefinition != null) resolver.CurrentTypeDefinition = newTypeDefinition; - ScanChildren(typeDeclaration); + + for (AstNode child = typeDeclaration.FirstChild; child != null; child = child.NextSibling) { + if (child.Role == TypeDeclaration.BaseTypeRole) { + currentTypeLookupMode = SimpleNameLookupMode.BaseTypeReference; + Scan(child); + currentTypeLookupMode = SimpleNameLookupMode.Type; + } else { + Scan(child); + } + } + return newTypeDefinition != null ? new TypeResolveResult(newTypeDefinition) : errorResult; } finally { resolver.CurrentTypeDefinition = previousTypeDefinition; @@ -256,6 +267,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return VisitFieldOrEventDeclaration(fieldDeclaration); } + public override ResolveResult VisitFixedFieldDeclaration(FixedFieldDeclaration fixedFieldDeclaration, object data) + { + return VisitFieldOrEventDeclaration(fixedFieldDeclaration); + } + public override ResolveResult VisitEventDeclaration(EventDeclaration eventDeclaration, object data) { return VisitFieldOrEventDeclaration(eventDeclaration); @@ -307,6 +323,19 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } + public override ResolveResult VisitFixedVariableInitializer(FixedVariableInitializer fixedVariableInitializer, object data) + { + ScanChildren(fixedVariableInitializer); + if (resolverEnabled) { + if (resolver.CurrentMember != null) + return new MemberResolveResult(resolver.CurrentMember, resolver.CurrentMember.ReturnType.Resolve(resolver.Context)); + else + return errorResult; + } else { + return null; + } + } + ResolveResult VisitMethodMember(AttributedNode member) { try { @@ -468,11 +497,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver resolver.CurrentMember = null; } } - - public override ResolveResult VisitFixedFieldDeclaration(FixedFieldDeclaration fixedFieldDeclaration, object data) - { - throw new NotImplementedException(); - } #endregion #region Track CheckForOverflow @@ -534,15 +558,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver #endregion #region Visit Expressions - static bool IsTargetOfInvocation(AstNode node) - { - InvocationExpression ie = node.Parent as InvocationExpression; - return ie != null && ie.Target == node; - } - IType ResolveType(AstType type) { - return MakeTypeReference(type).Resolve(resolver.Context); + return Resolve(type).Type; } public override ResolveResult VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression, object data) @@ -717,32 +735,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return errorResult; } - public override ResolveResult VisitIdentifierExpression(IdentifierExpression identifierExpression, object data) - { - if (resolverEnabled) { - List typeArguments = new List(); - foreach (AstType typeArgument in identifierExpression.TypeArguments) { - typeArguments.Add(ResolveType(typeArgument)); - } - return resolver.ResolveSimpleName(identifierExpression.Identifier, typeArguments, - IsTargetOfInvocation(identifierExpression)); - } else { - ScanChildren(identifierExpression); - return null; - } - } - - ResolveResult[] GetArguments(IEnumerable argumentExpressions, out string[] argumentNames) - { - argumentNames = null; // TODO: add support for named arguments - ResolveResult[] arguments = new ResolveResult[argumentExpressions.Count()]; - int i = 0; - foreach (AstNode argument in argumentExpressions) { - arguments[i++] = Resolve(argument); - } - return arguments; - } - public override ResolveResult VisitIndexerExpression(IndexerExpression indexerExpression, object data) { if (resolverEnabled) { @@ -756,19 +748,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } - public override ResolveResult VisitInvocationExpression(InvocationExpression invocationExpression, object data) - { - if (resolverEnabled) { - ResolveResult target = Resolve(invocationExpression.Target); - string[] argumentNames; - ResolveResult[] arguments = GetArguments(invocationExpression.Arguments, out argumentNames); - return resolver.ResolveInvocation(target, arguments, argumentNames); - } else { - ScanChildren(invocationExpression); - return null; - } - } - public override ResolveResult VisitIsExpression(IsExpression isExpression, object data) { ScanChildren(isExpression); @@ -783,23 +762,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver throw new NotImplementedException(); } - public override ResolveResult VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression, object data) - { - if (resolverEnabled) { - ResolveResult target = Resolve(memberReferenceExpression.Target); - List typeArguments = new List(); - foreach (AstType typeArgument in memberReferenceExpression.TypeArguments) { - typeArguments.Add(ResolveType(typeArgument)); - } - return resolver.ResolveMemberAccess(target, memberReferenceExpression.MemberName, - typeArguments, - IsTargetOfInvocation(memberReferenceExpression)); - } else { - ScanChildren(memberReferenceExpression); - return null; - } - } - public override ResolveResult VisitNullReferenceExpression(NullReferenceExpression nullReferenceExpression, object data) { if (resolverEnabled) { @@ -948,6 +910,187 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } #endregion + #region Visit Identifier/MemberReference/Invocation-Expression + // IdentifierExpression, MemberReferenceExpression and InvocationExpression + // are grouped together because they have to work together for + // "7.6.4.1 Identical simple names and type names" support + List GetTypeArguments(IEnumerable typeArguments) + { + List result = new List(); + foreach (AstType typeArgument in typeArguments) { + result.Add(ResolveType(typeArgument)); + } + return result; + } + + ResolveResult[] GetArguments(IEnumerable argumentExpressions, out string[] argumentNames) + { + argumentNames = null; + ResolveResult[] arguments = new ResolveResult[argumentExpressions.Count()]; + int i = 0; + foreach (AstNode argument in argumentExpressions) { + NamedArgumentExpression nae = argument as NamedArgumentExpression; + AstNode argumentValue; + if (nae != null) { + if (argumentNames == null) + argumentNames = new string[arguments.Length]; + argumentNames[i] = nae.Identifier; + argumentValue = nae.Expression; + } else { + argumentValue = argument; + } + arguments[i++] = Resolve(argumentValue); + } + return arguments; + } + + static bool IsTargetOfInvocation(AstNode node) + { + InvocationExpression ie = node.Parent as InvocationExpression; + return ie != null && ie.Target == node; + } + + bool IsVariableReferenceWithSameType(ResolveResult rr, string identifier, out TypeResolveResult trr) + { + if (!(rr is MemberResolveResult || rr is LocalResolveResult)) { + trr = null; + return false; + } + trr = resolver.LookupSimpleNameOrTypeName(identifier, EmptyList.Instance, SimpleNameLookupMode.Type) as TypeResolveResult; + return trr != null && trr.Type.Equals(rr.Type); + } + + /// + /// Gets whether 'rr' is considered a static access on the target identifier. + /// + /// Resolve Result of the MemberReferenceExpression + /// Resolve Result of the InvocationExpression + bool IsStaticResult(ResolveResult rr, ResolveResult invocationRR) + { + if (rr is TypeResolveResult) + return true; + MemberResolveResult mrr = (rr is MethodGroupResolveResult ? invocationRR : rr) as MemberResolveResult; + return mrr != null && mrr.Member.IsStatic; + } + + public override ResolveResult VisitIdentifierExpression(IdentifierExpression identifierExpression, object data) + { + // Note: this method is not called when it occurs in a situation where an ambiguity between + // simple names and type names might occur. + if (resolverEnabled) { + var typeArguments = GetTypeArguments(identifierExpression.TypeArguments); + return resolver.ResolveSimpleName(identifierExpression.Identifier, typeArguments, + IsTargetOfInvocation(identifierExpression)); + } else { + ScanChildren(identifierExpression); + return null; + } + } + + public override ResolveResult VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression, object data) + { + // target = Resolve(identifierExpression = memberReferenceExpression.Target) + // trr = ResolveType(identifierExpression) + // rr = Resolve(memberReferenceExpression) + + IdentifierExpression identifierExpression = memberReferenceExpression.Target as IdentifierExpression; + if (identifierExpression != null && identifierExpression.TypeArguments.Count == 0) { + // Special handling for §7.6.4.1 Identicial simple names and type names + ResolveResult target = resolver.ResolveSimpleName(identifierExpression.Identifier, EmptyList.Instance); + TypeResolveResult trr; + if (IsVariableReferenceWithSameType(target, identifierExpression.Identifier, out trr)) { + // It's ambiguous + ResolveResult rr = ResolveMemberReferenceOnGivenTarget(target, memberReferenceExpression); + resolveResultCache.Add(identifierExpression, IsStaticResult(rr, null) ? trr : target); + return rr; + } else { + // It's not ambiguous + resolveResultCache.Add(identifierExpression, target); + if (resolverEnabled) { + return ResolveMemberReferenceOnGivenTarget(target, memberReferenceExpression); + } else { + // Scan children (but not the IdentifierExpression which we already resolved) + for (AstNode child = memberReferenceExpression.FirstChild; child != null; child = child.NextSibling) { + if (child != identifierExpression) + Scan(child); + } + return null; + } + } + } else { + // Regular code path + if (resolverEnabled) { + ResolveResult target = Resolve(memberReferenceExpression.Target); + return ResolveMemberReferenceOnGivenTarget(target, memberReferenceExpression); + } else { + ScanChildren(memberReferenceExpression); + return null; + } + } + } + + ResolveResult ResolveMemberReferenceOnGivenTarget(ResolveResult target, MemberReferenceExpression memberReferenceExpression) + { + var typeArguments = GetTypeArguments(memberReferenceExpression.TypeArguments); + return resolver.ResolveMemberAccess( + target, memberReferenceExpression.MemberName, typeArguments, + IsTargetOfInvocation(memberReferenceExpression)); + } + + public override ResolveResult VisitInvocationExpression(InvocationExpression invocationExpression, object data) + { + // rr = Resolve(invocationExpression) + // target = Resolve(memberReferenceExpression = invocationExpression.Target) + // idRR = Resolve(identifierExpression = memberReferenceExpression.Target) + // trr = ResolveType(identifierExpression) + + MemberReferenceExpression mre = invocationExpression.Target as MemberReferenceExpression; + IdentifierExpression identifierExpression = mre != null ? mre.Target as IdentifierExpression : null; + if (identifierExpression != null && identifierExpression.TypeArguments.Count == 0) { + // Special handling for §7.6.4.1 Identicial simple names and type names + ResolveResult idRR = resolver.ResolveSimpleName(identifierExpression.Identifier, EmptyList.Instance); + ResolveResult target = ResolveMemberReferenceOnGivenTarget(idRR, mre); + resolveResultCache.Add(mre, target); + TypeResolveResult trr; + if (IsVariableReferenceWithSameType(idRR, identifierExpression.Identifier, out trr)) { + // It's ambiguous + ResolveResult rr = ResolveInvocationOnGivenTarget(target, invocationExpression); + resolveResultCache.Add(identifierExpression, IsStaticResult(target, rr) ? trr : idRR); + return rr; + } else { + // It's not ambiguous + resolveResultCache.Add(identifierExpression, idRR); + if (resolverEnabled) { + return ResolveInvocationOnGivenTarget(target, invocationExpression); + } else { + // Scan children (but not the MRE which we already resolved) + for (AstNode child = invocationExpression.FirstChild; child != null; child = child.NextSibling) { + if (child != mre) + Scan(child); + } + return null; + } + } + } else { + // Regular code path + if (resolverEnabled) { + ResolveResult target = Resolve(invocationExpression.Target); + return ResolveInvocationOnGivenTarget(target, invocationExpression); + } else { + ScanChildren(invocationExpression); + return null; + } + } + } + + ResolveResult ResolveInvocationOnGivenTarget(ResolveResult target, InvocationExpression invocationExpression) + { + string[] argumentNames; + ResolveResult[] arguments = GetArguments(invocationExpression.Arguments, out argumentNames); + return resolver.ResolveInvocation(target, arguments, argumentNames); + } + #endregion + #region Local Variable Scopes (Block Statements) public override ResolveResult VisitBlockStatement(BlockStatement blockStatement, object data) { @@ -1056,23 +1199,48 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// ITypeReference MakeTypeReference(AstType type, AstNode initializerExpression, bool isForEach) { + bool needsResolving; + if (mode == ResolveVisitorNavigationMode.ResolveAll) { + needsResolving = true; + } else { + var modeForType = navigator.Scan(type); + needsResolving = (modeForType == ResolveVisitorNavigationMode.Resolve || modeForType == ResolveVisitorNavigationMode.ResolveAll); + } if (initializerExpression != null && IsVar(type)) { - return new VarTypeReference(this, resolver.Clone(), initializerExpression, isForEach); + var typeRef = new VarTypeReference(this, resolver.Clone(), initializerExpression, isForEach); + if (needsResolving) { + // Hack: I don't see a clean way to make the 'var' SimpleType resolve to the inferred type, + // so we just do it here and store the result in the resolver cache. + IType actualType = typeRef.Resolve(resolver.Context); + if (actualType.Kind != TypeKind.Unknown) { + resolveResultCache.Add(type, new TypeResolveResult(actualType)); + } else { + resolveResultCache.Add(type, errorResult); + } + return actualType; + } else { + return typeRef; + } } else { - return MakeTypeReference(type); + // Perf: avoid duplicate resolving of the type (once as ITypeReference, once directly in ResolveVisitor) + // if possible. By using ResolveType when we know we need to resolve the node anyways, the resolve cache + // can take care of the duplicate call. + if (needsResolving) + return ResolveType(type); + else + return MakeTypeReference(type); } } - ITypeReference MakeTypeReference(AstType type) + static bool IsVar(AstType returnType) { - return TypeSystemConvertVisitor.ConvertType(type, resolver.CurrentTypeDefinition, resolver.CurrentMember as IMethod, resolver.UsingScope, SimpleNameLookupMode.Type); + SimpleType st = returnType as SimpleType; + return st != null && st.Identifier == "var" && st.TypeArguments.Count == 0; } - static bool IsVar(AstType returnType) + ITypeReference MakeTypeReference(AstType type) { - return returnType is SimpleType - && ((SimpleType)returnType).Identifier == "var" - && ((SimpleType)returnType).TypeArguments.Count == 0; + return TypeSystemConvertVisitor.ConvertType(type, resolver.CurrentTypeDefinition, resolver.CurrentMember as IMethod, resolver.UsingScope, currentTypeLookupMode); } sealed class VarTypeReference : ITypeReference @@ -1099,6 +1267,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver var oldMode = visitor.mode; var oldResolver = visitor.resolver; + var oldTypeLookupMode = visitor.currentTypeLookupMode; try { visitor.mode = ResolveVisitorNavigationMode.Resolve; visitor.resolver = storedContext; @@ -1113,6 +1282,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } finally { visitor.mode = oldMode; visitor.resolver = oldResolver; + visitor.currentTypeLookupMode = oldTypeLookupMode; visitor = null; storedContext = null; @@ -1153,57 +1323,44 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver #endregion #region Attributes - ITypeReference GetAttributeType (Attribute attribute) - { - var withoutSuffix = MakeTypeReference(attribute.Type); - ITypeReference withSuffix; - if (attribute.Type is SimpleType) { - var st = (SimpleType)attribute.Type; - withSuffix = MakeTypeReference(new SimpleType (st.Identifier + "Attribute")); - } else if (attribute.Type is MemberType) { - var mt = (MemberType)attribute.Type; - withSuffix = MakeTypeReference(new MemberType (mt.Target.Clone (), mt.MemberName + "Attribute")); - } else { - // unsupported type. - return SharedTypes.UnknownType; - } - return new AttributeTypeReference(withoutSuffix, withSuffix); - } - public override ResolveResult VisitAttribute(Attribute attribute, object data) { - ScanChildren(attribute); if (resolverEnabled) { - var type = GetAttributeType (attribute).Resolve (resolver.Context); - if (!attribute.HasArgumentList) - return new TypeResolveResult (type); - // try if the attribute usage references a constructuor + var type = ResolveType(attribute.Type); + + // Separate arguments into ctor arguments and non-ctor arguments: + var constructorArguments = attribute.Arguments.Where(a => !(a is AssignmentExpression)); + var nonConstructorArguments = attribute.Arguments.Where(a => a is AssignmentExpression); + + // Scan the non-constructor arguments + foreach (var arg in nonConstructorArguments) + Scan(arg); + + // Resolve the ctor arguments and find the matching ctor overload string[] argumentNames; - ResolveResult[] arguments = GetArguments(attribute.Arguments, out argumentNames); - var result = resolver.ResolveObjectCreation(type, arguments, argumentNames); - Console.WriteLine (result); - // if this is an error give back type resolve result, an attribute arg list isn't a constructor reference - // in all cases. - is it better to always give back the type resolve result ? - if (result.IsError) - return new TypeResolveResult (type); - return result; + ResolveResult[] arguments = GetArguments(constructorArguments, out argumentNames); + return resolver.ResolveObjectCreation(type, arguments, argumentNames); + } else { + ScanChildren(attribute); + return null; } - return null; } #endregion #region Using Declaration public override ResolveResult VisitUsingDeclaration(UsingDeclaration usingDeclaration, object data) { - // TODO: set isInUsingDeclaration + currentTypeLookupMode = SimpleNameLookupMode.TypeInUsingDeclaration; ScanChildren(usingDeclaration); + currentTypeLookupMode = SimpleNameLookupMode.Type; return null; } public override ResolveResult VisitUsingAliasDeclaration(UsingAliasDeclaration usingDeclaration, object data) { - // TODO: set isInUsingDeclaration + currentTypeLookupMode = SimpleNameLookupMode.TypeInUsingDeclaration; ScanChildren(usingDeclaration); + currentTypeLookupMode = SimpleNameLookupMode.Type; return null; } #endregion @@ -1211,37 +1368,76 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver #region Type References public override ResolveResult VisitPrimitiveType(PrimitiveType primitiveType, object data) { - ScanChildren(primitiveType); - return new TypeResolveResult(ResolveType(primitiveType)); + if (!resolverEnabled) + return null; + IType type = MakeTypeReference(primitiveType).Resolve(resolver.Context); + if (type.Kind != TypeKind.Unknown) + return new TypeResolveResult(type); + else + return errorResult; } - public override ResolveResult VisitSimpleType(SimpleType simpleType, object data) + ResolveResult HandleAttributeType(AstType astType) { - ScanChildren(simpleType); - return ResolveTypeOrNamespace(simpleType); + ScanChildren(astType); + IType type = TypeSystemConvertVisitor.ConvertAttributeType(astType, resolver.CurrentTypeDefinition, resolver.CurrentMember as IMethod, resolver.UsingScope).Resolve(resolver.Context); + if (type.Kind != TypeKind.Unknown) + return new TypeResolveResult(type); + else + return errorResult; } - ResolveResult ResolveTypeOrNamespace(AstType type) + public override ResolveResult VisitSimpleType(SimpleType simpleType, object data) { - ITypeReference typeRef = MakeTypeReference(type); - ITypeOrNamespaceReference typeOrNsRef = typeRef as ITypeOrNamespaceReference; - if (typeOrNsRef != null) { - return typeOrNsRef.DoResolve(resolver.Context); - } else { - return new TypeResolveResult(typeRef.Resolve(resolver.Context)); + if (!resolverEnabled) { + ScanChildren(simpleType); + return null; } + if (simpleType.Parent is Attribute) { + return HandleAttributeType(simpleType); + } + + var typeArguments = GetTypeArguments(simpleType.TypeArguments); + return resolver.LookupSimpleNameOrTypeName(simpleType.Identifier, typeArguments, currentTypeLookupMode); } public override ResolveResult VisitMemberType(MemberType memberType, object data) { - ScanChildren(memberType); - return ResolveTypeOrNamespace(memberType); + if (!resolverEnabled) { + ScanChildren(memberType); + return null; + } + if (memberType.Parent is Attribute) { + return HandleAttributeType(memberType); + } + ResolveResult target; + if (memberType.IsDoubleColon && memberType.Target is SimpleType) { + target = resolver.ResolveAlias(((SimpleType)memberType.Target).Identifier); + } else { + target = Resolve(memberType.Target); + } + + var typeArguments = GetTypeArguments(memberType.TypeArguments); + return resolver.ResolveMemberAccess(target, memberType.MemberName, typeArguments); } public override ResolveResult VisitComposedType(ComposedType composedType, object data) { - ScanChildren(composedType); - return new TypeResolveResult(ResolveType(composedType)); + if (!resolverEnabled) { + ScanChildren(composedType); + return null; + } + IType t = ResolveType(composedType.BaseType); + if (composedType.HasNullableSpecifier) { + t = NullableType.Create(t, resolver.Context); + } + for (int i = 0; i < composedType.PointerRank; i++) { + t = new PointerType(t); + } + foreach (var a in composedType.ArraySpecifiers.Reverse()) { + t = new ArrayType(t, a.Dimensions); + } + return new TypeResolveResult(t); } #endregion @@ -1270,11 +1466,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver throw new NotImplementedException(); } - public override ResolveResult VisitFixedVariableInitializer(FixedVariableInitializer fixedVariableInitializer, object data) - { - throw new NotImplementedException(); - } - #region Token Nodes public override ResolveResult VisitIdentifier(Identifier identifier, object data) { diff --git a/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs b/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs index cd7be72937..320a9b0185 100644 --- a/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs +++ b/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs @@ -742,26 +742,18 @@ namespace ICSharpCode.NRefactory.TypeSystem } } DefaultAttribute a = new DefaultAttribute(ReadTypeReference(attribute.AttributeType), ctorParameters); - try { - if (attribute.HasConstructorArguments) { - foreach (var arg in attribute.ConstructorArguments) { - a.PositionalArguments.Add(ReadConstantValue(arg)); - } + if (attribute.HasConstructorArguments) { + foreach (var arg in attribute.ConstructorArguments) { + a.PositionalArguments.Add(ReadConstantValue(arg)); } - } catch (InvalidOperationException) { - // occurs when Cecil can't decode an argument } - try { - if (attribute.HasFields || attribute.HasProperties) { - foreach (var arg in attribute.Fields) { - a.NamedArguments.Add(new KeyValuePair(arg.Name, ReadConstantValue(arg.Argument))); - } - foreach (var arg in attribute.Properties) { - a.NamedArguments.Add(new KeyValuePair(arg.Name, ReadConstantValue(arg.Argument))); - } + if (attribute.HasFields || attribute.HasProperties) { + foreach (var arg in attribute.Fields) { + a.NamedArguments.Add(new KeyValuePair(arg.Name, ReadConstantValue(arg.Argument))); + } + foreach (var arg in attribute.Properties) { + a.NamedArguments.Add(new KeyValuePair(arg.Name, ReadConstantValue(arg.Argument))); } - } catch (InvalidOperationException) { - // occurs when Cecil can't decode an argument } return a; } @@ -773,12 +765,12 @@ namespace ICSharpCode.NRefactory.TypeSystem void AddSecurityAttributes(Mono.Collections.Generic.Collection securityDeclarations, IList targetCollection) { foreach (var secDecl in securityDeclarations) { - foreach (var secAttribute in secDecl.SecurityAttributes) { - ITypeReference attributeType = ReadTypeReference(secAttribute.AttributeType); - var a = new DefaultAttribute(attributeType, new[] { securityActionTypeReference }); - a.PositionalArguments.Add(new SimpleConstantValue(securityActionTypeReference, (ushort)secDecl.Action)); - - try { + try { + foreach (var secAttribute in secDecl.SecurityAttributes) { + ITypeReference attributeType = ReadTypeReference(secAttribute.AttributeType); + var a = new DefaultAttribute(attributeType, new[] { securityActionTypeReference }); + a.PositionalArguments.Add(new SimpleConstantValue(securityActionTypeReference, (ushort)secDecl.Action)); + if (secAttribute.HasFields || secAttribute.HasProperties) { foreach (var arg in secAttribute.Fields) { a.NamedArguments.Add(new KeyValuePair(arg.Name, ReadConstantValue(arg.Argument))); @@ -787,10 +779,10 @@ namespace ICSharpCode.NRefactory.TypeSystem a.NamedArguments.Add(new KeyValuePair(arg.Name, ReadConstantValue(arg.Argument))); } } - } catch (InvalidOperationException) { - // occurs when Cecil can't decode an argument + targetCollection.Add(a); } - targetCollection.Add(a); + } catch (ResolutionException) { + // occurs when Cecil can't decode an argument } } }