Browse Source

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
shortcuts
Daniel Grunwald 17 years ago
parent
commit
aef5688593
  1. 51
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultClass.cs
  2. 21
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/SearchClassReturnType.cs
  3. 20
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryASTConvertVisitor.cs
  4. 41
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/TypeVisitor.cs
  5. 35
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/IProjectContent.cs

51
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultClass.cs

@ -374,13 +374,7 @@ namespace ICSharpCode.SharpDevelop.Dom
return CompareTo((IClass)o); return CompareTo((IClass)o);
} }
sealed class InheritanceTreeCache volatile IClass[] inheritanceTreeCache;
{
internal IClass[] inheritanceTree;
internal bool isCreating;
}
volatile InheritanceTreeCache inheritanceTreeCache;
public IEnumerable<IClass> ClassInheritanceTree { public IEnumerable<IClass> ClassInheritanceTree {
get { get {
@ -392,47 +386,24 @@ namespace ICSharpCode.SharpDevelop.Dom
// Especially the recursive calls are tricky, this has caused incorrect behavior (SD2-1474) // Especially the recursive calls are tricky, this has caused incorrect behavior (SD2-1474)
// or performance problems (SD2-1510) in the past. // or performance problems (SD2-1510) in the past.
// get the inheritanceTreeCache, creating it if required IClass[] inheritanceTree = this.inheritanceTreeCache;
// (on demand-creation saves memory - lots of classes never need a ClassInheritanceTree) if (inheritanceTree != null) {
InheritanceTreeCache inheritanceTreeCache = this.inheritanceTreeCache; return inheritanceTree;
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
} }
// now we have the inheritanceTreeCache -> lock on it inheritanceTree = CalculateClassInheritanceTree();
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<IClass>.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; this.inheritanceTreeCache = inheritanceTree;
} if (!KeepInheritanceTree)
DomCache.RegisterForClear(ClearCachedInheritanceTree);
return inheritanceTree;
} }
} }
void ClearCachedInheritanceTree() void ClearCachedInheritanceTree()
{ {
lock (inheritanceTreeCache) { inheritanceTreeCache = null;
inheritanceTreeCache.inheritanceTree = null;
}
} }
IClass[] CalculateClassInheritanceTree() IClass[] CalculateClassInheritanceTree()

21
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/SearchClassReturnType.cs

