Browse Source

Started implementation of simple name lookup.

newNRvisualizers
Daniel Grunwald 15 years ago
parent
commit
2c927c1b3f
  1. 3
      ICSharpCode.NRefactory.Tests/TypeSystem/CecilLoaderTests.cs
  2. 19
      ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs
  3. 2
      ICSharpCode.NRefactory.Tests/TypeSystem/ReflectionHelperTests.cs
  4. 5
      ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs
  5. 9
      ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs
  6. 22
      ICSharpCode.NRefactory/CSharp/Resolver/AmbiguousResolveResult.cs
  7. 144
      ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs
  8. 16
      ICSharpCode.NRefactory/CSharp/Resolver/ITypeOrNamespaceReference.cs
  9. 80
      ICSharpCode.NRefactory/CSharp/Resolver/MemberLookup.cs
  10. 30
      ICSharpCode.NRefactory/CSharp/Resolver/NamespaceResolveResult.cs
  11. 5
      ICSharpCode.NRefactory/CSharp/Resolver/ResolveResult.cs
  12. 58
      ICSharpCode.NRefactory/CSharp/Resolver/SimpleTypeOrNamespaceReference.cs
  13. 19
      ICSharpCode.NRefactory/CSharp/Resolver/TypeResolveResult.cs
  14. 138
      ICSharpCode.NRefactory/CSharp/Resolver/UsingScope.cs
  15. 7
      ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
  16. 40
      ICSharpCode.NRefactory/TypeSystem/AmbiguousType.cs
  17. 40
      ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs
  18. 19
      ICSharpCode.NRefactory/TypeSystem/ITypeResolveContext.cs
  19. 11
      ICSharpCode.NRefactory/TypeSystem/Implementation/CompositeTypeResolveContext.cs
  20. 49
      ICSharpCode.NRefactory/TypeSystem/Implementation/GetClassTypeReference.cs
  21. 38
      ICSharpCode.NRefactory/TypeSystem/Implementation/NestedTypeReference.cs
  22. 6
      ICSharpCode.NRefactory/TypeSystem/Implementation/ProxyTypeResolveContext.cs
  23. 10
      ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleProjectContent.cs
  24. 6
      ICSharpCode.NRefactory/TypeSystem/Implementation/TypeStorage.cs

3
ICSharpCode.NRefactory.Tests/TypeSystem/CecilLoaderTests.cs

@ -116,6 +116,9 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -116,6 +116,9 @@ namespace ICSharpCode.NRefactory.TypeSystem
ITypeDefinition c = Mscorlib.GetClass(typeof(void));
Assert.IsNotNull(c, "System.Void not found");
Assert.AreEqual(0, c.GetMethods(ctx).Count());
Assert.AreEqual(0, c.GetProperties(ctx).Count());
Assert.AreEqual(0, c.GetEvents(ctx).Count());
Assert.AreEqual(0, c.GetFields(ctx).Count());
Assert.AreEqual(
new string[] {
"[System.SerializableAttribute]",

19
ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs

@ -40,6 +40,25 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -40,6 +40,25 @@ namespace ICSharpCode.NRefactory.TypeSystem
GetAllBaseTypes(typeof(string)));
}
[Test]
public void ArrayOfString()
{
Assert.AreEqual(GetTypes(typeof(string[]), typeof(Array), typeof(object),
typeof(IList), typeof(ICollection), typeof(IEnumerable),
typeof(IList<string>), typeof(ICollection<string>), typeof(IEnumerable<string>),
typeof(IStructuralEquatable), typeof(IStructuralComparable), typeof(ICloneable)),
GetAllBaseTypes(typeof(string[])));
}
[Test]
public void MultidimensionalArrayOfString()
{
Assert.AreEqual(GetTypes(typeof(string[,]), typeof(Array), typeof(object),
typeof(IList), typeof(ICollection), typeof(IEnumerable),
typeof(IStructuralEquatable), typeof(IStructuralComparable), typeof(ICloneable)),
GetAllBaseTypes(typeof(string[,])));
}
[Test]
public void ClassDerivingFromItself()
{

2
ICSharpCode.NRefactory.Tests/TypeSystem/ReflectionHelperTests.cs

@ -87,7 +87,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -87,7 +87,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test]
public void TestToTypeReferenceInnerClassInUnboundGenericType()
{
Assert.AreEqual("System.Collections.Generic.Dictionary`2+ValueCollection[[`0],[`1]]",
Assert.AreEqual("System.Collections.Generic.Dictionary`2+ValueCollection",
typeof(Dictionary<,>.ValueCollection).ToTypeReference().Resolve(context).ReflectionName);
}

5
ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs

@ -55,4 +55,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase @@ -55,4 +55,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase
Flag2 = 0x20,
CombinedFlags = Flag1 | Flag2
}
public class Base<T> {
public class Nested {}
}
public class Derived<A, B> : Base<B> {}
}

