From aef568859349e3c1641bef352fc4d2aef0d184b8 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 21 Jan 2009 16:35:54 +0000 Subject: [PATCH] Fixed SD2-1510: Too slow startup when DesignerViewContent.cs was open (different solution to the problem, the previous commit introduced errors) git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@3769 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Src/Implementations/DefaultClass.cs | 53 +++++-------------- .../Implementations/SearchClassReturnType.cs | 21 +++++++- .../NRefactoryASTConvertVisitor.cs | 20 +++---- .../Src/NRefactoryResolver/TypeVisitor.cs | 41 +++++++++++--- .../Src/ProjectContent/IProjectContent.cs | 35 +++++++++--- 5 files changed, 103 insertions(+), 67 deletions(-) diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultClass.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultClass.cs index 607f0390af..04cdc4f642 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultClass.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultClass.cs @@ -374,13 +374,7 @@ namespace ICSharpCode.SharpDevelop.Dom return CompareTo((IClass)o); } - sealed class InheritanceTreeCache - { - internal IClass[] inheritanceTree; - internal bool isCreating; - } - - volatile InheritanceTreeCache inheritanceTreeCache; + volatile IClass[] inheritanceTreeCache; public IEnumerable ClassInheritanceTree { get { @@ -392,47 +386,24 @@ namespace ICSharpCode.SharpDevelop.Dom // Especially the recursive calls are tricky, this has caused incorrect behavior (SD2-1474) // or performance problems (SD2-1510) in the past. - // get the inheritanceTreeCache, creating it if required - // (on demand-creation saves memory - lots of classes never need a ClassInheritanceTree) - InheritanceTreeCache inheritanceTreeCache = this.inheritanceTreeCache; - if (inheritanceTreeCache == null) { - // but ensure only one is created, even when ClassInheritanceTree is called by multiple threads - InheritanceTreeCache newCache = new InheritanceTreeCache(); - #pragma warning disable 420 - // Warning CS0420: 'ICSharpCode.SharpDevelop.Dom.DefaultClass.inheritanceTreeCache': a reference to a volatile field will not be treated as volatile - // We disable this warning because Interlocked.* treats the location as volatile, even though - // normally ref-parameters in C# lose the volatile modifier. - inheritanceTreeCache = Interlocked.CompareExchange(ref this.inheritanceTreeCache, newCache, null) ?? newCache; - #pragma warning restore 420 + IClass[] inheritanceTree = this.inheritanceTreeCache; + if (inheritanceTree != null) { + return inheritanceTree; } - // now we have the inheritanceTreeCache -> lock on it - lock (inheritanceTreeCache) { - if (inheritanceTreeCache.inheritanceTree == null) { - // inheritance tree does not exist yet - if (inheritanceTreeCache.isCreating) { - // this is a recursive call -> don't produce inheritance tree - return EmptyList.Instance; - } else { - // now produce the actual inheritance tree - inheritanceTreeCache.isCreating = true; - inheritanceTreeCache.inheritanceTree = CalculateClassInheritanceTree(); - inheritanceTreeCache.isCreating = false; - if (!KeepInheritanceTree) - DomCache.RegisterForClear(ClearCachedInheritanceTree); - } - } - - return inheritanceTreeCache.inheritanceTree; - } + inheritanceTree = CalculateClassInheritanceTree(); + + this.inheritanceTreeCache = inheritanceTree; + if (!KeepInheritanceTree) + DomCache.RegisterForClear(ClearCachedInheritanceTree); + + return inheritanceTree; } } void ClearCachedInheritanceTree() { - lock (inheritanceTreeCache) { - inheritanceTreeCache.inheritanceTree = null; - } + inheritanceTreeCache = null; } IClass[] CalculateClassInheritanceTree() diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/SearchClassReturnType.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/SearchClassReturnType.cs index 99e590b037..1fdbc70afd 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/SearchClassReturnType.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/SearchClassReturnType.cs @@ -24,6 +24,7 @@ namespace ICSharpCode.SharpDevelop.Dom string name; string shortName; int typeParameterCount; + bool lookForInnerClassesInDeclaringClass = true; public SearchClassReturnType(IProjectContent projectContent, IClass declaringClass, int caretLine, int caretColumn, string name, int typeParameterCount) { @@ -42,6 +43,19 @@ namespace ICSharpCode.SharpDevelop.Dom shortName = name.Substring(pos + 1); } + /// + /// Gets/Sets whether to look for inner classes in the declaring class. + /// The default is true. + /// Set this property to false for return types that are used as base type references. + /// + public bool LookForInnerClassesInDeclaringClass { + get { return lookForInnerClassesInDeclaringClass; } + set { + lookForInnerClassesInDeclaringClass = value; + ClearCachedBaseType(); + } + } + volatile IReturnType cachedBaseType; int isSearching; // 0=false, 1=true @@ -58,7 +72,12 @@ namespace ICSharpCode.SharpDevelop.Dom if (Interlocked.CompareExchange(ref isSearching, 1, 0) != 0) return null; try { - type = pc.SearchType(new SearchTypeRequest(name, typeParameterCount, declaringClass, caretLine, caretColumn)).Result; + SearchTypeRequest request = new SearchTypeRequest(name, typeParameterCount, declaringClass, caretLine, caretColumn); + if (!lookForInnerClassesInDeclaringClass) { + // skip looking for inner classes by adjusting the CurrentType for the lookup + request.CurrentType = declaringClass.DeclaringType; + } + type = pc.SearchType(request).Result; cachedBaseType = type; if (type != null) DomCache.RegisterForClear(ClearCachedBaseType); diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryASTConvertVisitor.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryASTConvertVisitor.cs index fc6d30b1e7..681e199325 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryASTConvertVisitor.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryASTConvertVisitor.cs @@ -388,7 +388,7 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver if (c.ClassType != ClassType.Enum && typeDeclaration.BaseTypes != null) { foreach (AST.TypeReference type in typeDeclaration.BaseTypes) { - IReturnType rt = CreateReturnType(type); + IReturnType rt = CreateReturnType(type, null, TypeVisitor.ReturnTypeOptions.BaseTypeReference); if (rt != null) { c.BaseTypes.Add(rt); } @@ -508,7 +508,7 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver internal static IParameter CreateParameter(AST.ParameterDeclarationExpression par, IMethod method, IClass currentClass, ICompilationUnit cu) { - IReturnType parType = CreateReturnType(par.TypeReference, method, currentClass, cu); + IReturnType parType = CreateReturnType(par.TypeReference, method, currentClass, cu, TypeVisitor.ReturnTypeOptions.None); DefaultParameter p = new DefaultParameter(par.ParameterName, parType, GetRegion(par.StartLocation, par.EndLocation)); p.Modifiers = (ParameterModifiers)par.ParamModifier; return p; @@ -524,7 +524,7 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver method.IsExtensionMethod = methodDeclaration.IsExtensionMethod; method.Documentation = GetDocumentation(region.BeginLine, methodDeclaration.Attributes); ConvertTemplates(methodDeclaration.Templates, method); - method.ReturnType = CreateReturnType(methodDeclaration.TypeReference, method); + method.ReturnType = CreateReturnType(methodDeclaration.TypeReference, method, TypeVisitor.ReturnTypeOptions.None); ConvertAttributes(methodDeclaration, method); if (methodDeclaration.Parameters.Count > 0) { foreach (AST.ParameterDeclarationExpression par in methodDeclaration.Parameters) { @@ -559,7 +559,7 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver method.Documentation = GetDocumentation(region.BeginLine, declareDeclaration.Attributes); method.Modifiers |= ModifierEnum.Extern | ModifierEnum.Static; - method.ReturnType = CreateReturnType(declareDeclaration.TypeReference, method); + method.ReturnType = CreateReturnType(declareDeclaration.TypeReference, method, TypeVisitor.ReturnTypeOptions.None); ConvertAttributes(declareDeclaration, method); foreach (AST.ParameterDeclarationExpression par in declareDeclaration.Parameters) { @@ -753,23 +753,23 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver return null; } - IReturnType CreateReturnType(AST.TypeReference reference, IMethod method) + IReturnType CreateReturnType(AST.TypeReference reference, IMethod method, TypeVisitor.ReturnTypeOptions options) { - return CreateReturnType(reference, method, GetCurrentClass(), cu); + return CreateReturnType(reference, method, GetCurrentClass(), cu, options); } - static IReturnType CreateReturnType(AST.TypeReference reference, IMethod method, IClass currentClass, ICompilationUnit cu) + static IReturnType CreateReturnType(AST.TypeReference reference, IMethod method, IClass currentClass, ICompilationUnit cu, TypeVisitor.ReturnTypeOptions options) { if (currentClass == null) { - return TypeVisitor.CreateReturnType(reference, new DefaultClass(cu, "___DummyClass"), method, 1, 1, cu.ProjectContent, true); + return TypeVisitor.CreateReturnType(reference, new DefaultClass(cu, "___DummyClass"), method, 1, 1, cu.ProjectContent, options | TypeVisitor.ReturnTypeOptions.Lazy); } else { - return TypeVisitor.CreateReturnType(reference, currentClass, method, currentClass.Region.BeginLine + 1, 1, cu.ProjectContent, true); + return TypeVisitor.CreateReturnType(reference, currentClass, method, currentClass.Region.BeginLine + 1, 1, cu.ProjectContent, options | TypeVisitor.ReturnTypeOptions.Lazy); } } IReturnType CreateReturnType(AST.TypeReference reference) { - return CreateReturnType(reference, null); + return CreateReturnType(reference, null, TypeVisitor.ReturnTypeOptions.None); } } } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/TypeVisitor.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/TypeVisitor.cs index aefb823405..83d5a256fd 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/TypeVisitor.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/TypeVisitor.cs @@ -20,24 +20,47 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver // TODO: Rename this class, the visitor functionality was moved to ResolveVisitor public static class TypeVisitor { + [Flags] + public enum ReturnTypeOptions + { + None = 0, + Lazy = 1, + BaseTypeReference = 2 + } + public static IReturnType CreateReturnType(TypeReference reference, NRefactoryResolver resolver) { return CreateReturnType(reference, resolver.CallingClass, resolver.CallingMember, resolver.CaretLine, resolver.CaretColumn, - resolver.ProjectContent, false); + resolver.ProjectContent, ReturnTypeOptions.None); } + [Obsolete("Use the overload with ReturnTypeOptions instead")] public static IReturnType CreateReturnType(TypeReference reference, IClass callingClass, IMember callingMember, int caretLine, int caretColumn, IProjectContent projectContent, bool useLazyReturnType) + { + return CreateReturnType(reference, callingClass, callingMember, caretLine, caretColumn, + projectContent, + useLazyReturnType ? ReturnTypeOptions.Lazy : ReturnTypeOptions.None); + } + + public static IReturnType CreateReturnType(TypeReference reference, IClass callingClass, + IMember callingMember, int caretLine, int caretColumn, + IProjectContent projectContent, + ReturnTypeOptions options) { if (reference == null) return null; if (reference.IsNull) return null; if (reference is InnerClassTypeReference) { reference = ((InnerClassTypeReference)reference).CombineToNormalTypeReference(); } + + bool useLazyReturnType = (options & ReturnTypeOptions.Lazy) == ReturnTypeOptions.Lazy; + bool isBaseTypeReference = (options & ReturnTypeOptions.BaseTypeReference) == ReturnTypeOptions.BaseTypeReference; + LanguageProperties languageProperties = projectContent.Language; IReturnType t = null; if (callingClass != null && !reference.IsGlobal) { @@ -57,7 +80,7 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver } } if (t == null) { - if (reference.Type != reference.Type) { + if (reference.IsKeyword) { // keyword-type like void, int, string etc. IClass c = projectContent.GetClass(reference.Type, 0); if (c != null) @@ -66,11 +89,15 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver t = new GetClassReturnType(projectContent, reference.Type, 0); } else { int typeParameterCount = reference.GenericTypes.Count; - if (useLazyReturnType) { - if (reference.IsGlobal || reference.IsKeyword) + if (useLazyReturnType || isBaseTypeReference) { + if (reference.IsGlobal) { t = new GetClassReturnType(projectContent, reference.Type, typeParameterCount); - else if (callingClass != null) - t = new SearchClassReturnType(projectContent, callingClass, caretLine, caretColumn, reference.Type, typeParameterCount); + } else if (callingClass != null) { + SearchClassReturnType scrt = new SearchClassReturnType(projectContent, callingClass, caretLine, caretColumn, reference.Type, typeParameterCount); + if (isBaseTypeReference) + scrt.LookForInnerClassesInDeclaringClass = false; + t = scrt; + } } else { IClass c; if (reference.IsGlobal || reference.IsKeyword) { @@ -88,7 +115,7 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver if (reference.GenericTypes.Count > 0) { List para = new List(reference.GenericTypes.Count); for (int i = 0; i < reference.GenericTypes.Count; ++i) { - para.Add(CreateReturnType(reference.GenericTypes[i], callingClass, callingMember, caretLine, caretColumn, projectContent, useLazyReturnType)); + para.Add(CreateReturnType(reference.GenericTypes[i], callingClass, callingMember, caretLine, caretColumn, projectContent, options)); } t = new ConstructedReturnType(t, para); } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/IProjectContent.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/IProjectContent.cs index c1eb3c4ac3..d18efae547 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/IProjectContent.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/IProjectContent.cs @@ -138,15 +138,34 @@ namespace ICSharpCode.SharpDevelop.Dom Default = LookInReferences | LookForInnerClass } - public struct SearchTypeRequest + public sealed class SearchTypeRequest { - public readonly string Name; - public readonly int TypeParameterCount; - public readonly ICompilationUnit CurrentCompilationUnit; - public readonly IClass CurrentType; - public readonly int CaretLine; - public readonly int CaretColumn; - public readonly IUsingScope CurrentUsingScope; + IUsingScope currentUsingScope; + ICompilationUnit currentCompilationUnit; + + public string Name { get; set; } + public int TypeParameterCount { get; set; } + public IClass CurrentType { get; set; } + public int CaretLine { get; set; } + public int CaretColumn { get; set; } + + public ICompilationUnit CurrentCompilationUnit { + get { return currentCompilationUnit; } + set { + if (value == null) + throw new ArgumentNullException("CurrentCompilationUnit"); + currentCompilationUnit = value; + } + } + + public IUsingScope CurrentUsingScope { + get { return currentUsingScope; } + set { + if (value == null) + throw new ArgumentNullException("CurrentUsingScope"); + currentUsingScope = value; + } + } public SearchTypeRequest(string name, int typeParameterCount, IClass currentType, int caretLine, int caretColumn) {