@ -24,6 +24,7 @@ namespace ICSharpCode.SharpDevelop.Dom
string name; string name;
string shortName; string shortName;
int typeParameterCount; int typeParameterCount;
bool lookForInnerClassesInDeclaringClass = true;
public SearchClassReturnType(IProjectContent projectContent, IClass declaringClass, int caretLine, int caretColumn, string name, int typeParameterCount) 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); shortName = name.Substring(pos + 1);
} }
/// <summary>
/// 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.
/// </summary>
public bool LookForInnerClassesInDeclaringClass {
get { return lookForInnerClassesInDeclaringClass; }
set {
lookForInnerClassesInDeclaringClass = value;
ClearCachedBaseType();
}
}
volatile IReturnType cachedBaseType; volatile IReturnType cachedBaseType;
int isSearching; // 0=false, 1=true int isSearching; // 0=false, 1=true
@ -58,7 +72,12 @@ namespace ICSharpCode.SharpDevelop.Dom
if (Interlocked.CompareExchange(ref isSearching, 1, 0) != 0) if (Interlocked.CompareExchange(ref isSearching, 1, 0) != 0)
return null; return null;
try { 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; cachedBaseType = type;
if (type != null) if (type != null)
DomCache.RegisterForClear(ClearCachedBaseType); DomCache.RegisterForClear(ClearCachedBaseType);

20
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) { if (c.ClassType != ClassType.Enum && typeDeclaration.BaseTypes != null) {
foreach (AST.TypeReference type in typeDeclaration.BaseTypes) { foreach (AST.TypeReference type in typeDeclaration.BaseTypes) {
IReturnType rt = CreateReturnType(type); IReturnType rt = CreateReturnType(type, null, TypeVisitor.ReturnTypeOptions.BaseTypeReference);
if (rt != null) { if (rt != null) {
c.BaseTypes.Add(rt); 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) 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)); DefaultParameter p = new DefaultParameter(par.ParameterName, parType, GetRegion(par.StartLocation, par.EndLocation));
p.Modifiers = (ParameterModifiers)par.ParamModifier; p.Modifiers = (ParameterModifiers)par.ParamModifier;
return p; return p;
@ -524,7 +524,7 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
method.IsExtensionMethod = methodDeclaration.IsExtensionMethod; method.IsExtensionMethod = methodDeclaration.IsExtensionMethod;
method.Documentation = GetDocumentation(region.BeginLine, methodDeclaration.Attributes); method.Documentation = GetDocumentation(region.BeginLine, methodDeclaration.Attributes);
ConvertTemplates(methodDeclaration.Templates, method); ConvertTemplates(methodDeclaration.Templates, method);
method.ReturnType = CreateReturnType(methodDeclaration.TypeReference, method); method.ReturnType = CreateReturnType(methodDeclaration.TypeReference, method, TypeVisitor.ReturnTypeOptions.None);
ConvertAttributes(methodDeclaration, method); ConvertAttributes(methodDeclaration, method);
if (methodDeclaration.Parameters.Count > 0) { if (methodDeclaration.Parameters.Count > 0) {
foreach (AST.ParameterDeclarationExpression par in methodDeclaration.Parameters) { foreach (AST.ParameterDeclarationExpression par in methodDeclaration.Parameters) {
@ -559,7 +559,7 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
method.Documentation = GetDocumentation(region.BeginLine, declareDeclaration.Attributes); method.Documentation = GetDocumentation(region.BeginLine, declareDeclaration.Attributes);
method.Modifiers |= ModifierEnum.Extern | ModifierEnum.Static; method.Modifiers |= ModifierEnum.Extern | ModifierEnum.Static;
method.ReturnType = CreateReturnType(declareDeclaration.TypeReference, method); method.ReturnType = CreateReturnType(declareDeclaration.TypeReference, method, TypeVisitor.ReturnTypeOptions.None);
ConvertAttributes(declareDeclaration, method); ConvertAttributes(declareDeclaration, method);
foreach (AST.ParameterDeclarationExpression par in declareDeclaration.Parameters) { foreach (AST.ParameterDeclarationExpression par in declareDeclaration.Parameters) {
@ -753,23 +753,23 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
return null; 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) { 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 { } 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) IReturnType CreateReturnType(AST.TypeReference reference)
{ {
return CreateReturnType(reference, null); return CreateReturnType(reference, null, TypeVisitor.ReturnTypeOptions.None);
} }
} }
} }

41
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 // TODO: Rename this class, the visitor functionality was moved to ResolveVisitor
public static class TypeVisitor public static class TypeVisitor
{ {
[Flags]
public enum ReturnTypeOptions
{
None = 0,
Lazy = 1,
BaseTypeReference = 2
}
public static IReturnType CreateReturnType(TypeReference reference, NRefactoryResolver resolver) public static IReturnType CreateReturnType(TypeReference reference, NRefactoryResolver resolver)
{ {
return CreateReturnType(reference, return CreateReturnType(reference,
resolver.CallingClass, resolver.CallingMember, resolver.CallingClass, resolver.CallingMember,
resolver.CaretLine, resolver.CaretColumn, 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, public static IReturnType CreateReturnType(TypeReference reference, IClass callingClass,
IMember callingMember, int caretLine, int caretColumn, IMember callingMember, int caretLine, int caretColumn,
IProjectContent projectContent, IProjectContent projectContent,
bool useLazyReturnType) 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 == null) return null;
if (reference.IsNull) return null; if (reference.IsNull) return null;
if (reference is InnerClassTypeReference) { if (reference is InnerClassTypeReference) {
reference = ((InnerClassTypeReference)reference).CombineToNormalTypeReference(); reference = ((InnerClassTypeReference)reference).CombineToNormalTypeReference();
} }
bool useLazyReturnType = (options & ReturnTypeOptions.Lazy) == ReturnTypeOptions.Lazy;
bool isBaseTypeReference = (options & ReturnTypeOptions.BaseTypeReference) == ReturnTypeOptions.BaseTypeReference;
LanguageProperties languageProperties = projectContent.Language; LanguageProperties languageProperties = projectContent.Language;
IReturnType t = null; IReturnType t = null;
if (callingClass != null && !reference.IsGlobal) { if (callingClass != null && !reference.IsGlobal) {
@ -57,7 +80,7 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
} }
} }
if (t == null) { if (t == null) {
if (reference.Type != reference.Type) { if (reference.IsKeyword) {
// keyword-type like void, int, string etc. // keyword-type like void, int, string etc.
IClass c = projectContent.GetClass(reference.Type, 0); IClass c = projectContent.GetClass(reference.Type, 0);
if (c != null) if (c != null)
@ -66,11 +89,15 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
t = new GetClassReturnType(projectContent, reference.Type, 0); t = new GetClassReturnType(projectContent, reference.Type, 0);
} else { } else {
int typeParameterCount = reference.GenericTypes.Count; int typeParameterCount = reference.GenericTypes.Count;
if (useLazyReturnType) { if (useLazyReturnType || isBaseTypeReference) {
if (reference.IsGlobal || reference.IsKeyword) if (reference.IsGlobal) {
t = new GetClassReturnType(projectContent, reference.Type, typeParameterCount); t = new GetClassReturnType(projectContent, reference.Type, typeParameterCount);
else if (callingClass != null) } else if (callingClass != null) {
t = new SearchClassReturnType(projectContent, callingClass, caretLine, caretColumn, reference.Type, typeParameterCount); SearchClassReturnType scrt = new SearchClassReturnType(projectContent, callingClass, caretLine, caretColumn, reference.Type, typeParameterCount);
if (isBaseTypeReference)
scrt.LookForInnerClassesInDeclaringClass = false;
t = scrt;
}
} else { } else {
IClass c; IClass c;
if (reference.IsGlobal || reference.IsKeyword) { if (reference.IsGlobal || reference.IsKeyword) {
@ -88,7 +115,7 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
if (reference.GenericTypes.Count > 0) { if (reference.GenericTypes.Count > 0) {
List<IReturnType> para = new List<IReturnType>(reference.GenericTypes.Count); List<IReturnType> para = new List<IReturnType>(reference.GenericTypes.Count);
for (int i = 0; i < reference.GenericTypes.Count; ++i) { 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); t = new ConstructedReturnType(t, para);
} }

35
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/IProjectContent.cs

@ -138,15 +138,34 @@ namespace ICSharpCode.SharpDevelop.Dom
Default = LookInReferences | LookForInnerClass Default = LookInReferences | LookForInnerClass
} }
public struct SearchTypeRequest public sealed class SearchTypeRequest
{ {
public readonly string Name; IUsingScope currentUsingScope;
public readonly int TypeParameterCount; ICompilationUnit currentCompilationUnit;
public readonly ICompilationUnit CurrentCompilationUnit;
public readonly IClass CurrentType; public string Name { get; set; }
public readonly int CaretLine; public int TypeParameterCount { get; set; }
public readonly int CaretColumn; public IClass CurrentType { get; set; }
public readonly IUsingScope CurrentUsingScope; 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) public SearchTypeRequest(string name, int typeParameterCount, IClass currentType, int caretLine, int caretColumn)
{ {

Loading…
Cancel
Save