9
ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs

@ -215,6 +215,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -215,6 +215,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
foreach (IField f in e.Fields) {
Assert.IsTrue(f.IsStatic);
Assert.IsTrue(f.IsConst);
Assert.AreEqual(Accessibility.Public, f.Accessibility);
Assert.AreSame(e, f.ConstantValue.GetValueType(ctx));
Assert.AreEqual(typeof(short), f.ConstantValue.GetValue(ctx).GetType());
}
@ -235,5 +236,13 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -235,5 +236,13 @@ namespace ICSharpCode.NRefactory.TypeSystem
Assert.AreEqual("CombinedFlags", e.Fields[4].Name);
Assert.AreEqual(0x30, e.Fields[4].ConstantValue.GetValue(ctx));
}
[Test]
public void ParameterizedTypeGetNestedTypesFromBaseClassTest()
{
var d = typeof(Derived<string, int>).ToTypeReference().Resolve(ctx);
Assert.AreEqual(new[] { typeof(Base<>.Nested).FullName + "[[System.Int32]]" },
d.GetNestedTypes(ctx).Select(n => n.ReflectionName).ToArray());
}
}
}

22
ICSharpCode.NRefactory/CSharp/Resolver/AmbiguousResolveResult.cs

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
// 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 ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
/// <summary>
/// Represents an ambiguous type resolve result.
/// </summary>
public class AmbiguousTypeResolveResult : TypeResolveResult
{
public AmbiguousTypeResolveResult(IType type) : base(type)
{
}
public override bool IsError {
get { return true; }
}
}
}

144
ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs

@ -22,17 +22,39 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -22,17 +22,39 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
readonly ITypeResolveContext context;
/// <summary>
/// Gets/Sets whether the current context is <c>checked</c>.
/// </summary>
public bool CheckForOverflow { get; set; }
#region Constructor
public CSharpResolver(ITypeResolveContext context)
{
if (context == null)
throw new ArgumentNullException("context");
this.context = context;
}
#endregion
#region Properties
/// <summary>
/// Gets/Sets whether the current context is <c>checked</c>.
/// </summary>
public bool CheckForOverflow { get; set; }
/// <summary>
/// Gets/Sets the current member definition that is used to look up identifiers as parameters
/// or type parameters.
/// </summary>
/// <remarks>Don't forget to also set CurrentTypeDefinition when setting CurrentMember;
/// setting one of the properties does not automatically set the other.</remarks>
public IMember CurrentMember { get; set; }
/// <summary>
/// Gets/Sets the current type definition that is used to look up identifiers as simple members.
/// </summary>
public ITypeDefinition CurrentTypeDefinition { get; set; }
/// <summary>
/// Gets/Sets the current using scope that is used to look up identifiers as class names.
/// </summary>
public UsingScope UsingScope { get; set; }
#endregion
#region class OperatorMethod
static OperatorMethod[] Lift(params OperatorMethod[] methods)
@ -1317,5 +1339,117 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1317,5 +1339,117 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return ResolveCast(targetType, expression);
}
#endregion
#region ResolveSimpleName
public ResolveResult ResolveSimpleName(string identifier, IList<IType> typeArguments)
{
// C# 4.0 spec: §7.6.2 Simple Names
// TODO: lookup in local variables, in parameters, etc.
return LookupSimpleNameOrTypeName(identifier, typeArguments, false);
}
public ResolveResult LookupSimpleNamespaceOrTypeName(string identifier, IList<IType> typeArguments)
{
return LookupSimpleNameOrTypeName(identifier, typeArguments, true);
}
ResolveResult LookupSimpleNameOrTypeName(string identifier, IList<IType> typeArguments, bool typeOnly)
{
// C# 4.0 spec: §3.8 Namespace and type names; §7.6.2 Simple Names
int k = typeArguments.Count;
// look in type parameters of current method
if (k == 0) {
IMethod m = this.CurrentMember as IMethod;
if (m != null) {
foreach (ITypeParameter tp in m.TypeParameters) {
if (tp.Name == identifier)
return new TypeResolveResult(tp);
}
}
}
// look in current type definitions
for (ITypeDefinition t = this.CurrentTypeDefinition; t != null; t = t.DeclaringTypeDefinition) {
if (k == 0) {
// look for type parameter with that name
foreach (ITypeParameter tp in t.TypeParameters) {
if (tp.Name == identifier)
return new TypeResolveResult(tp);
}
}
if (typeOnly) {
// TODO: perform member lookup within the type t, restricted to finding types
} else {
// TODO: perform member lookup within the type t
}
}
// look in current namespace definitions
for (UsingScope n = this.UsingScope; n != null; n = n.Parent) {
string fullName = NamespaceDeclaration.BuildQualifiedName(n.NamespaceName, identifier);
// first look for a namespace
if (k == 0) {
if (context.GetNamespace(fullName, StringComparer.Ordinal) != null) {
if (n.HasAlias(identifier))
return new AmbiguousTypeResolveResult(SharedTypes.UnknownType);
return new NamespaceResolveResult(fullName);
}
}
// then look for a type
ITypeDefinition def = context.GetClass(fullName, k, StringComparer.Ordinal);
if (def != null) {
IType result = def;
if (k != 0) {
result = new ParameterizedType(def, typeArguments);
}
if (n.HasAlias(identifier))
return new AmbiguousTypeResolveResult(result);
else
return new TypeResolveResult(result);
}
// then look for aliases:
if (k == 0) {
if (n.ExternAliases.Contains(identifier)) {
// TODO: implement extern alias support
throw new NotImplementedException();
}
foreach (var pair in n.UsingAliases) {
if (pair.Key == identifier) {
string ns = pair.Value.ResolveNamespace(context);
if (ns != null)
return new NamespaceResolveResult(ns);
else
return new TypeResolveResult(pair.Value.Resolve(context));
}
}
}
// finally, look in the imported namespaces:
IType firstResult = null;
foreach (var u in n.Usings) {
string ns = u.ResolveNamespace(context);
if (ns != null) {
fullName = NamespaceDeclaration.BuildQualifiedName(ns, identifier);
def = context.GetClass(ns, k, StringComparer.Ordinal);
if (firstResult == null) {
if (k == 0)
firstResult = def;
else
firstResult = new ParameterizedType(def, typeArguments);
} else {
return new AmbiguousTypeResolveResult(firstResult);
}
}
}
if (firstResult != null)
return new TypeResolveResult(firstResult);
// if we didn't find anything: repeat lookup with parent namespace
}
return ErrorResult;
}
#endregion
}
}

