Browse Source

Use 'UsingScopeCache' instance for caching the extension methods.

newNRvisualizers
Daniel Grunwald 15 years ago
parent
commit
82fad4ef64
  1. 4
      ICSharpCode.NRefactory/CSharp/Refactoring/TypeSystemAstBuilder.cs
  2. 2
      ICSharpCode.NRefactory/CSharp/Resolver/AliasNamespaceReference.cs
  3. 97
      ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs
  4. 2
      ICSharpCode.NRefactory/CSharp/Resolver/ConstantValues.cs
  5. 2
      ICSharpCode.NRefactory/CSharp/Resolver/MemberTypeOrNamespaceReference.cs
  6. 6
      ICSharpCode.NRefactory/CSharp/Resolver/MethodGroupResolveResult.cs
  7. 26
      ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs
  8. 2
      ICSharpCode.NRefactory/CSharp/Resolver/SimpleTypeOrNamespaceReference.cs

4
ICSharpCode.NRefactory/CSharp/Refactoring/TypeSystemAstBuilder.cs

@ -115,7 +115,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (resolver != null) { if (resolver != null) {
// Look if there's an alias to the target type // Look if there's an alias to the target type
for (UsingScope usingScope = resolver.UsingScope; usingScope != null; usingScope = usingScope.Parent) { for (UsingScope usingScope = resolver.CurrentUsingScope; usingScope != null; usingScope = usingScope.Parent) {
foreach (var pair in usingScope.UsingAliases) { foreach (var pair in usingScope.UsingAliases) {
IType type = pair.Value.Resolve(resolver.Context); IType type = pair.Value.Resolve(resolver.Context);
if (TypeMatches(type, typeDef, typeArguments)) if (TypeMatches(type, typeDef, typeArguments))
@ -200,7 +200,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
if (resolver != null) { if (resolver != null) {
// Look if there's an alias to the target namespace // Look if there's an alias to the target namespace
for (UsingScope usingScope = resolver.UsingScope; usingScope != null; usingScope = usingScope.Parent) { for (UsingScope usingScope = resolver.CurrentUsingScope; usingScope != null; usingScope = usingScope.Parent) {
foreach (var pair in usingScope.UsingAliases) { foreach (var pair in usingScope.UsingAliases) {
// maybe add some caching? we're resolving all aliases N times when converting a namespace name with N parts // maybe add some caching? we're resolving all aliases N times when converting a namespace name with N parts
NamespaceResolveResult nrr = pair.Value.ResolveNamespace(resolver.Context); NamespaceResolveResult nrr = pair.Value.ResolveNamespace(resolver.Context);

2
ICSharpCode.NRefactory/CSharp/Resolver/AliasNamespaceReference.cs

@ -45,7 +45,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public ResolveResult DoResolve(ITypeResolveContext context) public ResolveResult DoResolve(ITypeResolveContext context)
{ {
CSharpResolver r = new CSharpResolver(context); CSharpResolver r = new CSharpResolver(context);
r.UsingScope = parentUsingScope; r.CurrentUsingScope = parentUsingScope;
return r.ResolveAlias(identifier); return r.ResolveAlias(identifier);
} }

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

@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization; using System.Globalization;
@ -25,6 +26,7 @@ using System.Text;
using System.Threading; using System.Threading;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation; using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.CSharp.Resolver namespace ICSharpCode.NRefactory.CSharp.Resolver
{ {
@ -82,10 +84,67 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// </summary> /// </summary>
public ITypeDefinition CurrentTypeDefinition { get; set; } public ITypeDefinition CurrentTypeDefinition { get; set; }
UsingScopeCache currentUsingScope;
/// <summary> /// <summary>
/// Gets/Sets the current using scope that is used to look up identifiers as class names. /// Gets/Sets the current using scope that is used to look up identifiers as class names.
/// </summary> /// </summary>
public UsingScope UsingScope { get; set; } public UsingScope CurrentUsingScope {
get { return currentUsingScope != null ? currentUsingScope.UsingScope : null; }
set {
if (value == null) {
currentUsingScope = null;
} else {
if (currentUsingScope != null && currentUsingScope.UsingScope == value)
return;
CacheManager cache = context.CacheManager;
if (cache != null) {
object obj;
if (cache.Dictionary.TryGetValue(value, out obj)) {
currentUsingScope = (UsingScopeCache)obj;
} else {
currentUsingScope = new UsingScopeCache(value);
cache.Dictionary.TryAdd(value, currentUsingScope);
}
} else {
currentUsingScope = new UsingScopeCache(value);
}
}
}
}
/// <summary>
/// Gets the current project content.
/// Returns <c>CurrentUsingScope.ProjectContent</c>.
/// </summary>
public IProjectContent ProjectContent {
get {
if (currentUsingScope != null)
return currentUsingScope.UsingScope.ProjectContent;
else
return null;
}
}
#endregion
#region Per-UsingScope Cache
/// <summary>
/// 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.
/// </summary>
sealed class UsingScopeCache
{
public readonly UsingScope UsingScope;
public volatile List<List<IMethod>> AllExtensionMethods;
public UsingScopeCache(UsingScope usingScope)
{
this.UsingScope = usingScope;
}
}
#endregion #endregion
#region Local Variable Management #region Local Variable Management
@ -1910,6 +1969,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (parameterizeResultType && typeArguments.All(t => t.Kind == TypeKind.UnboundTypeArgument)) if (parameterizeResultType && typeArguments.All(t => t.Kind == TypeKind.UnboundTypeArgument))
parameterizeResultType = false; parameterizeResultType = false;
ResolveResult r;
// look in current type definitions // look in current type definitions
for (ITypeDefinition t = this.CurrentTypeDefinition; t != null; t = t.DeclaringTypeDefinition) { for (ITypeDefinition t = this.CurrentTypeDefinition; t != null; t = t.DeclaringTypeDefinition) {
if (k == 0) { if (k == 0) {
@ -1928,7 +1988,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
MemberLookup lookup = new MemberLookup(context, t, t.ProjectContent); MemberLookup lookup = new MemberLookup(context, t, t.ProjectContent);
ResolveResult r;
if (lookupMode == SimpleNameLookupMode.Expression || lookupMode == SimpleNameLookupMode.InvocationTarget) { if (lookupMode == SimpleNameLookupMode.Expression || lookupMode == SimpleNameLookupMode.InvocationTarget) {
r = lookup.Lookup(new TypeResolveResult(t), identifier, typeArguments, lookupMode == SimpleNameLookupMode.InvocationTarget); r = lookup.Lookup(new TypeResolveResult(t), identifier, typeArguments, lookupMode == SimpleNameLookupMode.InvocationTarget);
} else { } else {
@ -1939,7 +1998,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
// look in current namespace definitions // look in current namespace definitions
for (UsingScope n = this.UsingScope; n != null; n = n.Parent) { for (UsingScope n = this.CurrentUsingScope; n != null; n = n.Parent) {
// first look for a namespace // first look for a namespace
if (k == 0) { if (k == 0) {
string fullName = NamespaceDeclaration.BuildQualifiedName(n.NamespaceName, identifier); string fullName = NamespaceDeclaration.BuildQualifiedName(n.NamespaceName, identifier);
@ -1966,7 +2025,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (n.ExternAliases.Contains(identifier)) { if (n.ExternAliases.Contains(identifier)) {
return ResolveExternAlias(identifier); return ResolveExternAlias(identifier);
} }
if (lookupMode != SimpleNameLookupMode.TypeInUsingDeclaration || n != this.UsingScope) { if (lookupMode != SimpleNameLookupMode.TypeInUsingDeclaration || n != this.CurrentUsingScope) {
foreach (var pair in n.UsingAliases) { foreach (var pair in n.UsingAliases) {
if (pair.Key == identifier) { if (pair.Key == identifier) {
NamespaceResolveResult ns = pair.Value.ResolveNamespace(context); NamespaceResolveResult ns = pair.Value.ResolveNamespace(context);
@ -1979,7 +2038,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
} }
// finally, look in the imported namespaces: // finally, look in the imported namespaces:
if (lookupMode != SimpleNameLookupMode.TypeInUsingDeclaration || n != this.UsingScope) { if (lookupMode != SimpleNameLookupMode.TypeInUsingDeclaration || n != this.CurrentUsingScope) {
IType firstResult = null; IType firstResult = null;
foreach (var u in n.Usings) { foreach (var u in n.Usings) {
NamespaceResolveResult ns = u.ResolveNamespace(context); NamespaceResolveResult ns = u.ResolveNamespace(context);
@ -2020,7 +2079,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (identifier == "global") if (identifier == "global")
return new NamespaceResolveResult(string.Empty); return new NamespaceResolveResult(string.Empty);
for (UsingScope n = this.UsingScope; n != null; n = n.Parent) { for (UsingScope n = this.CurrentUsingScope; n != null; n = n.Parent) {
if (n.ExternAliases.Contains(identifier)) { if (n.ExternAliases.Contains(identifier)) {
return ResolveExternAlias(identifier); return ResolveExternAlias(identifier);
} }
@ -2033,7 +2092,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return ErrorResult; return ErrorResult;
} }
ResolveResult ResolveExternAlias(string alias) static ResolveResult ResolveExternAlias(string alias)
{ {
// TODO: implement extern alias support // TODO: implement extern alias support
return new NamespaceResolveResult(string.Empty); return new NamespaceResolveResult(string.Empty);
@ -2069,7 +2128,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (mgrr != null) { if (mgrr != null) {
Debug.Assert(mgrr.extensionMethods == null); Debug.Assert(mgrr.extensionMethods == null);
// set the values that are necessary to make MethodGroupResolveResult.GetExtensionMethods() work // set the values that are necessary to make MethodGroupResolveResult.GetExtensionMethods() work
mgrr.usingScope = this.UsingScope; mgrr.usingScope = this.CurrentUsingScope;
mgrr.resolver = this; mgrr.resolver = this;
} }
} }
@ -2115,7 +2174,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// </summary> /// </summary>
public MemberLookup CreateMemberLookup() public MemberLookup CreateMemberLookup()
{ {
return new MemberLookup(context, this.CurrentTypeDefinition, this.UsingScope != null ? this.UsingScope.ProjectContent : null); return new MemberLookup(context, this.CurrentTypeDefinition, this.ProjectContent);
} }
#endregion #endregion
@ -2178,17 +2237,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// Gets all extension methods available in the current using scope. /// Gets all extension methods available in the current using scope.
/// This list includes unaccessible /// This list includes unaccessible
/// </summary> /// </summary>
List<List<IMethod>> GetAllExtensionMethods() IList<List<IMethod>> GetAllExtensionMethods()
{ {
// TODO: maybe cache the result? if (currentUsingScope == null)
// Idea: class ExtensionMethodGroupCache : List<List<IMethod>> return EmptyList<List<IMethod>>.Instance;
// a new ExtensionMethodGroupCache instance would be created whenever the UsingScope is changed List<List<IMethod>> extensionMethodGroups = currentUsingScope.AllExtensionMethods;
// The list contents would be initialized on-demand. if (extensionMethodGroups != null)
// Because cloning the resolver would re-use the cache, it must be thread-safe. return extensionMethodGroups;
// The cache could be passed to the MethodGroupResolveResult instead of passing the resolver. extensionMethodGroups = new List<List<IMethod>>();
List<List<IMethod>> extensionMethodGroups = new List<List<IMethod>>();
List<IMethod> m; List<IMethod> m;
for (UsingScope scope = this.UsingScope; scope != null; scope = scope.Parent) { for (UsingScope scope = currentUsingScope.UsingScope; scope != null; scope = scope.Parent) {
m = GetExtensionMethods(scope.NamespaceName).ToList(); m = GetExtensionMethods(scope.NamespaceName).ToList();
if (m.Count > 0) if (m.Count > 0)
extensionMethodGroups.Add(m); extensionMethodGroups.Add(m);
@ -2202,6 +2260,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (m.Count > 0) if (m.Count > 0)
extensionMethodGroups.Add(m); extensionMethodGroups.Add(m);
} }
currentUsingScope.AllExtensionMethods = extensionMethodGroups;
return extensionMethodGroups; return extensionMethodGroups;
} }

2
ICSharpCode.NRefactory/CSharp/Resolver/ConstantValues.cs

@ -53,7 +53,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver.ConstantValues
return new CSharpResolver(context) { return new CSharpResolver(context) {
CheckForOverflow = false, // TODO: get project-wide overflow setting CheckForOverflow = false, // TODO: get project-wide overflow setting
CurrentTypeDefinition = parentTypeDefinition, CurrentTypeDefinition = parentTypeDefinition,
UsingScope = parentUsingScope CurrentUsingScope = parentUsingScope
}; };
} }

2
ICSharpCode.NRefactory/CSharp/Resolver/MemberTypeOrNamespaceReference.cs

@ -71,7 +71,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return targetRR; return targetRR;
CSharpResolver r = new CSharpResolver(context); CSharpResolver r = new CSharpResolver(context);
r.CurrentTypeDefinition = parentTypeDefinition; r.CurrentTypeDefinition = parentTypeDefinition;
r.UsingScope = parentUsingScope; r.CurrentUsingScope = parentUsingScope;
IType[] typeArgs = new IType[typeArguments.Count]; IType[] typeArgs = new IType[typeArguments.Count];
for (int i = 0; i < typeArgs.Length; i++) { for (int i = 0; i < typeArgs.Length; i++) {
typeArgs[i] = typeArguments[i].Resolve(context); typeArgs[i] = typeArguments[i].Resolve(context);

6
ICSharpCode.NRefactory/CSharp/Resolver/MethodGroupResolveResult.cs

@ -138,12 +138,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{ {
if (resolver != null) { if (resolver != null) {
Debug.Assert(extensionMethods == null); Debug.Assert(extensionMethods == null);
UsingScope oldUsingScope = resolver.UsingScope; UsingScope oldUsingScope = resolver.CurrentUsingScope;
try { try {
resolver.UsingScope = usingScope; resolver.CurrentUsingScope = usingScope;
extensionMethods = resolver.GetExtensionMethods(this.TargetType, methodName, typeArguments); extensionMethods = resolver.GetExtensionMethods(this.TargetType, methodName, typeArguments);
} finally { } finally {
resolver.UsingScope = oldUsingScope; resolver.CurrentUsingScope = oldUsingScope;
resolver = null; resolver = null;
usingScope = null; usingScope = null;
} }

26
ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs

@ -357,31 +357,31 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#region Track UsingScope #region Track UsingScope
public override ResolveResult VisitCompilationUnit(CompilationUnit unit, object data) public override ResolveResult VisitCompilationUnit(CompilationUnit unit, object data)
{ {
UsingScope previousUsingScope = resolver.UsingScope; UsingScope previousUsingScope = resolver.CurrentUsingScope;
try { try {
if (parsedFile != null) if (parsedFile != null)
resolver.UsingScope = parsedFile.RootUsingScope; resolver.CurrentUsingScope = parsedFile.RootUsingScope;
ScanChildren(unit); ScanChildren(unit);
return voidResult; return voidResult;
} finally { } finally {
resolver.UsingScope = previousUsingScope; resolver.CurrentUsingScope = previousUsingScope;
} }
} }
public override ResolveResult VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration, object data) public override ResolveResult VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration, object data)
{ {
UsingScope previousUsingScope = resolver.UsingScope; UsingScope previousUsingScope = resolver.CurrentUsingScope;
try { try {
if (parsedFile != null) { if (parsedFile != null) {
resolver.UsingScope = parsedFile.GetUsingScope(namespaceDeclaration.StartLocation); resolver.CurrentUsingScope = parsedFile.GetUsingScope(namespaceDeclaration.StartLocation);
} }
ScanChildren(namespaceDeclaration); ScanChildren(namespaceDeclaration);
if (resolver.UsingScope != null) if (resolver.CurrentUsingScope != null)
return new NamespaceResolveResult(resolver.UsingScope.NamespaceName); return new NamespaceResolveResult(resolver.CurrentUsingScope.NamespaceName);
else else
return null; return null;
} finally { } finally {
resolver.UsingScope = previousUsingScope; resolver.CurrentUsingScope = previousUsingScope;
} }
} }
#endregion #endregion
@ -782,11 +782,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public override ResolveResult VisitAnonymousTypeCreateExpression(AnonymousTypeCreateExpression anonymousTypeCreateExpression, object data) public override ResolveResult VisitAnonymousTypeCreateExpression(AnonymousTypeCreateExpression anonymousTypeCreateExpression, object data)
{ {
// 7.6.10.6 Anonymous object creation expressions // 7.6.10.6 Anonymous object creation expressions
if (resolver.UsingScope == null) { if (resolver.ProjectContent == null) {
ScanChildren(anonymousTypeCreateExpression); ScanChildren(anonymousTypeCreateExpression);
return errorResult; return errorResult;
} }
var anonymousType = new DefaultTypeDefinition(resolver.UsingScope.ProjectContent, string.Empty, "$Anonymous$"); var anonymousType = new DefaultTypeDefinition(resolver.ProjectContent, string.Empty, "$Anonymous$");
anonymousType.IsSynthetic = true; anonymousType.IsSynthetic = true;
resolver.PushInitializerType(anonymousType); resolver.PushInitializerType(anonymousType);
foreach (var expr in anonymousTypeCreateExpression.Initializers) { foreach (var expr in anonymousTypeCreateExpression.Initializers) {
@ -2100,7 +2100,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
IConstantValue cv = null; IConstantValue cv = null;
if (isConst) { if (isConst) {
cv = TypeSystemConvertVisitor.ConvertConstantValue(type, vi.Initializer, resolver.CurrentTypeDefinition, resolver.CurrentMember as IMethod, resolver.UsingScope); cv = TypeSystemConvertVisitor.ConvertConstantValue(type, vi.Initializer, resolver.CurrentTypeDefinition, resolver.CurrentMember as IMethod, resolver.CurrentUsingScope);
} }
resolver.AddVariable(type, MakeRegion(vi), vi.Name, cv); resolver.AddVariable(type, MakeRegion(vi), vi.Name, cv);
@ -2299,7 +2299,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ITypeReference MakeTypeReference(AstType type) ITypeReference MakeTypeReference(AstType type)
{ {
return TypeSystemConvertVisitor.ConvertType(type, resolver.CurrentTypeDefinition, resolver.CurrentMember as IMethod, resolver.UsingScope, currentTypeLookupMode); return TypeSystemConvertVisitor.ConvertType(type, resolver.CurrentTypeDefinition, resolver.CurrentMember as IMethod, resolver.CurrentUsingScope, currentTypeLookupMode);
} }
sealed class VarTypeReference : ITypeReference sealed class VarTypeReference : ITypeReference
@ -2440,7 +2440,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ResolveResult HandleAttributeType(AstType astType) ResolveResult HandleAttributeType(AstType astType)
{ {
ScanChildren(astType); ScanChildren(astType);
IType type = TypeSystemConvertVisitor.ConvertAttributeType(astType, resolver.CurrentTypeDefinition, resolver.CurrentMember as IMethod, resolver.UsingScope).Resolve(resolver.Context); IType type = TypeSystemConvertVisitor.ConvertAttributeType(astType, resolver.CurrentTypeDefinition, resolver.CurrentMember as IMethod, resolver.CurrentUsingScope).Resolve(resolver.Context);
if (type.Kind != TypeKind.Unknown) if (type.Kind != TypeKind.Unknown)
return new TypeResolveResult(type); return new TypeResolveResult(type);
else else

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

@ -66,7 +66,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
CSharpResolver r = new CSharpResolver(context); CSharpResolver r = new CSharpResolver(context);
r.CurrentTypeDefinition = parentTypeDefinition; r.CurrentTypeDefinition = parentTypeDefinition;
r.UsingScope = parentUsingScope; r.CurrentUsingScope = parentUsingScope;
IType[] typeArgs = new IType[typeArguments.Count]; IType[] typeArgs = new IType[typeArguments.Count];
for (int i = 0; i < typeArgs.Length; i++) { for (int i = 0; i < typeArgs.Length; i++) {
typeArgs[i] = typeArguments[i].Resolve(context); typeArgs[i] = typeArguments[i].Resolve(context);

Loading…
Cancel
Save