diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs b/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs
index 7960dd3732..03a29c859d 100644
--- a/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs
+++ b/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs
@@ -79,11 +79,64 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// setting one of the properties does not automatically set the other.
public IMember CurrentMember { get; set; }
+ ///
+ /// Gets the current project content.
+ /// Returns CurrentUsingScope.ProjectContent.
+ ///
+ public IProjectContent ProjectContent {
+ get {
+ if (currentUsingScope != null)
+ return currentUsingScope.UsingScope.ProjectContent;
+ else
+ return null;
+ }
+ }
+ #endregion
+
+ #region Per-CurrentTypeDefinition Cache
+ TypeDefinitionCache currentTypeDefinition;
+
///
/// Gets/Sets the current type definition that is used to look up identifiers as simple members.
///
- public ITypeDefinition CurrentTypeDefinition { get; set; }
+ public ITypeDefinition CurrentTypeDefinition {
+ get { return currentTypeDefinition != null ? currentTypeDefinition.TypeDefinition : null; }
+ set {
+ if (value == null) {
+ currentTypeDefinition = null;
+ } else {
+ if (currentTypeDefinition != null && currentTypeDefinition.TypeDefinition == value)
+ return;
+
+ CacheManager cache = context.CacheManager;
+ if (cache != null) {
+ currentTypeDefinition = cache.GetThreadLocal(value) as TypeDefinitionCache;
+ if (currentTypeDefinition == null) {
+ currentTypeDefinition = new TypeDefinitionCache(value);
+ cache.SetThreadLocal(value, currentTypeDefinition);
+ }
+ } else {
+ currentTypeDefinition = new TypeDefinitionCache(value);
+ }
+ }
+ }
+ }
+
+ sealed class TypeDefinitionCache
+ {
+ public readonly ITypeDefinition TypeDefinition;
+ public readonly Dictionary SimpleNameLookupCacheExpression = new Dictionary();
+ public readonly Dictionary SimpleNameLookupCacheInvocationTarget = new Dictionary();
+ public readonly Dictionary SimpleTypeLookupCache = new Dictionary();
+
+ public TypeDefinitionCache(ITypeDefinition typeDefinition)
+ {
+ this.TypeDefinition = typeDefinition;
+ }
+ }
+ #endregion
+ #region CurrentUsingScope
UsingScopeCache currentUsingScope;
///
@@ -100,10 +153,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
CacheManager cache = context.CacheManager;
if (cache != null) {
- currentUsingScope = cache.GetShared(value) as UsingScopeCache;
+ currentUsingScope = cache.GetThreadLocal(value) as UsingScopeCache;
if (currentUsingScope == null) {
currentUsingScope = new UsingScopeCache(value);
- cache.SetShared(value, currentUsingScope);
+ cache.SetThreadLocal(value, currentUsingScope);
}
} else {
currentUsingScope = new UsingScopeCache(value);
@@ -112,21 +165,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
}
- ///
- /// Gets the current project content.
- /// Returns CurrentUsingScope.ProjectContent.
- ///
- public IProjectContent ProjectContent {
- get {
- if (currentUsingScope != null)
- return currentUsingScope.UsingScope.ProjectContent;
- else
- return null;
- }
- }
- #endregion
-
- #region Per-UsingScope Cache
///
/// There is one cache instance per using scope; and it might be shared between multiple resolvers
/// that are on different threads, so it must be thread-safe.
@@ -134,9 +172,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
sealed class UsingScopeCache
{
public readonly UsingScope UsingScope;
+ public readonly Dictionary ResolveCache = new Dictionary();
- public volatile List> AllExtensionMethods;
-
+ public List> AllExtensionMethods;
public UsingScopeCache(UsingScope usingScope)
{
@@ -1967,7 +2005,63 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (parameterizeResultType && typeArguments.All(t => t.Kind == TypeKind.UnboundTypeArgument))
parameterizeResultType = false;
- ResolveResult r;
+ ResolveResult r = null;
+ if (currentTypeDefinition != null) {
+ Dictionary cache = null;
+ bool foundInCache = false;
+ if (k == 0) {
+ switch (lookupMode) {
+ case SimpleNameLookupMode.Expression:
+ cache = currentTypeDefinition.SimpleNameLookupCacheExpression;
+ break;
+ case SimpleNameLookupMode.InvocationTarget:
+ cache = currentTypeDefinition.SimpleNameLookupCacheInvocationTarget;
+ break;
+ case SimpleNameLookupMode.Type:
+ cache = currentTypeDefinition.SimpleTypeLookupCache;
+ break;
+ }
+ if (cache != null) {
+ foundInCache = cache.TryGetValue(identifier, out r);
+ }
+ }
+ if (!foundInCache) {
+ r = LookInCurrentType(identifier, typeArguments, lookupMode, parameterizeResultType);
+ if (cache != null) {
+ // also cache missing members (r==null)
+ cache[identifier] = r;
+ }
+ }
+ if (r != null)
+ return r;
+ }
+
+ if (currentUsingScope != null) {
+ if (k == 0 && lookupMode != SimpleNameLookupMode.TypeInUsingDeclaration) {
+ if (!currentUsingScope.ResolveCache.TryGetValue(identifier, out r)) {
+ r = LookInCurrentUsingScope(identifier, typeArguments, false, false);
+ currentUsingScope.ResolveCache[identifier] = r;
+ }
+ } else {
+ r = LookInCurrentUsingScope(identifier, typeArguments, lookupMode == SimpleNameLookupMode.TypeInUsingDeclaration, parameterizeResultType);
+ }
+ if (r != null)
+ return r;
+ }
+
+ if (typeArguments.Count == 0) {
+ if (identifier == "dynamic")
+ return new TypeResolveResult(SharedTypes.Dynamic);
+ else
+ return new UnknownIdentifierResolveResult(identifier);
+ } else {
+ return ErrorResult;
+ }
+ }
+
+ ResolveResult LookInCurrentType(string identifier, IList typeArguments, SimpleNameLookupMode lookupMode, bool parameterizeResultType)
+ {
+ int k = typeArguments.Count;
// look in current type definitions
for (ITypeDefinition t = this.CurrentTypeDefinition; t != null; t = t.DeclaringTypeDefinition) {
if (k == 0) {
@@ -1986,6 +2080,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
MemberLookup lookup = new MemberLookup(context, t, t.ProjectContent);
+ ResolveResult r;
if (lookupMode == SimpleNameLookupMode.Expression || lookupMode == SimpleNameLookupMode.InvocationTarget) {
r = lookup.Lookup(new TypeResolveResult(t), identifier, typeArguments, lookupMode == SimpleNameLookupMode.InvocationTarget);
} else {
@@ -1994,9 +2089,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (!(r is UnknownMemberResolveResult)) // but do return AmbiguousMemberResolveResult
return r;
}
-
+ return null;
+ }
+
+ ResolveResult LookInCurrentUsingScope(string identifier, IList typeArguments, bool isInUsingDeclaration, bool parameterizeResultType)
+ {
+ int k = typeArguments.Count;
// look in current namespace definitions
- for (UsingScope n = this.CurrentUsingScope; n != null; n = n.Parent) {
+ UsingScope currentUsingScope = this.CurrentUsingScope;
+ for (UsingScope n = currentUsingScope; n != null; n = n.Parent) {
// first look for a namespace
if (k == 0) {
string fullName = NamespaceDeclaration.BuildQualifiedName(n.NamespaceName, identifier);
@@ -2023,7 +2124,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (n.ExternAliases.Contains(identifier)) {
return ResolveExternAlias(identifier);
}
- if (lookupMode != SimpleNameLookupMode.TypeInUsingDeclaration || n != this.CurrentUsingScope) {
+ if (!(isInUsingDeclaration && n == currentUsingScope)) {
foreach (var pair in n.UsingAliases) {
if (pair.Key == identifier) {
NamespaceResolveResult ns = pair.Value.ResolveNamespace(context);
@@ -2036,7 +2137,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
}
// finally, look in the imported namespaces:
- if (lookupMode != SimpleNameLookupMode.TypeInUsingDeclaration || n != this.CurrentUsingScope) {
+ if (!(isInUsingDeclaration && n == currentUsingScope)) {
IType firstResult = null;
foreach (var u in n.Usings) {
NamespaceResolveResult ns = u.ResolveNamespace(context);
@@ -2059,14 +2160,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
// if we didn't find anything: repeat lookup with parent namespace
}
- if (typeArguments.Count == 0) {
- if (identifier == "dynamic")
- return new TypeResolveResult(SharedTypes.Dynamic);
- else
- return new UnknownIdentifierResolveResult(identifier);
- } else {
- return ErrorResult;
- }
+ return null;
}
///