16
ICSharpCode.NRefactory/CSharp/Resolver/ITypeOrNamespaceReference.cs

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
// 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 ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
/// <summary>
/// Represents a reference which could point to a type or namespace.
/// </summary>
public interface ITypeOrNamespaceReference : ITypeReference
{
string ResolveNamespace(ITypeResolveContext context);
}
}

80
ICSharpCode.NRefactory/CSharp/Resolver/MemberLookup.cs

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver
@ -11,26 +12,89 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -11,26 +12,89 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// </summary>
public class MemberLookup
{
#region Static helper methods
/// <summary>
/// Gets whether the member is considered to be invocable.
/// </summary>
public static bool IsInvocable(IMember member, ITypeResolveContext context)
{
if (member == null)
throw new ArgumentNullException("member");
// C# 4.0 spec, §7.4 member lookup
if (member is IEvent || member is IMethod)
return true;
if (member.ReturnType == SharedTypes.Dynamic)
return true;
return member.ReturnType.Resolve(context).IsDelegate();
}
#endregion
ITypeResolveContext context;
ITypeDefinition currentTypeDefinition;
IProjectContent currentProject;
public MemberLookup(ITypeResolveContext context)
public MemberLookup(ITypeResolveContext context, ITypeDefinition currentTypeDefinition, IProjectContent currentProject)
{
if (context == null)
throw new ArgumentNullException("context");
this.context = context;
this.currentTypeDefinition = currentTypeDefinition;
this.currentProject = currentProject;
}
#region IsAccessible
/// <summary>
/// Gets whether the member is considered to be invocable.
/// Gets whether <paramref name="entity"/> is accessible in the current class.
/// </summary>
public bool IsInvocable(IMember member)
/// <param name="member">The entity to test</param>
/// <param name="typeOfReference">The type used to access the member, or null if no target is used (e.g. static method call)</param>
/// <returns>true if the member is accessible</returns>
public bool IsAccessible(IEntity entity, IType typeOfReference)
{
if (member is IEvent || member is IMethod)
return true;
if (member.ReturnType == SharedTypes.Dynamic)
return true;
return member.ReturnType.Resolve(context).IsDelegate();
if (entity == null)
throw new ArgumentNullException("entity");
// C# 4.0 spec, §3.5.2 Accessiblity domains
switch (entity.Accessibility) {
case Accessibility.None:
return false;
case Accessibility.Private:
return entity.DeclaringTypeDefinition == currentTypeDefinition;
case Accessibility.Public:
return true;
case Accessibility.Protected:
return IsProtectedAccessible(entity.DeclaringTypeDefinition, typeOfReference);
case Accessibility.Internal:
return IsInternalAccessible(entity.ProjectContent);
case Accessibility.ProtectedOrInternal:
return IsProtectedAccessible(entity.DeclaringTypeDefinition, typeOfReference)
|| IsInternalAccessible(entity.ProjectContent);
case Accessibility.ProtectedAndInternal:
return IsProtectedAccessible(entity.DeclaringTypeDefinition, typeOfReference)
&& IsInternalAccessible(entity.ProjectContent);
default:
throw new Exception("Invalid value for Accessibility");
}
}
bool IsInternalAccessible(IProjectContent declaringProject)
{
return declaringProject != null && currentProject != null && declaringProject.InternalsVisibleTo(currentProject, context);
}
bool IsProtectedAccessible(ITypeDefinition declaringType, IType typeOfReference)
{
if (declaringType == currentTypeDefinition)
return true;
// PERF: this might hurt performance as this method is called several times (once for each member)
// make sure resolving base types is cheap (caches?) or cache within the MemberLookup instance
if (currentTypeDefinition == null || !currentTypeDefinition.IsDerivedFrom(declaringType, context))
return false;
if (typeOfReference == null)
return true; // no restriction on the type of reference
ITypeDefinition referenceDef = typeOfReference.GetDefinition();
return referenceDef != null && referenceDef.IsDerivedFrom(currentTypeDefinition, context);
}
#endregion
}
}

