diff --git a/src/AddIns/Misc/ResourceToolkit/Project/ResourceToolkit.csproj b/src/AddIns/Misc/ResourceToolkit/Project/ResourceToolkit.csproj
index 74b475ef81..4c8a52f323 100644
--- a/src/AddIns/Misc/ResourceToolkit/Project/ResourceToolkit.csproj
+++ b/src/AddIns/Misc/ResourceToolkit/Project/ResourceToolkit.csproj
@@ -91,6 +91,8 @@
+
+
diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/BclNRefactoryResourceResolver.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/BclNRefactoryResourceResolver.cs
index d0d4a79a52..d3885a7833 100644
--- a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/BclNRefactoryResourceResolver.cs
+++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/BclNRefactoryResourceResolver.cs
@@ -15,6 +15,7 @@ using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Parser;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Dom;
+using ICSharpCode.SharpDevelop.Project;
using Hornung.ResourceToolkit.ResourceFileContent;
@@ -32,7 +33,7 @@ namespace Hornung.ResourceToolkit.Resolver
/// Tries to find a resource reference in the specified expression.
///
/// The ExpressionResult for the expression.
- /// The AST representation of the expression.
+ /// The AST representation of the full expression.
/// SharpDevelop's ResolveResult for the expression.
/// The line where the expression is located.
/// The column where the expression is located.
@@ -46,13 +47,15 @@ namespace Hornung.ResourceToolkit.Resolver
MemberResolveResult mrr = resolveResult as MemberResolveResult;
if (mrr != null) {
rfc = ResolveResourceFileContent(mrr.ResolvedMember);
- }
-
- LocalResolveResult lrr = resolveResult as LocalResolveResult;
- if (lrr != null) {
- if (!lrr.IsParameter) {
- rfc = ResolveResourceFileContent(lrr.Field);
+ } else {
+
+ LocalResolveResult lrr = resolveResult as LocalResolveResult;
+ if (lrr != null) {
+ if (!lrr.IsParameter) {
+ rfc = ResolveResourceFileContent(lrr.Field);
+ }
}
+
}
@@ -68,6 +71,26 @@ namespace Hornung.ResourceToolkit.Resolver
// ********************************************************************************************************************************
+ #region ResourceFileContent mapping cache
+
+ static Dictionary cachedResourceFileContentMappings;
+
+ static BclNRefactoryResourceResolver()
+ {
+ cachedResourceFileContentMappings = new Dictionary(new MemberEqualityComparer());
+ NRefactoryAstCacheService.CacheEnabledChanged += NRefactoryCacheEnabledChanged;
+ }
+
+ static void NRefactoryCacheEnabledChanged(object sender, EventArgs e)
+ {
+ if (!NRefactoryAstCacheService.CacheEnabled) {
+ // Clear cache when disabled.
+ cachedResourceFileContentMappings.Clear();
+ }
+ }
+
+ #endregion
+
///
/// Tries to determine the resource file content which is referenced by the
/// resource manager which is assigned to the specified member.
@@ -79,33 +102,49 @@ namespace Hornung.ResourceToolkit.Resolver
///
static IResourceFileContent ResolveResourceFileContent(IMember member)
{
- if (member != null && member.ReturnType != null) {
- if (IsResourceManager(member.ReturnType) && member.DeclaringType != null && member.DeclaringType.CompilationUnit != null) {
+ if (member != null && member.ReturnType != null &&
+ member.DeclaringType != null && member.DeclaringType.CompilationUnit != null) {
+
+ IResourceFileContent content;
+ if (!NRefactoryAstCacheService.CacheEnabled || !cachedResourceFileContentMappings.TryGetValue(member, out content)) {
string declaringFileName = member.DeclaringType.CompilationUnit.FileName;
if (declaringFileName != null) {
-
- SupportedLanguage? language = NRefactoryResourceResolver.GetFileLanguage(declaringFileName);
- if (language == null) {
- return null;
- }
-
- CompilationUnit cu = NRefactoryAstCacheService.GetFullAst(language.Value, declaringFileName);
- if (cu != null) {
+ if (IsResourceManager(member.ReturnType, declaringFileName)) {
+
+ SupportedLanguage? language = NRefactoryResourceResolver.GetFileLanguage(declaringFileName);
+ if (language == null) {
+ return null;
+ }
- ResourceManagerInitializationFindVisitor visitor = new ResourceManagerInitializationFindVisitor(member);
- cu.AcceptVisitor(visitor, null);
- if (visitor.FoundFileName != null) {
+ CompilationUnit cu = NRefactoryAstCacheService.GetFullAst(language.Value, declaringFileName);
+ if (cu != null) {
- return ResourceFileContentRegistry.GetResourceFileContent(visitor.FoundFileName);
+ ResourceManagerInitializationFindVisitor visitor = new ResourceManagerInitializationFindVisitor(member);
+ cu.AcceptVisitor(visitor, null);
+ if (visitor.FoundFileName != null) {
+
+ content = ResourceFileContentRegistry.GetResourceFileContent(visitor.FoundFileName);
+
+ if (NRefactoryAstCacheService.CacheEnabled && content != null) {
+ cachedResourceFileContentMappings.Add(member, content);
+ }
+
+ return content;
+
+ }
}
}
-
}
+ return null;
+
}
+
+ return content;
+
}
return null;
}
@@ -114,9 +153,21 @@ namespace Hornung.ResourceToolkit.Resolver
/// Determines if the specified type is a ResourceManager type that can
/// be handled by this resolver.
///
- static bool IsResourceManager(IReturnType type)
+ static bool IsResourceManager(IReturnType type, string sourceFileName)
{
- IClass resourceManager = ParserService.CurrentProjectContent.GetClass("System.Resources.ResourceManager");
+ IProject p = ProjectFileDictionaryService.GetProjectForFile(sourceFileName);
+ IProjectContent pc;
+ if (p == null) {
+ pc = ParserService.CurrentProjectContent;
+ } else {
+ pc = ParserService.GetProjectContent(p);
+ }
+
+ if (pc == null) {
+ return false;
+ }
+
+ IClass resourceManager = pc.GetClass("System.Resources.ResourceManager");
if (resourceManager == null) {
return false;
}
@@ -144,6 +195,9 @@ namespace Hornung.ResourceToolkit.Resolver
readonly IMember resourceManagerMember;
readonly bool isLocalVariable;
+ bool triedToResolvePropertyAssociation;
+ IField resourceManagerFieldAccessedByProperty;
+
CompilationUnit compilationUnit;
string foundFileName;
@@ -188,6 +242,12 @@ namespace Hornung.ResourceToolkit.Resolver
public override object TrackedVisit(VariableDeclaration variableDeclaration, object data)
{
+ // Resolving anything here only makes sense
+ // if this declaration actually has an initializer.
+ if (variableDeclaration.Initializer.IsNull) {
+ return base.TrackedVisit(variableDeclaration, data);
+ }
+
LocalVariableDeclaration localVariableDeclaration = data as LocalVariableDeclaration;
if (this.isLocalVariable && localVariableDeclaration != null) {
if (variableDeclaration.Name == this.resourceManagerMember.Name) {
@@ -202,20 +262,42 @@ namespace Hornung.ResourceToolkit.Resolver
}
}
+
FieldDeclaration fieldDeclaration = data as FieldDeclaration;
if (!this.isLocalVariable && fieldDeclaration != null) {
- if (variableDeclaration.Name == this.resourceManagerMember.Name) {
- // Make sure we got the right declaration by comparing the positions.
- // Both must have the same start position.
- if (fieldDeclaration.StartLocation.X == this.resourceManagerMember.Region.BeginColumn && fieldDeclaration.StartLocation.Y == this.resourceManagerMember.Region.BeginLine) {
+ // Make sure we got the right declaration by comparing the positions.
+ // Both must have the same start position.
+ if (variableDeclaration.Name == this.resourceManagerMember.Name &&
+ fieldDeclaration.StartLocation.X == this.resourceManagerMember.Region.BeginColumn && fieldDeclaration.StartLocation.Y == this.resourceManagerMember.Region.BeginLine) {
+
+ #if DEBUG
+ LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver found field declaration: "+fieldDeclaration.ToString()+" at "+fieldDeclaration.StartLocation.ToString());
+ #endif
+ data = true;
+
+ } else {
+
+ // This field might be referred to by a property
+ // that we are looking for.
+ // This association is cached in the
+ // resourceManagerFieldAccessedByProperty field
+ // to improve performance.
+ this.TryResolveResourceManagerProperty();
+
+ if (this.resourceManagerFieldAccessedByProperty != null &&
+ fieldDeclaration.StartLocation.X == this.resourceManagerFieldAccessedByProperty.Region.BeginColumn &&
+ fieldDeclaration.StartLocation.Y == this.resourceManagerFieldAccessedByProperty.Region.BeginLine) {
+
#if DEBUG
- LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver found field declaration: "+fieldDeclaration.ToString()+" at "+fieldDeclaration.StartLocation.ToString());
+ LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver found field declaration (via associated property): "+fieldDeclaration.ToString()+" at "+fieldDeclaration.StartLocation.ToString());
#endif
data = true;
+
}
}
}
+
return base.TrackedVisit(variableDeclaration, data);
}
@@ -226,15 +308,29 @@ namespace Hornung.ResourceToolkit.Resolver
(!this.isLocalVariable || this.resourceManagerMember.Region.IsInside(this.CurrentNodeStartLocation.Y, this.CurrentNodeStartLocation.X)) // skip if local variable is out of scope
) {
- MemberResolveResult mrr = this.Resolve(assignmentExpression.Left, this.resourceManagerMember) as MemberResolveResult;
- if (mrr != null) {
+ IMember resolvedMember = null;
+ ResolveResult rr = this.Resolve(assignmentExpression.Left, this.resourceManagerMember.DeclaringType.CompilationUnit.FileName);
+ if (rr != null) {
+ // Support both local variables and member variables
+ MemberResolveResult mrr = rr as MemberResolveResult;
+ if (mrr != null) {
+ resolvedMember = mrr.ResolvedMember;
+ } else {
+ LocalResolveResult lrr = rr as LocalResolveResult;
+ if (lrr != null) {
+ resolvedMember = lrr.Field;
+ }
+ }
+ }
+
+ if (resolvedMember != null) {
#if DEBUG
- LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver: Resolved member: "+mrr.ResolvedMember.ToString());
+ LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver: Resolved member: "+resolvedMember.ToString());
#endif
// HACK: The GetType()s are necessary because the DOM IComparable implementations try to cast the parameter object to their own interface type which may fail.
- if (mrr.ResolvedMember.GetType().Equals(this.resourceManagerMember.GetType()) && mrr.ResolvedMember.CompareTo(this.resourceManagerMember) == 0) {
+ if (resolvedMember.GetType().Equals(this.resourceManagerMember.GetType()) && resolvedMember.CompareTo(this.resourceManagerMember) == 0) {
#if DEBUG
LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver found assignment to field: "+assignmentExpression.ToString());
@@ -245,35 +341,28 @@ namespace Hornung.ResourceToolkit.Resolver
// there is a possible relationship between the return types
// of the resolved member and the member we are looking for.
} else if (this.compilationUnit != null && !this.isLocalVariable &&
- (
- mrr.ResolvedMember.ReturnType.Equals(this.resourceManagerMember.ReturnType) ||
- (
- mrr.ResolvedMember.ReturnType.GetUnderlyingClass() != null && this.resourceManagerMember.ReturnType.GetUnderlyingClass() != null &&
- (
- mrr.ResolvedMember.ReturnType.GetUnderlyingClass().IsTypeInInheritanceTree(this.resourceManagerMember.ReturnType.GetUnderlyingClass()) ||
- this.resourceManagerMember.ReturnType.GetUnderlyingClass().IsTypeInInheritanceTree(mrr.ResolvedMember.ReturnType.GetUnderlyingClass())
- )
- )
- )) {
+ IsTypeRelationshipPossible(resolvedMember, this.resourceManagerMember)) {
- if (this.resourceManagerMember is IProperty && mrr.ResolvedMember is IField) {
+ if (this.resourceManagerMember is IProperty && resolvedMember is IField) {
// Find out if the resourceManagerMember is a property whose get block returns the value of the resolved member.
- PropertyFieldAssociationVisitor visitor = new PropertyFieldAssociationVisitor((IProperty)this.resourceManagerMember);
- this.compilationUnit.AcceptVisitor(visitor, null);
- if (visitor.AssociatedField != null && visitor.AssociatedField.CompareTo(mrr.ResolvedMember) == 0) {
+ // We might already have found this association in the
+ // resourceManagerFieldAccessedByProperty field.
+ this.TryResolveResourceManagerProperty();
+
+ if (this.resourceManagerFieldAccessedByProperty != null && this.resourceManagerFieldAccessedByProperty.CompareTo(resolvedMember) == 0) {
#if DEBUG
LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver found assignment to field: "+assignmentExpression.ToString());
#endif
data = true;
}
- } else if (this.resourceManagerMember is IField && mrr.ResolvedMember is IProperty) {
+ } else if (this.resourceManagerMember is IField && resolvedMember is IProperty) {
// Find out if the resolved member is a property whose set block assigns the value to the resourceManagerMember.
PropertyFieldAssociationVisitor visitor = new PropertyFieldAssociationVisitor((IField)this.resourceManagerMember);
this.compilationUnit.AcceptVisitor(visitor, null);
- if (visitor.AssociatedProperty != null && visitor.AssociatedProperty.CompareTo(mrr.ResolvedMember) == 0) {
+ if (visitor.AssociatedProperty != null && visitor.AssociatedProperty.CompareTo(resolvedMember) == 0) {
#if DEBUG
LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver found assignment to property: "+assignmentExpression.ToString());
#endif
@@ -290,6 +379,35 @@ namespace Hornung.ResourceToolkit.Resolver
return base.TrackedVisit(assignmentExpression, data);
}
+ ///
+ /// If the resourceManagerMember is a property, this method tries
+ /// to find the field that this property is associated to.
+ /// This association is cached in the
+ /// resourceManagerFieldAccessedByProperty field
+ /// to improve performance.
+ ///
+ void TryResolveResourceManagerProperty()
+ {
+ if (this.resourceManagerFieldAccessedByProperty == null && !this.triedToResolvePropertyAssociation) {
+
+ // Don't try this more than once in the same CompilationUnit
+ this.triedToResolvePropertyAssociation = true;
+
+ IProperty prop = this.resourceManagerMember as IProperty;
+ if (prop != null) {
+
+ // Resolve the property association.
+ PropertyFieldAssociationVisitor visitor = new PropertyFieldAssociationVisitor(prop);
+ this.compilationUnit.AcceptVisitor(visitor, null);
+
+ // Store the association in the instance field.
+ this.resourceManagerFieldAccessedByProperty = visitor.AssociatedField;
+
+ }
+
+ }
+ }
+
public override object TrackedVisit(ObjectCreateExpression objectCreateExpression, object data)
{
if (data as bool? ?? false) {
@@ -300,7 +418,7 @@ namespace Hornung.ResourceToolkit.Resolver
// Resolve the constructor.
// A type derived from the declaration type is also allowed.
- MemberResolveResult mrr = this.Resolve(objectCreateExpression, this.resourceManagerMember) as MemberResolveResult;
+ MemberResolveResult mrr = this.Resolve(objectCreateExpression, this.resourceManagerMember.DeclaringType.CompilationUnit.FileName) as MemberResolveResult;
#if DEBUG
if (mrr != null) {
@@ -345,7 +463,7 @@ namespace Hornung.ResourceToolkit.Resolver
// Support typeof(...)
TypeOfExpression t = param as TypeOfExpression;
if (t != null && this.PositionAvailable) {
- TypeResolveResult trr = this.Resolve(new TypeReferenceExpression(t.TypeReference), this.resourceManagerMember) as TypeResolveResult;
+ TypeResolveResult trr = this.Resolve(new TypeReferenceExpression(t.TypeReference), this.resourceManagerMember.DeclaringType.CompilationUnit.FileName) as TypeResolveResult;
if (trr != null) {
#if DEBUG
@@ -377,6 +495,27 @@ namespace Hornung.ResourceToolkit.Resolver
#endregion
+ ///
+ /// Determines whether there is a possible relationship between the
+ /// return types of member1 and member2.
+ ///
+ public static bool IsTypeRelationshipPossible(IMember member1, IMember member2)
+ {
+ if (member1.ReturnType.Equals(member2.ReturnType)) {
+ return true;
+ }
+ IClass class1;
+ IClass class2;
+ if ((class1 = member1.ReturnType.GetUnderlyingClass()) == null) {
+ return false;
+ }
+ if ((class2 = member2.ReturnType.GetUnderlyingClass()) == null) {
+ return false;
+ }
+ return class1.IsTypeInInheritanceTree(class2) ||
+ class2.IsTypeInInheritanceTree(class1);
+ }
+
// ********************************************************************************************************************************
///
diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ICSharpCodeCoreNRefactoryResourceResolver.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ICSharpCodeCoreNRefactoryResourceResolver.cs
index d6bb2abc6b..daf03ef540 100644
--- a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ICSharpCodeCoreNRefactoryResourceResolver.cs
+++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ICSharpCodeCoreNRefactoryResourceResolver.cs
@@ -28,7 +28,7 @@ namespace Hornung.ResourceToolkit.Resolver
/// Tries to find a resource reference in the specified expression.
///
/// The ExpressionResult for the expression.
- /// The AST representation of the expression.
+ /// The AST representation of the full expression.
/// SharpDevelop's ResolveResult for the expression.
/// The line where the expression is located.
/// The column where the expression is located.
diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ICSharpCodeCoreResourceResolver.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ICSharpCodeCoreResourceResolver.cs
index f2ce0fb240..07c471293f 100644
--- a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ICSharpCodeCoreResourceResolver.cs
+++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ICSharpCodeCoreResourceResolver.cs
@@ -207,13 +207,20 @@ namespace Hornung.ResourceToolkit.Resolver
return null;
}
- string localFile;
- foreach (string relativePath in AddInTree.BuildItems("/AddIns/ResourceToolkit/ICSharpCodeCoreResourceResolver/LocalResourcesLocations", null, false)) {
- if ((localFile = FindICSharpCodeCoreResourceFile(Path.GetFullPath(Path.Combine(project.Directory, relativePath)))) != null) {
- return localFile;
+ string localFile = null;
+
+ if (!NRefactoryAstCacheService.CacheEnabled || !cachedLocalResourceFiles.TryGetValue(project, out localFile)) {
+ foreach (string relativePath in AddInTree.BuildItems("/AddIns/ResourceToolkit/ICSharpCodeCoreResourceResolver/LocalResourcesLocations", null, false)) {
+ if ((localFile = FindICSharpCodeCoreResourceFile(Path.GetFullPath(Path.Combine(project.Directory, relativePath)))) != null) {
+ if (NRefactoryAstCacheService.CacheEnabled) {
+ cachedLocalResourceFiles.Add(project, localFile);
+ }
+ break;
+ }
}
}
- return null;
+
+ return localFile;
}
///
@@ -223,37 +230,45 @@ namespace Hornung.ResourceToolkit.Resolver
public static string GetICSharpCodeCoreHostResourceFileName(string sourceFileName)
{
IProject project = ProjectFileDictionaryService.GetProjectForFile(sourceFileName);
+ string hostFile = null;
- // Get SD directory using the reference to ICSharpCode.Core
- string coreAssemblyFullPath = GetICSharpCodeCoreFullPath(project);
-
- if (coreAssemblyFullPath == null) {
- // Look for the ICSharpCode.Core project using all available projects.
- if (ProjectService.OpenSolution != null) {
- foreach (IProject p in ProjectService.OpenSolution.Projects) {
- if ((coreAssemblyFullPath = GetICSharpCodeCoreFullPath(p)) != null) {
- break;
+ if (project == null ||
+ !NRefactoryAstCacheService.CacheEnabled || !cachedHostResourceFiles.TryGetValue(project, out hostFile)) {
+
+ // Get SD directory using the reference to ICSharpCode.Core
+ string coreAssemblyFullPath = GetICSharpCodeCoreFullPath(project);
+
+ if (coreAssemblyFullPath == null) {
+ // Look for the ICSharpCode.Core project using all available projects.
+ if (ProjectService.OpenSolution != null) {
+ foreach (IProject p in ProjectService.OpenSolution.Projects) {
+ if ((coreAssemblyFullPath = GetICSharpCodeCoreFullPath(p)) != null) {
+ break;
+ }
}
}
}
- }
-
- if (coreAssemblyFullPath != null) {
+
+ if (coreAssemblyFullPath == null) {
+ return null;
+ }
#if DEBUG
LoggingService.Debug("ResourceToolkit: ICSharpCodeCoreResourceResolver coreAssemblyFullPath = "+coreAssemblyFullPath);
#endif
- string hostFile;
foreach (string relativePath in AddInTree.BuildItems("/AddIns/ResourceToolkit/ICSharpCodeCoreResourceResolver/HostResourcesLocations", null, false)) {
if ((hostFile = FindICSharpCodeCoreResourceFile(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(coreAssemblyFullPath), relativePath)))) != null) {
- return hostFile;
+ if (NRefactoryAstCacheService.CacheEnabled && project != null) {
+ cachedHostResourceFiles.Add(project, hostFile);
+ }
+ break;
}
}
}
- return null;
+ return hostFile;
}
static string GetICSharpCodeCoreFullPath(IProject sourceProject)
@@ -296,5 +311,27 @@ namespace Hornung.ResourceToolkit.Resolver
return coreAssemblyFullPath;
}
+ #region ICSharpCode.Core resource file mapping cache
+
+ static Dictionary cachedLocalResourceFiles;
+ static Dictionary cachedHostResourceFiles;
+
+ static ICSharpCodeCoreResourceResolver()
+ {
+ cachedLocalResourceFiles = new Dictionary();
+ cachedHostResourceFiles = new Dictionary();
+ NRefactoryAstCacheService.CacheEnabledChanged += NRefactoryCacheEnabledChanged;
+ }
+
+ static void NRefactoryCacheEnabledChanged(object sender, EventArgs e)
+ {
+ if (!NRefactoryAstCacheService.CacheEnabled) {
+ // Clear cache when disabled.
+ cachedLocalResourceFiles.Clear();
+ cachedHostResourceFiles.Clear();
+ }
+ }
+
+ #endregion
}
}
diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/INRefactoryResourceResolver.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/INRefactoryResourceResolver.cs
index 986999e35a..7c34db09c5 100644
--- a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/INRefactoryResourceResolver.cs
+++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/INRefactoryResourceResolver.cs
@@ -24,7 +24,7 @@ namespace Hornung.ResourceToolkit.Resolver
/// Tries to find a resource reference in the specified expression.
///
/// The ExpressionResult for the expression.
- /// The AST representation of the expression.
+ /// The AST representation of the full expression.
/// SharpDevelop's ResolveResult for the expression.
/// The line where the expression is located.
/// The column where the expression is located.
diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/MemberEqualityComparer.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/MemberEqualityComparer.cs
new file mode 100644
index 0000000000..6db57e6fad
--- /dev/null
+++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/MemberEqualityComparer.cs
@@ -0,0 +1,51 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Collections.Generic;
+
+using ICSharpCode.SharpDevelop.Dom;
+
+namespace Hornung.ResourceToolkit.Resolver
+{
+ ///
+ /// Determines equality of DOM members by region and fully qualified name.
+ ///
+ public class MemberEqualityComparer : IEqualityComparer
+ {
+ public bool Equals(IMember x, IMember y)
+ {
+ if (x == null || y == null) {
+ return false;
+ }
+ if (x.Region.CompareTo(y.Region) != 0) {
+ return false;
+ }
+ IComparer nameComparer;
+ if (x.DeclaringType != null &&
+ x.DeclaringType.ProjectContent != null &&
+ x.DeclaringType.ProjectContent.Language != null) {
+ nameComparer = x.DeclaringType.ProjectContent.Language.NameComparer;
+ } else {
+ nameComparer = StringComparer.InvariantCulture;
+ }
+ return nameComparer.Compare(x.FullyQualifiedName, y.FullyQualifiedName) == 0;
+ }
+
+ public int GetHashCode(IMember obj)
+ {
+ if (obj == null) {
+ return 0;
+ }
+ return obj.Region.BeginLine ^
+ obj.Region.BeginColumn ^
+ obj.Region.EndLine ^
+ obj.Region.EndColumn ^
+ obj.FullyQualifiedName.GetHashCode();
+ }
+ }
+}
diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/MemberFindAstVisitor.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/MemberFindAstVisitor.cs
new file mode 100644
index 0000000000..c4a047ac6f
--- /dev/null
+++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/MemberFindAstVisitor.cs
@@ -0,0 +1,207 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+
+using ICSharpCode.NRefactory.Ast;
+using ICSharpCode.NRefactory.Visitors;
+using ICSharpCode.SharpDevelop.Dom;
+
+namespace Hornung.ResourceToolkit.Resolver
+{
+ ///
+ /// Finds a certain member inside the AST.
+ ///
+ public class MemberFindAstVisitor : AbstractAstVisitor
+ {
+ readonly IMember memberToFind;
+ INode memberNode;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The member to find.
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "System.ArgumentException.#ctor(System.String,System.String)")]
+ public MemberFindAstVisitor(IMember member)
+ {
+ if (member == null) {
+ throw new ArgumentNullException("member");
+ }
+ if (member.Region.IsEmpty) {
+ throw new ArgumentException("Cannot find this member because its region is empty."+Environment.NewLine+"member: '"+member.ToString()+"'", "member");
+ }
+ this.memberToFind = member;
+ }
+
+ ///
+ /// Gets the INode that belongs to the member specified in the constructor call,
+ /// or a null reference, if the member cannot be found.
+ ///
+ public INode MemberNode {
+ get {
+ return this.memberNode;
+ }
+ }
+
+ // ********************************************************************************************************************************
+
+ ///
+ /// Tests whether the specified node is the node belonging to the member we are
+ /// looking for.
+ ///
+ /// true, if this is the right node or the node has already been found before, otherwise false.
+ bool CheckNode(INode node)
+ {
+ if (this.memberNode != null) {
+ return true;
+ }
+ if (!node.StartLocation.IsEmpty &&
+ node.StartLocation.Y == this.memberToFind.Region.BeginLine &&
+ node.StartLocation.X == this.memberToFind.Region.BeginColumn) {
+ this.memberNode = node;
+ return true;
+ }
+ return false;
+ }
+
+ public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data)
+ {
+ if (this.CheckNode(constructorDeclaration)) {
+ return null;
+ }
+ return base.VisitConstructorDeclaration(constructorDeclaration, data);
+ }
+
+ public override object VisitDeclareDeclaration(DeclareDeclaration declareDeclaration, object data)
+ {
+ if (this.CheckNode(declareDeclaration)) {
+ return null;
+ }
+ return base.VisitDeclareDeclaration(declareDeclaration, data);
+ }
+
+ public override object VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration, object data)
+ {
+ if (this.CheckNode(delegateDeclaration)) {
+ return null;
+ }
+ return base.VisitDelegateDeclaration(delegateDeclaration, data);
+ }
+
+ public override object VisitDestructorDeclaration(DestructorDeclaration destructorDeclaration, object data)
+ {
+ if (this.CheckNode(destructorDeclaration)) {
+ return null;
+ }
+ return base.VisitDestructorDeclaration(destructorDeclaration, data);
+ }
+
+ public override object VisitEventDeclaration(EventDeclaration eventDeclaration, object data)
+ {
+ if (this.CheckNode(eventDeclaration)) {
+ return null;
+ }
+ return base.VisitEventDeclaration(eventDeclaration, data);
+ }
+
+ public override object VisitFieldDeclaration(FieldDeclaration fieldDeclaration, object data)
+ {
+ if (this.CheckNode(fieldDeclaration)) {
+ return null;
+ }
+ return base.VisitFieldDeclaration(fieldDeclaration, data);
+ }
+
+ public override object VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration, object data)
+ {
+ if (this.CheckNode(indexerDeclaration)) {
+ return null;
+ }
+ return base.VisitIndexerDeclaration(indexerDeclaration, data);
+ }
+
+ public override object VisitLocalVariableDeclaration(LocalVariableDeclaration localVariableDeclaration, object data)
+ {
+ if (this.CheckNode(localVariableDeclaration)) {
+ return null;
+ }
+ return base.VisitLocalVariableDeclaration(localVariableDeclaration, data);
+ }
+
+ public override object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data)
+ {
+ if (this.CheckNode(methodDeclaration)) {
+ return null;
+ }
+ return base.VisitMethodDeclaration(methodDeclaration, data);
+ }
+
+ public override object VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration, object data)
+ {
+ if (this.CheckNode(namespaceDeclaration)) {
+ return null;
+ }
+ return base.VisitNamespaceDeclaration(namespaceDeclaration, data);
+ }
+
+ public override object VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration, object data)
+ {
+ if (this.CheckNode(operatorDeclaration)) {
+ return null;
+ }
+ return base.VisitOperatorDeclaration(operatorDeclaration, data);
+ }
+
+ public override object VisitParameterDeclarationExpression(ParameterDeclarationExpression parameterDeclarationExpression, object data)
+ {
+ if (this.CheckNode(parameterDeclarationExpression)) {
+ return null;
+ }
+ return base.VisitParameterDeclarationExpression(parameterDeclarationExpression, data);
+ }
+
+ public override object VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration, object data)
+ {
+ if (this.CheckNode(propertyDeclaration)) {
+ return null;
+ }
+ return base.VisitPropertyDeclaration(propertyDeclaration, data);
+ }
+
+ public override object VisitPropertyGetRegion(PropertyGetRegion propertyGetRegion, object data)
+ {
+ if (this.CheckNode(propertyGetRegion)) {
+ return null;
+ }
+ return base.VisitPropertyGetRegion(propertyGetRegion, data);
+ }
+
+ public override object VisitPropertySetRegion(PropertySetRegion propertySetRegion, object data)
+ {
+ if (this.CheckNode(propertySetRegion)) {
+ return null;
+ }
+ return base.VisitPropertySetRegion(propertySetRegion, data);
+ }
+
+ public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
+ {
+ if (this.CheckNode(typeDeclaration)) {
+ return null;
+ }
+ return base.VisitTypeDeclaration(typeDeclaration, data);
+ }
+
+ public override object VisitVariableDeclaration(VariableDeclaration variableDeclaration, object data)
+ {
+ if (this.CheckNode(variableDeclaration)) {
+ return null;
+ }
+ return base.VisitVariableDeclaration(variableDeclaration, data);
+ }
+ }
+}
diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NRefactoryAstCacheService.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NRefactoryAstCacheService.cs
index 98349b7b43..e667671b32 100644
--- a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NRefactoryAstCacheService.cs
+++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NRefactoryAstCacheService.cs
@@ -14,16 +14,23 @@ using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Parser;
using ICSharpCode.SharpDevelop;
+using ICSharpCode.SharpDevelop.Dom;
+using ICSharpCode.SharpDevelop.Dom.NRefactoryResolver;
+using ICSharpCode.SharpDevelop.Project;
namespace Hornung.ResourceToolkit.Resolver
{
///
/// Parses files using NRefactory and caches the AST on demand.
+ /// Provides an event to monitor the cache status and
+ /// the method to resolve expressions
+ /// faster by making use of the cache.
///
public static class NRefactoryAstCacheService
{
static bool cacheEnabled;
static Dictionary cachedAstInfo = new Dictionary();
+ static Dictionary cachedMemberMappings = new Dictionary(new MemberEqualityComparer());
///
/// Gets a flag that indicates whether the AST cache is currently enabled.
@@ -34,6 +41,21 @@ namespace Hornung.ResourceToolkit.Resolver
}
}
+ ///
+ /// Occurs when the cache is enabled or disabled.
+ ///
+ public static event EventHandler CacheEnabledChanged;
+
+ ///
+ /// Raises the CacheEnabledChanged event.
+ ///
+ private static void OnCacheEnabledChanged(EventArgs e)
+ {
+ if (CacheEnabledChanged != null) {
+ CacheEnabledChanged(null, e);
+ }
+ }
+
///
/// Enables the AST cache.
///
@@ -46,6 +68,7 @@ namespace Hornung.ResourceToolkit.Resolver
}
cacheEnabled = true;
LoggingService.Info("ResourceToolkit: NRefactoryAstCacheService cache enabled");
+ OnCacheEnabledChanged(EventArgs.Empty);
}
///
@@ -55,7 +78,9 @@ namespace Hornung.ResourceToolkit.Resolver
{
cacheEnabled = false;
cachedAstInfo.Clear();
+ cachedMemberMappings.Clear();
LoggingService.Info("ResourceToolkit: NRefactoryAstCacheService cache disabled and cleared");
+ OnCacheEnabledChanged(EventArgs.Empty);
}
///
@@ -91,5 +116,116 @@ namespace Hornung.ResourceToolkit.Resolver
}
return null;
}
+
+ // ********************************************************************************************************************************
+
+ ///
+ /// Resolves an expression using low-level NRefactoryResolver methods and making
+ /// use of the cache if possible.
+ ///
+ /// The file name of the source code file that contains the expression to be resolved.
+ /// The 1-based line number of the expression.
+ /// The 1-based column number of the expression.
+ /// The CompilationUnit that contains the NRefactory AST for this file. May be null (then the CompilationUnit is retrieved from the cache or the file is parsed).
+ /// The expression to be resolved.
+ /// The ExpressionContext of the expression.
+ /// A ResolveResult or null if the expression cannot be resolved.
+ public static ResolveResult ResolveLowLevel(string fileName, int caretLine, int caretColumn, CompilationUnit compilationUnit, string expression, ExpressionContext context)
+ {
+ using (ICSharpCode.NRefactory.IParser p = ICSharpCode.NRefactory.ParserFactory.CreateParser(NRefactoryResourceResolver.GetFileLanguage(fileName).Value, new System.IO.StringReader(expression))) {
+ Expression expr = p.ParseExpression();
+ if (expr == null) {
+ return null;
+ }
+ return ResolveLowLevel(fileName, caretLine, caretColumn, compilationUnit, expression, expr, context);
+ }
+ }
+
+ ///
+ /// Resolves an expression using low-level NRefactoryResolver methods and making
+ /// use of the cache if possible.
+ ///
+ /// The file name of the source code file that contains the expression to be resolved.
+ /// The 1-based line number of the expression.
+ /// The 1-based column number of the expression.
+ /// The CompilationUnit that contains the NRefactory AST for this file. May be null (then the CompilationUnit is retrieved from the cache or the file is parsed).
+ /// The expression to be resolved as a string. If this parameter is null, the expression string is generated by using the code generator.
+ /// The parsed expression to be resolved.
+ /// The ExpressionContext of the expression.
+ /// A ResolveResult or null if the expression cannot be resolved.
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters", MessageId = "4#")]
+ public static ResolveResult ResolveLowLevel(string fileName, int caretLine, int caretColumn, CompilationUnit compilationUnit, string expressionString, Expression expression, ExpressionContext context)
+ {
+ if (fileName == null) {
+ throw new ArgumentNullException("fileName");
+ }
+ if (expression == null) {
+ throw new ArgumentNullException("expression");
+ }
+
+ IProject p = ProjectFileDictionaryService.GetProjectForFile(fileName);
+ if (p == null) {
+ LoggingService.Info("ResourceToolkit: NRefactoryAstCacheService: ResolveLowLevel failed. Project is null for file '"+fileName+"'");
+ return null;
+ }
+
+ IProjectContent pc = ParserService.GetProjectContent(p);
+ if (pc == null) {
+ LoggingService.Info("ResourceToolkit: NRefactoryAstCacheService: ResolveLowLevel failed. ProjectContent is null for project '"+p.ToString()+"'");
+ return null;
+ }
+
+ NRefactoryResolver resolver = new NRefactoryResolver(pc);
+
+ if (compilationUnit == null) {
+ compilationUnit = GetFullAst(resolver.Language, fileName);
+ }
+ if (compilationUnit == null) {
+ LoggingService.Info("ResourceToolkit: NRefactoryAstCacheService: ResolveLowLevel failed due to the compilation unit being unavailable.");
+ return null;
+ }
+
+ if (!resolver.Initialize(fileName, caretLine, caretColumn)) {
+ LoggingService.Info("ResourceToolkit: NRefactoryAstCacheService: ResolveLowLevel failed. NRefactoryResolver.Initialize returned false.");
+ return null;
+ }
+
+ if (resolver.CallingClass != null) {
+ ResolveResult rr;
+ if (expressionString == null) {
+ // HACK: Re-generate the code for the expression from the expression object by using the code generator.
+ // This is necessary when invoking from inside an AST visitor where the
+ // code belonging to this expression is unavailable.
+ expressionString = resolver.LanguageProperties.CodeGenerator.GenerateCode(expression, String.Empty);
+ }
+ if ((rr = NRefactoryResolver.GetResultFromDeclarationLine(resolver.CallingClass, resolver.CallingMember as IMethodOrProperty, caretLine, caretColumn, expressionString)) != null) {
+ return rr;
+ }
+ }
+
+ if (resolver.CallingMember != null) {
+
+ // Cache member->node mappings to improves performance
+ // (if cache is enabled)
+ INode memberNode;
+ if (!CacheEnabled || !cachedMemberMappings.TryGetValue(resolver.CallingMember, out memberNode)) {
+ MemberFindAstVisitor visitor = new MemberFindAstVisitor(resolver.CallingMember);
+ compilationUnit.AcceptVisitor(visitor, null);
+ memberNode = visitor.MemberNode;
+ if (CacheEnabled && memberNode != null) {
+ cachedMemberMappings.Add(resolver.CallingMember, memberNode);
+ }
+ }
+
+ if (memberNode == null) {
+ LoggingService.Info("ResourceToolkit: NRefactoryAstCacheService: Could not find member in AST: "+resolver.CallingMember.ToString());
+ } else {
+ resolver.RunLookupTableVisitor(memberNode);
+ }
+
+ }
+
+ return resolver.ResolveInternal(expression, context);
+ }
}
}
diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NRefactoryResourceResolver.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NRefactoryResourceResolver.cs
index 51a77c8478..e325b5a7c2 100644
--- a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NRefactoryResourceResolver.cs
+++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NRefactoryResourceResolver.cs
@@ -128,23 +128,30 @@ namespace Hornung.ResourceToolkit.Resolver
ResourceResolveResult rrr = null;
- // The full expression is parsed here because
- // we will need to modify the result in the next step.
- Expression expr = null;
SupportedLanguage? language = GetFileLanguage(fileName);
- if (language != null) {
- using(ICSharpCode.NRefactory.IParser parser = ParserFactory.CreateParser(language.Value, new StringReader(result.Expression))) {
- if (parser != null) {
- expr = parser.ParseExpression();
- }
- }
+ if (language == null) {
+ return null;
}
// The resolve routine needs the member which contains the actual member being referenced.
// If a complete expression is given, the expression needs to be reduced to
// the member reference.
+ Expression fullExpr = null;
while (result.Expression != null && result.Expression.Length > 0) {
- if ((rrr = TryResolve(result, expr, caretLine, caretColumn, fileName, document.TextContent)) != null) {
+ Expression expr = null;
+ using(ICSharpCode.NRefactory.IParser parser = ParserFactory.CreateParser(language.Value, new StringReader(result.Expression))) {
+ if (parser != null) {
+ expr = parser.ParseExpression();
+ }
+ }
+
+ if (expr == null) {
+ break;
+ }
+ if (fullExpr == null) {
+ fullExpr = expr;
+ }
+ if ((rrr = TryResolve(result, expr, fullExpr, caretLine, caretColumn, fileName, document.TextContent)) != null) {
break;
}
result.Expression = ef.RemoveLastPart(result.Expression);
@@ -163,14 +170,14 @@ namespace Hornung.ResourceToolkit.Resolver
/// Tries to resolve the resource reference using all available
/// NRefactory resource resolvers.
///
- static ResourceResolveResult TryResolve(ExpressionResult result, Expression expr, int caretLine, int caretColumn, string fileName, string fileContent)
+ static ResourceResolveResult TryResolve(ExpressionResult result, Expression expr, Expression fullExpr, int caretLine, int caretColumn, string fileName, string fileContent)
{
- ResolveResult rr = ParserService.Resolve(result, caretLine, caretColumn, fileName, fileContent);
+ ResolveResult rr = NRefactoryAstCacheService.ResolveLowLevel(fileName, caretLine+1, caretColumn+1, null, result.Expression, expr, result.Context);
if (rr != null) {
ResourceResolveResult rrr;
foreach (INRefactoryResourceResolver resolver in Resolvers) {
- if ((rrr = resolver.Resolve(result, expr, rr, caretLine, caretColumn, fileName, fileContent)) != null) {
+ if ((rrr = resolver.Resolve(result, fullExpr, rr, caretLine, caretColumn, fileName, fileContent)) != null) {
return rrr;
}
}
diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/PositionTrackingAstVisitor.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/PositionTrackingAstVisitor.cs
index 1c0676a0d7..9ff675c6a7 100644
--- a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/PositionTrackingAstVisitor.cs
+++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/PositionTrackingAstVisitor.cs
@@ -82,40 +82,33 @@ namespace Hornung.ResourceToolkit.Resolver
// ********************************************************************************************************************************
+ private CompilationUnit compilationUnit;
+
+ public override object TrackedVisit(CompilationUnit compilationUnit, object data)
+ {
+ this.compilationUnit = compilationUnit;
+ return base.TrackedVisit(compilationUnit, data);
+ }
+
+ // ********************************************************************************************************************************
+
///
/// Resolves an expression in the current node's context.
///
/// The expression to be resolved.
- /// Any member declared in the source file in question. Used to get the language, file name and file content.
- public ResolveResult Resolve(Expression expression, IMember memberInThisFile)
+ /// The file name of the source file that contains the expression to be resolved.
+ public ResolveResult Resolve(Expression expression, string fileName)
{
if (!this.PositionAvailable) {
- LoggingService.Debug("ResourceToolkit: PositionTrackingAstVisitor: Resolve failed due to position information being unavailable. Expression: "+expression.ToString());
+ LoggingService.Info("ResourceToolkit: PositionTrackingAstVisitor: Resolve failed due to position information being unavailable. Expression: "+expression.ToString());
return null;
}
- // In order to resolve expression, we need the original code.
- // HACK: To get the code belonging to this expression, we pass it through the code generator.
- // (Is there a better way?)
-
- string code = null;
- LanguageProperties lp = NRefactoryResourceResolver.GetLanguagePropertiesForMember(memberInThisFile);
- if (lp != null && lp.CodeGenerator != null) {
- code = lp.CodeGenerator.GenerateCode(expression, String.Empty);
- }
-
- if (!String.IsNullOrEmpty(code)) {
-
- // Now resolve the expression in the current context.
- ResolveResult rr = ParserService.Resolve(new ExpressionResult(code, ExpressionContext.Default), this.CurrentNodeStartLocation.Y-1, this.CurrentNodeStartLocation.X, memberInThisFile.DeclaringType.CompilationUnit.FileName, ParserService.GetParseableFileContent(memberInThisFile.DeclaringType.CompilationUnit.FileName));
-
- return rr;
-
- } else {
- LoggingService.Debug("ResourceToolkit: PositionTrackingAstVisitor could not re-generate code for the expression: "+expression.ToString());
- }
+ #if DEBUG
+ LoggingService.Debug("ResourceToolkit: PositionTrackingAstVisitor: Using this parent node for resolve: "+this.parentNodes.Peek().ToString());
+ #endif
- return null;
+ return NRefactoryAstCacheService.ResolveLowLevel(fileName, this.CurrentNodeStartLocation.Y, this.CurrentNodeStartLocation.X+1, this.compilationUnit, null, expression, ExpressionContext.Default);
}
// ********************************************************************************************************************************
diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/PropertyFieldAssociationVisitor.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/PropertyFieldAssociationVisitor.cs
index 7f0ff3c8dc..10d1a3a6d0 100644
--- a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/PropertyFieldAssociationVisitor.cs
+++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/PropertyFieldAssociationVisitor.cs
@@ -100,8 +100,24 @@ namespace Hornung.ResourceToolkit.Resolver
if (this.associatedMember == null && // skip if already found to improve performance
this.currentContext == VisitorContext.PropertyGetRegion && data != null) {
+ // Fix some type casting and parenthesized expressions
+ Expression expr = returnStatement.Expression;
+ while (true) {
+ CastExpression ce = expr as CastExpression;
+ if (ce != null) {
+ expr = ce.Expression;
+ continue;
+ }
+ ParenthesizedExpression pe = expr as ParenthesizedExpression;
+ if (pe != null) {
+ expr = pe.Expression;
+ continue;
+ }
+ break;
+ }
+
// Resolve the expression.
- MemberResolveResult mrr = this.Resolve(returnStatement.Expression, this.memberToFind) as MemberResolveResult;
+ MemberResolveResult mrr = this.Resolve(expr, this.memberToFind.DeclaringType.CompilationUnit.FileName) as MemberResolveResult;
if (mrr != null && mrr.ResolvedMember is IField) {
PropertyDeclaration pd;
@@ -124,7 +140,7 @@ namespace Hornung.ResourceToolkit.Resolver
if (this.memberToFind.CompareTo(mrr.ResolvedMember) == 0) {
// Resolve the property.
- MemberResolveResult prr = ParserService.Resolve(new ExpressionResult(pd.Name, ExpressionContext.Default), pd.StartLocation.Y-1, pd.StartLocation.X, this.memberToFind.DeclaringType.CompilationUnit.FileName, ParserService.GetParseableFileContent(this.memberToFind.DeclaringType.CompilationUnit.FileName)) as MemberResolveResult;
+ MemberResolveResult prr = NRefactoryAstCacheService.ResolveLowLevel(this.memberToFind.DeclaringType.CompilationUnit.FileName, pd.StartLocation.Y, pd.StartLocation.X+1, null, pd.Name, ExpressionContext.Default) as MemberResolveResult;
if (prr != null) {
#if DEBUG
@@ -160,7 +176,7 @@ namespace Hornung.ResourceToolkit.Resolver
assignmentExpression.Op == AssignmentOperatorType.Assign && data != null) {
// Resolve the expression.
- MemberResolveResult mrr = this.Resolve(assignmentExpression.Left, this.memberToFind) as MemberResolveResult;
+ MemberResolveResult mrr = this.Resolve(assignmentExpression.Left, this.memberToFind.DeclaringType.CompilationUnit.FileName) as MemberResolveResult;
if (mrr != null && mrr.ResolvedMember is IField && !((IField)mrr.ResolvedMember).IsLocalVariable) {
PropertyDeclaration pd;
@@ -183,7 +199,7 @@ namespace Hornung.ResourceToolkit.Resolver
if (this.memberToFind.CompareTo(mrr.ResolvedMember) == 0) {
// Resolve the property.
- MemberResolveResult prr = ParserService.Resolve(new ExpressionResult(pd.Name, ExpressionContext.Default), pd.StartLocation.Y-1, pd.StartLocation.X, this.memberToFind.DeclaringType.CompilationUnit.FileName, ParserService.GetParseableFileContent(this.memberToFind.DeclaringType.CompilationUnit.FileName)) as MemberResolveResult;
+ MemberResolveResult prr = NRefactoryAstCacheService.ResolveLowLevel(this.memberToFind.DeclaringType.CompilationUnit.FileName, pd.StartLocation.Y, pd.StartLocation.X+1, null, pd.Name, ExpressionContext.Default) as MemberResolveResult;
if (prr != null) {
#if DEBUG