From 06c1adf1a00751fe5f9cc5f6f8e6c2289260ae2f Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 14 Oct 2010 14:26:56 +0200 Subject: [PATCH] Worked on CSharpResolver. --- .../Resolver/ByReferenceResolveResult.cs | 5 + .../CSharp/Resolver/CSharpResolver.cs | 126 +++++++++++++++++- .../CSharp/Resolver/ConstantResolveResult.cs | 5 + .../CSharp/Resolver/MemberLookup.cs | 34 +++-- .../CSharp/Resolver/MemberResolveResult.cs | 7 + .../Resolver/MethodGroupResolveResult.cs | 13 +- .../CSharp/Resolver/NamespaceResolveResult.cs | 2 +- .../Resolver/UnknownMemberResolveResult.cs | 73 ++++++++++ .../CSharp/Resolver/UsingScope.cs | 4 + .../ICSharpCode.NRefactory.csproj | 1 + 10 files changed, 254 insertions(+), 16 deletions(-) create mode 100644 ICSharpCode.NRefactory/CSharp/Resolver/UnknownMemberResolveResult.cs diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/ByReferenceResolveResult.cs b/ICSharpCode.NRefactory/CSharp/Resolver/ByReferenceResolveResult.cs index 40ac984169..2056fe4c35 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/ByReferenceResolveResult.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/ByReferenceResolveResult.cs @@ -23,5 +23,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver public IType ElementType { get { return ((ByReferenceType)this.Type).ElementType; } } + + public override string ToString() + { + return string.Format("[{0} {1} {2}]", GetType().Name, IsOut ? "out" : "ref", ElementType); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs b/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs index fda25cb2fc..d727c490a0 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs @@ -1344,16 +1344,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver enum SimpleNameLookupMode { Expression, + InvocationTarget, Type, TypeInUsingDeclaration } - public ResolveResult ResolveSimpleName(string identifier, IList typeArguments) + public ResolveResult ResolveSimpleName(string identifier, IList typeArguments, bool isInvocationTarget = false) { // C# 4.0 spec: §7.6.2 Simple Names // TODO: lookup in local variables, in parameters, etc. - return LookupSimpleNameOrTypeName(identifier, typeArguments, SimpleNameLookupMode.Expression); + return LookupSimpleNameOrTypeName(identifier, typeArguments, + isInvocationTarget ? SimpleNameLookupMode.InvocationTarget : SimpleNameLookupMode.Expression); } public ResolveResult LookupSimpleNamespaceOrTypeName(string identifier, IList typeArguments, bool isUsingDeclaration = false) @@ -1379,6 +1381,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } + MemberLookup lookup = new MemberLookup(context, this.CurrentTypeDefinition, this.UsingScope.ProjectContent); // look in current type definitions for (ITypeDefinition t = this.CurrentTypeDefinition; t != null; t = t.DeclaringTypeDefinition) { if (k == 0) { @@ -1389,12 +1392,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } - if (lookupMode == SimpleNameLookupMode.Expression) { + if (lookupMode == SimpleNameLookupMode.Expression || lookupMode == SimpleNameLookupMode.InvocationTarget) { // TODO: perform member lookup within the type t - + ResolveResult r = lookup.Lookup(t, identifier, typeArguments, lookupMode == SimpleNameLookupMode.InvocationTarget); + if (!(r is UnknownMemberResolveResult)) + return r; } else { // TODO: perform member lookup within the type t, restricted to finding types - + throw new NotImplementedException(); } } // look in current namespace definitions @@ -1485,5 +1490,116 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return ErrorResult; } #endregion + + #region ResolveMemberAccess + public ResolveResult ResolveMemberAccess(ResolveResult target, string identifier, IList typeArguments, bool isInvocationTarget = false) + { + // C# 4.0 spec: §7.6.4 + + NamespaceResolveResult nrr = target as NamespaceResolveResult; + if (nrr != null) { + string fullName = NamespaceDeclaration.BuildQualifiedName(nrr.NamespaceName, identifier); + if (typeArguments.Count == 0) { + if (context.GetNamespace(fullName, StringComparer.Ordinal) != null) + return new NamespaceResolveResult(fullName); + } + ITypeDefinition def = context.GetClass(fullName, typeArguments.Count, StringComparer.Ordinal); + if (def != null) + return new TypeResolveResult(def); + return ErrorResult; + } + + if (target.Type == SharedTypes.Dynamic) + return DynamicResult; + + MemberLookup lookup = new MemberLookup(context, this.CurrentTypeDefinition, this.UsingScope.ProjectContent); + return lookup.Lookup(target.Type, identifier, typeArguments, isInvocationTarget); + } + #endregion + + #region ResolveInvocation + public ResolveResult ResolveInvocation(ResolveResult target, ResolveResult[] arguments, string[] argumentNames = null) + { + // C# 4.0 spec: §7.6.5 + if (target.Type == SharedTypes.Dynamic) + return DynamicResult; + + MethodGroupResolveResult mgrr = target as MethodGroupResolveResult; + if (mgrr != null) { + throw new NotImplementedException(); + } + UnknownMemberResolveResult umrr = target as UnknownMemberResolveResult; + if (umrr != null) { + return new UnknownMethodResolveResult(umrr.TargetType, umrr.MemberName, umrr.TypeArguments, CreateParameters(arguments, argumentNames)); + } + IMethod invokeMethod = target.Type.GetDelegateInvokeMethod(); + if (invokeMethod != null) { + return new ResolveResult(invokeMethod.ReturnType.Resolve(context)); + } + return ErrorResult; + } + + static List CreateParameters(ResolveResult[] arguments, string[] argumentNames) + { + List list = new List(); + if (argumentNames == null) { + argumentNames = new string[arguments.Length]; + } else { + if (argumentNames.Length != arguments.Length) + throw new ArgumentException(); + argumentNames = (string[])argumentNames.Clone(); + } + for (int i = 0; i < arguments.Length; i++) { + // invent argument names where necessary: + if (arguments[i] == null) { + string newArgumentName = GuessParameterName(arguments[i]); + if (argumentNames.Contains(newArgumentName)) { + // disambiguate argument name (e.g. add a number) + throw new NotImplementedException(); + } + argumentNames[i] = newArgumentName; + } + + // create the parameter: + ByReferenceResolveResult brrr = arguments[i] as ByReferenceResolveResult; + if (brrr != null) { + list.Add(new DefaultParameter(arguments[i].Type, argumentNames[i]) { + IsRef = brrr.IsRef, + IsOut = brrr.IsOut + }); + } else { + // argument might be a lambda or delegate type, so we have to try to guess the delegate type + IType type = arguments[i].Type; + if (type == SharedTypes.Null || type == SharedTypes.UnknownType) { + list.Add(new DefaultParameter(TypeCode.Object.ToTypeReference(), argumentNames[i])); + } else { + list.Add(new DefaultParameter(type, argumentNames[i])); + } + } + } + return list; + } + + static string GuessParameterName(ResolveResult rr) + { + MemberResolveResult mrr = rr as MemberResolveResult; + if (mrr != null) + return mrr.Member.Name; + + UnknownMemberResolveResult umrr = rr as UnknownMemberResolveResult; + if (umrr != null) + return umrr.MemberName; + + MethodGroupResolveResult mgrr = rr as MethodGroupResolveResult; + if (mgrr != null && mgrr.Methods.Count > 0) + return mgrr.Methods[0].Name; + + if (!string.IsNullOrEmpty(rr.Type.Name)) { + return char.ToLower(rr.Type.Name[0]) + rr.Type.Name.Substring(1); + } else { + return "parameter"; + } + } + #endregion } } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/ConstantResolveResult.cs b/ICSharpCode.NRefactory/CSharp/Resolver/ConstantResolveResult.cs index f34e20c2c6..32489a1d8b 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/ConstantResolveResult.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/ConstantResolveResult.cs @@ -25,5 +25,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver public override object ConstantValue { get { return constantValue; } } + + public override string ToString() + { + return string.Format("[{0} {1} = {2}]", GetType().Name, this.Type, constantValue); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/MemberLookup.cs b/ICSharpCode.NRefactory/CSharp/Resolver/MemberLookup.cs index e3611030d6..33f2030b01 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/MemberLookup.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/MemberLookup.cs @@ -96,21 +96,23 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// /// Performs a member lookup. /// - public ResolveResult Lookup(IType type, string name, int typeParameterCount, bool isInvocation) + public ResolveResult Lookup(IType type, string name, IList typeArguments, bool isInvocation) { + int typeArgumentCount = typeArguments.Count; + List types = new List(); List members = new List(); if (!isInvocation) { // Consider nested types only if it's not an invocation. The type parameter count must match in this case. types.AddRange(type.GetNestedTypes(context, - d => d.TypeParameterCount == typeParameterCount + d => d.TypeParameterCount == typeArgumentCount && d.Name == name && IsAccessible(d, true))); } ITypeDefinition typeDef = type.GetDefinition(); bool allowProtectedAccess = typeDef != null && typeDef.IsDerivedFrom(currentTypeDefinition, context); - if (typeParameterCount == 0) { + if (typeArgumentCount == 0) { Predicate memberFilter = delegate(IMember member) { return !member.IsOverride && member.Name == name && IsAccessible(member, allowProtectedAccess); }; @@ -124,12 +126,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver // No need to check for isInvocation/isInvocable here: // we filter out all non-methods Predicate memberFilter = delegate(IMethod method) { - return method.TypeParameters.Count == typeParameterCount + return method.TypeParameters.Count == typeArgumentCount && !method.IsOverride && method.Name == name && IsAccessible(method, allowProtectedAccess); }; members.AddRange(type.GetMethods(context, memberFilter)); } + // TODO: can't members also hide types? + // remove types hidden by other types for (int i = types.Count - 1; i >= 0; i--) { ITypeDefinition d = GetDeclaringTypeDef(types[i]); @@ -196,20 +200,32 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } - if (types.Count == 1 && members.Count == 0) - return new TypeResolveResult(types[0]); - if (types.Count > 0) - return new AmbiguousTypeResolveResult(types[0]); + if (types.Count > 0) { + IType returnedType = types[0]; + if (typeArguments.Count > 0) { + // parameterize the type if necessary + ITypeDefinition returnedTypeDef = returnedType as ITypeDefinition; + if (returnedTypeDef != null) + returnedType = new ParameterizedType(returnedTypeDef, typeArguments); + } + if (types.Count == 1 && members.Count == 0) + return new TypeResolveResult(types[0]); + else + return new AmbiguousTypeResolveResult(types[0]); + } + if (members.Count == 0) + return new UnknownMemberResolveResult(type, name, typeArguments); IMember firstNonMethod = members.FirstOrDefault(m => !(m is IMethod)); if (members.Count == 1 && firstNonMethod != null) return new MemberResolveResult(firstNonMethod, firstNonMethod.ReturnType.Resolve(context)); if (firstNonMethod == null) - return new MethodGroupResolveResult(members.ConvertAll(m => (IMethod)m)); + return new MethodGroupResolveResult(members.ConvertAll(m => (IMethod)m), typeArguments); return new AmbiguousMemberResultResult(firstNonMethod, firstNonMethod.ReturnType.Resolve(context)); } static bool IsNonInterfaceType(ITypeDefinition def) { + // return type if def is neither an interface nor System.Object return def.ClassType != ClassType.Interface && !(def.Name == "Object" && def.Namespace == "System" && def.TypeParameterCount == 0); } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/MemberResolveResult.cs b/ICSharpCode.NRefactory/CSharp/Resolver/MemberResolveResult.cs index 75e47eba4e..8026b89bff 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/MemberResolveResult.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/MemberResolveResult.cs @@ -15,11 +15,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver public MemberResolveResult(IMember member, IType returnType) : base(returnType) { + if (member == null) + throw new ArgumentNullException("member"); this.member = member; } public IMember Member { get { return member; } } + + public override string ToString() + { + return string.Format("[{0} {1}]", GetType().Name, member); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/MethodGroupResolveResult.cs b/ICSharpCode.NRefactory/CSharp/Resolver/MethodGroupResolveResult.cs index a698c8be89..9c5b9d9e57 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/MethodGroupResolveResult.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/MethodGroupResolveResult.cs @@ -15,16 +15,27 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver public class MethodGroupResolveResult : ResolveResult { readonly ReadOnlyCollection methods; + readonly ReadOnlyCollection typeArguments; - public MethodGroupResolveResult(IList methods) : base(SharedTypes.UnknownType) + public MethodGroupResolveResult(IList methods, IList typeArguments) : base(SharedTypes.UnknownType) { if (methods == null) throw new ArgumentNullException("methods"); this.methods = new ReadOnlyCollection(methods); + this.typeArguments = new ReadOnlyCollection(typeArguments); } public ReadOnlyCollection Methods { get { return methods; } } + + public ReadOnlyCollection TypeArguments { + get { return typeArguments; } + } + + public override string ToString() + { + return string.Format("[{0} with {1} method(s)]", GetType().Name, methods.Count); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/NamespaceResolveResult.cs b/ICSharpCode.NRefactory/CSharp/Resolver/NamespaceResolveResult.cs index b5f9738ec1..8b4ed998b4 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/NamespaceResolveResult.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/NamespaceResolveResult.cs @@ -24,7 +24,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver public override string ToString() { - return "[NamespaceResolveResult " + namespaceName + "]"; + return string.Format("[{0} {1}]", GetType().Name, namespaceName); } } } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/UnknownMemberResolveResult.cs b/ICSharpCode.NRefactory/CSharp/Resolver/UnknownMemberResolveResult.cs new file mode 100644 index 0000000000..56e8311b2e --- /dev/null +++ b/ICSharpCode.NRefactory/CSharp/Resolver/UnknownMemberResolveResult.cs @@ -0,0 +1,73 @@ +// Copyright (c) 2010 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 System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.CSharp.Resolver +{ + /// + /// Represents an unknown member. + /// + public class UnknownMemberResolveResult : ResolveResult + { + readonly IType targetType; + readonly string memberName; + readonly ReadOnlyCollection typeArguments; + + public UnknownMemberResolveResult(IType targetType, string memberName, IEnumerable typeArguments) : base(SharedTypes.UnknownType) + { + if (targetType == null) + throw new ArgumentNullException("targetType"); + this.targetType = targetType; + this.memberName = memberName; + this.typeArguments = new ReadOnlyCollection(typeArguments.ToArray()); + } + + public IType TargetType { + get { return targetType; } + } + + public string MemberName { + get { return memberName; } + } + + public ReadOnlyCollection TypeArguments { + get { return typeArguments; } + } + + public override bool IsError { + get { return true; } + } + + public override string ToString() + { + return string.Format("[{0} {1}.{2}]", GetType().Name, targetType, memberName); + } + } + + /// + /// Represents an unknown method. + /// + public class UnknownMethodResolveResult : UnknownMemberResolveResult + { + readonly ReadOnlyCollection parameters; + + public UnknownMethodResolveResult(IType targetType, string methodName, IEnumerable typeArguments, IEnumerable parameters) + : base(targetType, methodName, typeArguments) + { + this.parameters = new ReadOnlyCollection(parameters.ToArray()); + } + + public ReadOnlyCollection Parameters { + get { return parameters; } + } + + public override bool IsError { + get { return true; } + } + } +} diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/UsingScope.cs b/ICSharpCode.NRefactory/CSharp/Resolver/UsingScope.cs index 3c728e5937..2b46ee5ab7 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/UsingScope.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/UsingScope.cs @@ -70,6 +70,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver get { return parent; } } + public IProjectContent ProjectContent { + get { return projectContent; } + } + public DomRegion Region { get { return region; } set { diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index bfa9ecae9e..4f9f9acb46 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -155,6 +155,7 @@ +