30
ICSharpCode.NRefactory/CSharp/Resolver/NamespaceResolveResult.cs

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
// 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 ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
/// <summary>
/// Represents that an expression resolved to a namespace.
/// </summary>
public class NamespaceResolveResult : ResolveResult
{
readonly string namespaceName;
public NamespaceResolveResult(string namespaceName) : base(SharedTypes.UnknownType)
{
this.namespaceName = namespaceName;
}
public string NamespaceName {
get { return namespaceName; }
}
public override string ToString()
{
return "[NamespaceResolveResult " + namespaceName + "]";
}
}
}

5
ICSharpCode.NRefactory/CSharp/Resolver/ResolveResult.cs

@ -36,5 +36,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -36,5 +36,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public virtual bool IsError {
get { return false; }
}
public override string ToString()
{
return "[" + GetType().Name + " " + type + "]";
}
}
}

58
ICSharpCode.NRefactory/CSharp/Resolver/SimpleTypeOrNamespaceReference.cs

@ -0,0 +1,58 @@ @@ -0,0 +1,58 @@
// 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 ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
/// <summary>
/// Represents a simple C# name. (a single identifier with an optional list of type arguments)
/// </summary>
public sealed class SimpleTypeOrNamespaceReference : ITypeOrNamespaceReference
{
readonly IMember parentMember;
readonly ITypeDefinition parentTypeDefinition;
readonly UsingScope parentUsingScope;
readonly string identifier;
readonly IList<ITypeReference> typeArguments;
public SimpleTypeOrNamespaceReference(string identifier, IList<ITypeReference> typeArguments, IMember parentMember, ITypeDefinition parentTypeDefinition, UsingScope parentUsingScope)
{
if (identifier == null)
throw new ArgumentNullException("identifier");
this.identifier = identifier;
this.typeArguments = typeArguments ?? EmptyList<ITypeReference>.Instance;
this.parentMember = parentMember;
this.parentTypeDefinition = parentTypeDefinition;
this.parentUsingScope = parentUsingScope;
}
ResolveResult DoResolve(ITypeResolveContext context)
{
CSharpResolver r = new CSharpResolver(context);
r.CurrentMember = parentMember;
r.CurrentTypeDefinition = parentTypeDefinition.GetCompoundClass();
r.UsingScope = parentUsingScope;
IType[] typeArgs = new IType[typeArguments.Count];
for (int i = 0; i < typeArgs.Length; i++) {
typeArgs[i] = typeArguments[i].Resolve(context);
}
return r.LookupSimpleNamespaceOrTypeName(identifier, typeArgs);
}
public string ResolveNamespace(ITypeResolveContext context)
{
NamespaceResolveResult nrr = DoResolve(context) as NamespaceResolveResult;
return nrr != null ? nrr.NamespaceName : null;
}
public IType Resolve(ITypeResolveContext context)
{
TypeResolveResult rr = DoResolve(context) as TypeResolveResult;
return rr != null ? rr.Type : SharedTypes.UnknownType;
}
}
}

19
ICSharpCode.NRefactory/CSharp/Resolver/TypeResolveResult.cs

@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
// 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 ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
/// <summary>
/// The resolved expression refers to a type name.
/// </summary>
public class TypeResolveResult : ResolveResult
{
public TypeResolveResult(IType type)
: base(type)
{
}
}
}

138
ICSharpCode.NRefactory/CSharp/Resolver/UsingScope.cs

@ -0,0 +1,138 @@ @@ -0,0 +1,138 @@
// 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.Linq;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
/// <summary>
/// Represents a scope that contains "using" statements.
/// This is either the file itself, or a namespace declaration.
/// </summary>
public class UsingScope : AbstractFreezable
{
readonly IProjectContent projectContent;
readonly UsingScope parent;
DomRegion region;
string namespaceName = "";
IList<ITypeOrNamespaceReference> usings;
IList<KeyValuePair<string, ITypeOrNamespaceReference>> usingAliases;
IList<string> externAliases;
//IList<UsingScope> childScopes;
protected override void FreezeInternal()
{
if (usings == null || usings.Count == 0)
usings = EmptyList<ITypeOrNamespaceReference>.Instance;
else
usings = Array.AsReadOnly(usings.ToArray());
if (usingAliases == null || usingAliases.Count == 0)
usingAliases = EmptyList<KeyValuePair<string, ITypeOrNamespaceReference>>.Instance;
else
usingAliases = Array.AsReadOnly(usingAliases.ToArray());
externAliases = FreezeList(externAliases);
//childScopes = FreezeList(childScopes);
// In current model (no child scopes), it makes sense to freeze the parent as well
// to ensure the whole lookup chain is immutable.
// But we probably shouldn't do this if we add back childScopes.
if (parent != null)
parent.Freeze();
base.FreezeInternal();
}
public UsingScope(IProjectContent projectContent)
{
if (projectContent == null)
throw new ArgumentNullException("projectContent");
this.projectContent = projectContent;
}
public UsingScope(UsingScope parent, string namespaceName)
{
if (parent == null)
throw new ArgumentNullException("parent");
if (namespaceName == null)
throw new ArgumentNullException("namespaceName");
this.parent = parent;
this.projectContent = parent.projectContent;
this.namespaceName = namespaceName;
}
public UsingScope Parent {
get { return parent; }
}
public DomRegion Region {
get { return region; }
set {
CheckBeforeMutation();
region = value;
}
}
public string NamespaceName {
get { return namespaceName; }
set {
if (value == null)
throw new ArgumentNullException("NamespaceName");
CheckBeforeMutation();
namespaceName = value;
}
}
public IList<ITypeOrNamespaceReference> Usings {
get {
if (usings == null)
usings = new List<ITypeOrNamespaceReference>();
return usings;
}
}
public IList<KeyValuePair<string, ITypeOrNamespaceReference>> UsingAliases {
get {
if (usingAliases == null)
usingAliases = new List<KeyValuePair<string, ITypeOrNamespaceReference>>();
return usingAliases;
}
}
public IList<string> ExternAliases {
get {
if (externAliases == null)
externAliases = new List<string>();
return externAliases;
}
}
// public IList<UsingScope> ChildScopes {
// get {
// if (childScopes == null)
// childScopes = new List<UsingScope>();
// return childScopes;
// }
// }
/// <summary>
/// Gets whether this using scope has an alias (either using or extern)
/// with the specified name.
/// </summary>
public bool HasAlias(string identifier)
{
if (usingAliases != null) {
foreach (var pair in usingAliases) {
if (pair.Key == identifier)
return true;
}
}
return externAliases != null && externAliases.Contains(identifier);
}
}
}

7
ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

@ -139,18 +139,23 @@ @@ -139,18 +139,23 @@
<Compile Include="CSharp\Parser\mcs\MonoSymbolWriter.cs" />
<Compile Include="CSharp\Parser\mcs\outline.cs" />
<Compile Include="CSharp\Parser\mcs\roottypes.cs" />
<Compile Include="CSharp\Resolver\AmbiguousResolveResult.cs" />
<Compile Include="CSharp\Resolver\ByReferenceResolveResult.cs" />
<Compile Include="CSharp\Resolver\ConstantResolveResult.cs" />
<Compile Include="CSharp\Resolver\Conversions.cs" />
<Compile Include="CSharp\Resolver\CSharpResolver.cs" />
<Compile Include="CSharp\Resolver\ErrorResolveResult.cs" />
<Compile Include="CSharp\Resolver\ITypeOrNamespaceReference.cs" />
<Compile Include="CSharp\Resolver\MemberLookup.cs" />
<Compile Include="CSharp\Resolver\NamespaceResolveResult.cs" />
<Compile Include="CSharp\Resolver\OverloadResolution.cs" />
<Compile Include="CSharp\Resolver\OverloadResolutionErrors.cs" />
<Compile Include="CSharp\Resolver\ResolveResult.cs" />
<Compile Include="CSharp\Resolver\SimpleTypeOrNamespaceReference.cs" />
<Compile Include="CSharp\Resolver\TypeResolveResult.cs" />
<Compile Include="CSharp\Resolver\UsingScope.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TypeSystem\Accessibility.cs" />
<Compile Include="TypeSystem\AmbiguousType.cs" />
<Compile Include="TypeSystem\ArrayType.cs" />
<Compile Include="TypeSystem\ByReferenceType.cs" />
<Compile Include="TypeSystem\CecilLoader.cs" />

40
ICSharpCode.NRefactory/TypeSystem/AmbiguousType.cs

@ -1,40 +0,0 @@ @@ -1,40 +0,0 @@

using System;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.TypeSystem
{
/// <summary>
/// Represents an ambiguous type (same type found in multiple locations).
/// </summary>
public class AmbiguousType : AbstractType
{
readonly string name;
public AmbiguousType(string name)
{
if (name == null)
throw new ArgumentNullException("name");
this.name = name;
}
public override string Name {
get { return name; }
}
public override bool? IsReferenceType {
get { return null; }
}
public override int GetHashCode()
{
return name.GetHashCode() ^ 12661218;
}
public override bool Equals(IType other)
{
AmbiguousType at = other as AmbiguousType;
return at != null && name == at.name;
}
}
}

40
ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs

@ -3,6 +3,8 @@ @@ -3,6 +3,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.TypeSystem
{
@ -53,6 +55,29 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -53,6 +55,29 @@ namespace ICSharpCode.NRefactory.TypeSystem
}
#endregion
#region GetAllBaseTypeDefinitions
/// <summary>
/// Gets all base type definitions.
/// </summary>
/// <remarks>
/// This is equivalent to type.GetAllBaseTypes().Select(t => t.GetDefinition()).Where(d => d != null).Distinct().
/// </remarks>
public static IEnumerable<ITypeDefinition> GetAllBaseTypeDefinitions(this ITypeDefinition type, ITypeResolveContext context)
{
HashSet<ITypeDefinition> typeDefinitions = new HashSet<ITypeDefinition>();
typeDefinitions.Add(type);
return TreeTraversal.PreOrder(type, t => t.GetBaseTypes(context).Select(b => b.GetDefinition()).Where(d => d != null && typeDefinitions.Add(d)));
}
/// <summary>
/// Gets whether this type definition is derived from the base type defintiion.
/// </summary>
public static bool IsDerivedFrom(this ITypeDefinition type, ITypeDefinition baseType, ITypeResolveContext context)
{
return GetAllBaseTypeDefinitions(type, context).Contains(baseType);
}
#endregion
#region IsOpen / IsUnbound
sealed class TypeClassificationVisitor : TypeVisitor
{
@ -152,5 +177,20 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -152,5 +177,20 @@ namespace ICSharpCode.NRefactory.TypeSystem
return null;
}
#endregion
#region InternalsVisibleTo
/// <summary>
/// Gets whether the internals of this project are visible to the other project
/// </summary>
public static bool InternalsVisibleTo(this IProjectContent projectContent, IProjectContent other, ITypeResolveContext context)
{
if (projectContent == other)
return true;
// TODO: implement support for [InternalsVisibleToAttribute]
// Make sure implementation doesn't hurt performance, e.g. don't resolve all assembly attributes whenever
// this method is called - it'll be called once per internal member during lookup operations
return false;
}
#endregion
}
}

19
ICSharpCode.NRefactory/TypeSystem/ITypeResolveContext.cs

@ -55,6 +55,18 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -55,6 +55,18 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// </remarks>
IEnumerable<string> GetNamespaces();
/// <summary>
/// Gets a namespace.
/// </summary>
/// <param name="nameSpace">The full name of the namespace.</param>
/// <param name="nameComparer">The comparer to use.</param>
/// <returns>The full name of the namespace, if it exists; or null if the namespace does not exist.</returns>
/// <remarks>
/// For StringComparer.Ordinal, the return value is either null or the input namespace.
/// For other name comparers, this method returns the declared name of the namespace.
/// </remarks>
string GetNamespace(string nameSpace, StringComparer nameComparer);
/// <summary>
/// Returns a <see cref="ISynchronizedTypeResolveContext"/> that
/// represents the same context as this instance, but cannot be modified
@ -118,5 +130,12 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -118,5 +130,12 @@ namespace ICSharpCode.NRefactory.TypeSystem
Utils.CacheManager ITypeResolveContext.CacheManager {
get { return null; }
}
string ITypeResolveContext.GetNamespace(string nameSpace, StringComparer nameComparer)
{
Contract.Requires(nameSpace != null);
Contract.Requires(nameComparer != null);
return null;
}
}
}

11
ICSharpCode.NRefactory/TypeSystem/Implementation/CompositeTypeResolveContext.cs

@ -80,6 +80,17 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -80,6 +80,17 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return children.SelectMany(c => c.GetNamespaces()).Distinct();
}
/// <inheritdoc/>
public string GetNamespace(string nameSpace, StringComparer nameComparer)
{
foreach (ITypeResolveContext context in children) {
string r = context.GetNamespace(nameSpace, nameComparer);
if (r != null)
return r;
}
return null;
}
/// <inheritdoc/>
public virtual ISynchronizedTypeResolveContext Synchronize()
{

49
ICSharpCode.NRefactory/TypeSystem/Implementation/GetClassTypeReference.cs

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
@ -12,6 +13,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -12,6 +13,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
string fullTypeName;
int typeParameterCount;
//volatile CachedResult v_cachedResult;
public GetClassTypeReference(string fullTypeName, int typeParameterCount)
{
@ -21,22 +23,47 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -21,22 +23,47 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
this.typeParameterCount = typeParameterCount;
}
/*
sealed class CachedResult
{
public readonly CacheManager CacheManager;
public readonly IType Result;
public CachedResult(CacheManager cacheManager, IType result)
{
this.CacheManager = cacheManager;
this.Result = result;
}
}
*/
public IType Resolve(ITypeResolveContext context)
{
if (context == null)
throw new ArgumentNullException("context");
// TODO: PERF: caching idea: if these lookups are a performance problem and the same GetClassTypeReference
// is asked to resolve lots of times in a row, try the following:
// Give ITypeResolveContext a property "object CacheToken { get; }" which is non-null if the
// context supports caching, and returns the same object only as long as the context is unchanged.
// Then store a thread-local array KeyValuePair<GetClassTypeReference, IType> with the last 5 (?) resolved
// types, and a thread-local reference to the cache token. Subsequent calls with the same cache token
// do a quick (reference equality) lookup in the array first.
// This should be faster than any ServiceContainer-based caches.
// It is worth an idea to make CacheToken implement IServiceContainer, so that other (more expensive)
// caches can be registered there, but I think it's troublesome as one ITypeResolveContext should be usable
// on multiple threads.
/* TODO PERF: caching disabled until we measure how much of an advantage it is
* (and whether other approaches like caching only the last N resolve calls in a thread-static cache would work better)
* Maybe even make a distinction between the really common type references (e.g. primitiveTypeReferences) and
* normal GetClassTypeReferences?
CacheManager cacheManager = context.CacheManager;
if (cacheManager != null) {
CachedResult result = this.v_cachedResult;
if (result != null && result.CacheManager == cacheManager)
return result.Result;
IType newResult = DoResolve(context);
this.v_cachedResult = new CachedResult(cacheManager, newResult);
cacheManager.Disposed += delegate { v_cachedResult = null; }; // maybe optimize this to use interface call instead of delegate?
return newResult;
} else {
return DoResolve(context);
}
}
IType DoResolve(ITypeResolveContext context)
{
*/
return context.GetClass(fullTypeName, typeParameterCount, StringComparer.Ordinal) ?? SharedTypes.UnknownType;
}

38
ICSharpCode.NRefactory/TypeSystem/Implementation/NestedTypeReference.cs

@ -10,34 +10,40 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -10,34 +10,40 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// </summary>
public sealed class NestedTypeReference : ITypeReference, ISupportsInterning
{
ITypeReference baseTypeRef;
ITypeReference declaringTypeRef;
string name;
int additionalTypeParameterCount;
/// <summary>
/// Creates a new NestedTypeReference.
/// </summary>
/// <param name="baseTypeRef">Reference to the base type.</param>
/// <param name="declaringTypeRef">Reference to the declaring type.</param>
/// <param name="name">Name of the nested class</param>
/// <param name="additionalTypeParameterCount">Number of type parameters on the inner class (without type parameters on baseTypeRef)</param>
public NestedTypeReference(ITypeReference baseTypeRef, string name, int additionalTypeParameterCount)
/// <remarks>
/// <paramref name="declaringTypeRef"/> must be exactly the (unbound) declaring type, not a derived type, not a parameterized type.
/// NestedTypeReference thus always resolves to a type definition, never to (partially) parameterized types.
/// </remarks>
public NestedTypeReference(ITypeReference declaringTypeRef, string name, int additionalTypeParameterCount)
{
if (baseTypeRef == null)
throw new ArgumentNullException("baseTypeRef");
if (declaringTypeRef == null)
throw new ArgumentNullException("declaringTypeRef");
if (name == null)
throw new ArgumentNullException("name");
this.baseTypeRef = baseTypeRef;
this.declaringTypeRef = declaringTypeRef;
this.name = name;
this.additionalTypeParameterCount = additionalTypeParameterCount;
}
public IType Resolve(ITypeResolveContext context)
{
IType baseType = baseTypeRef.Resolve(context);
int tpc = baseType.TypeParameterCount;
foreach (IType type in baseType.GetNestedTypes(context)) {
if (type.Name == name && type.TypeParameterCount == tpc + additionalTypeParameterCount)
return type;
ITypeDefinition declaringType = declaringTypeRef.Resolve(context) as ITypeDefinition;
if (declaringType != null) {
int tpc = declaringType.TypeParameterCount;
foreach (IType type in declaringType.InnerClasses) {
if (type.Name == name && type.TypeParameterCount == tpc + additionalTypeParameterCount)
return type;
}
}
return SharedTypes.UnknownType;
}
@ -45,26 +51,26 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -45,26 +51,26 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public override string ToString()
{
if (additionalTypeParameterCount == 0)
return baseTypeRef + "+" + name;
return declaringTypeRef + "+" + name;
else
return baseTypeRef + "+" + name + "`" + additionalTypeParameterCount;
return declaringTypeRef + "+" + name + "`" + additionalTypeParameterCount;
}
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{
baseTypeRef = provider.Intern(baseTypeRef);
declaringTypeRef = provider.Intern(declaringTypeRef);
name = provider.Intern(name);
}
int ISupportsInterning.GetHashCodeForInterning()
{
return baseTypeRef.GetHashCode() ^ name.GetHashCode() ^ additionalTypeParameterCount;
return declaringTypeRef.GetHashCode() ^ name.GetHashCode() ^ additionalTypeParameterCount;
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
NestedTypeReference o = other as NestedTypeReference;
return o != null && baseTypeRef == o.baseTypeRef && name == o.name && additionalTypeParameterCount == o.additionalTypeParameterCount;
return o != null && declaringTypeRef == o.declaringTypeRef && name == o.name && additionalTypeParameterCount == o.additionalTypeParameterCount;
}
}
}

6
ICSharpCode.NRefactory/TypeSystem/Implementation/ProxyTypeResolveContext.cs

@ -48,6 +48,12 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -48,6 +48,12 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return target.GetNamespaces();
}
/// <inheritdoc/>
public virtual string GetNamespace(string nameSpace, StringComparer nameComparer)
{
return target.GetNamespace(nameSpace, nameComparer);
}
/// <inheritdoc/>
public virtual ISynchronizedTypeResolveContext Synchronize()
{

10
ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleProjectContent.cs

@ -153,6 +153,16 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -153,6 +153,16 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
readerWriterLock.ExitReadLock();
}
}
public string GetNamespace(string nameSpace, StringComparer nameComparer)
{
readerWriterLock.EnterReadLock();
try {
return types.GetNamespace(nameSpace, nameComparer);
} finally {
readerWriterLock.ExitReadLock();
}
}
#endregion
#region Synchronization

6
ICSharpCode.NRefactory/TypeSystem/Implementation/TypeStorage.cs

@ -136,6 +136,12 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -136,6 +136,12 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
return GetClasses().Select(c => c.Namespace).Distinct();
}
/// <inheritdoc/>
public string GetNamespace(string nameSpace, StringComparer nameComparer)
{
return GetNamespaces().FirstOrDefault(n => nameComparer.Equals(nameSpace, n));
}
#endregion
#region Synchronize

Loading…
Cancel
Save