Browse Source

ResourceToolkit:

Improved the performance of the resource resolvers (especially when working with large designer-generated localizable forms), mainly by increased caching of reusable information during a FindReferences run.

Fixed finding a property<->field association when the return statement in the property getter includes a cast or a parenthesized expression.

Fixed finding the resource manager when it is a field that is accessed through a property and this field is initialized directly in the declaraion.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@1917 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Christian Hornung 20 years ago
parent
commit
a4574b29cb
  1. 2
      src/AddIns/Misc/ResourceToolkit/Project/ResourceToolkit.csproj
  2. 237
      src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/BclNRefactoryResourceResolver.cs
  3. 2
      src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ICSharpCodeCoreNRefactoryResourceResolver.cs
  4. 73
      src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ICSharpCodeCoreResourceResolver.cs
  5. 2
      src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/INRefactoryResourceResolver.cs
  6. 51
      src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/MemberEqualityComparer.cs
  7. 207
      src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/MemberFindAstVisitor.cs
  8. 136
      src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NRefactoryAstCacheService.cs
  9. 33
      src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NRefactoryResourceResolver.cs
  10. 41
      src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/PositionTrackingAstVisitor.cs
  11. 24
      src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/PropertyFieldAssociationVisitor.cs

2
src/AddIns/Misc/ResourceToolkit/Project/ResourceToolkit.csproj

@ -91,6 +91,8 @@ @@ -91,6 +91,8 @@
<Compile Include="Src\Gui\IFilterHost.cs" />
<Compile Include="Src\ResourceItem.cs" />
<EmbeddedResource Include="Resources\EditStringResourceDialog.xfrm" />
<Compile Include="Src\Resolver\MemberFindAstVisitor.cs" />
<Compile Include="Src\Resolver\MemberEqualityComparer.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\Main\ICSharpCode.SharpDevelop.Dom\Project\ICSharpCode.SharpDevelop.Dom.csproj">

237
src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/BclNRefactoryResourceResolver.cs

@ -15,6 +15,7 @@ using ICSharpCode.NRefactory.Ast; @@ -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 @@ -32,7 +33,7 @@ namespace Hornung.ResourceToolkit.Resolver
/// Tries to find a resource reference in the specified expression.
/// </summary>
/// <param name="expressionResult">The ExpressionResult for the expression.</param>
/// <param name="expr">The AST representation of the expression.</param>
/// <param name="expr">The AST representation of the full expression.</param>
/// <param name="resolveResult">SharpDevelop's ResolveResult for the expression.</param>
/// <param name="caretLine">The line where the expression is located.</param>
/// <param name="caretColumn">The column where the expression is located.</param>
@ -46,13 +47,15 @@ namespace Hornung.ResourceToolkit.Resolver @@ -46,13 +47,15 @@ namespace Hornung.ResourceToolkit.Resolver
MemberResolveResult mrr = resolveResult as MemberResolveResult;
if (mrr != null) {
rfc = ResolveResourceFileContent(mrr.ResolvedMember);
}
} else {
LocalResolveResult lrr = resolveResult as LocalResolveResult;
if (lrr != null) {
if (!lrr.IsParameter) {
rfc = ResolveResourceFileContent(lrr.Field);
LocalResolveResult lrr = resolveResult as LocalResolveResult;
if (lrr != null) {
if (!lrr.IsParameter) {
rfc = ResolveResourceFileContent(lrr.Field);
}
}
}
@ -68,6 +71,26 @@ namespace Hornung.ResourceToolkit.Resolver @@ -68,6 +71,26 @@ namespace Hornung.ResourceToolkit.Resolver
// ********************************************************************************************************************************
#region ResourceFileContent mapping cache
static Dictionary<IMember, IResourceFileContent> cachedResourceFileContentMappings;
static BclNRefactoryResourceResolver()
{
cachedResourceFileContentMappings = new Dictionary<IMember, IResourceFileContent>(new MemberEqualityComparer());
NRefactoryAstCacheService.CacheEnabledChanged += NRefactoryCacheEnabledChanged;
}
static void NRefactoryCacheEnabledChanged(object sender, EventArgs e)
{
if (!NRefactoryAstCacheService.CacheEnabled) {
// Clear cache when disabled.
cachedResourceFileContentMappings.Clear();
}
}
#endregion
/// <summary>
/// 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 @@ -79,33 +102,49 @@ namespace Hornung.ResourceToolkit.Resolver
/// </returns>
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) {
if (IsResourceManager(member.ReturnType, declaringFileName)) {
SupportedLanguage? language = NRefactoryResourceResolver.GetFileLanguage(declaringFileName);
if (language == null) {
return null;
}
SupportedLanguage? language = NRefactoryResourceResolver.GetFileLanguage(declaringFileName);
if (language == null) {
return null;
}
CompilationUnit cu = NRefactoryAstCacheService.GetFullAst(language.Value, declaringFileName);
if (cu != null) {
CompilationUnit cu = NRefactoryAstCacheService.GetFullAst(language.Value, declaringFileName);
if (cu != null) {
ResourceManagerInitializationFindVisitor visitor = new ResourceManagerInitializationFindVisitor(member);
cu.AcceptVisitor(visitor, null);
if (visitor.FoundFileName != null) {
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 ResourceFileContentRegistry.GetResourceFileContent(visitor.FoundFileName);
return content;
}
}
}
}
return null;
}
return content;
}
return null;
}
@ -114,9 +153,21 @@ namespace Hornung.ResourceToolkit.Resolver @@ -114,9 +153,21 @@ namespace Hornung.ResourceToolkit.Resolver
/// Determines if the specified type is a ResourceManager type that can
/// be handled by this resolver.
/// </summary>
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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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())
)
)
)) {
if (this.resourceManagerMember is IProperty && mrr.ResolvedMember is IField) {
IsTypeRelationshipPossible(resolvedMember, this.resourceManagerMember)) {
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 @@ -290,6 +379,35 @@ namespace Hornung.ResourceToolkit.Resolver
return base.TrackedVisit(assignmentExpression, data);
}
/// <summary>
/// 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.
/// </summary>
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 @@ -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 @@ -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 @@ -377,6 +495,27 @@ namespace Hornung.ResourceToolkit.Resolver
#endregion
/// <summary>
/// Determines whether there is a possible relationship between the
/// return types of member1 and member2.
/// </summary>
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);
}
// ********************************************************************************************************************************
/// <summary>

2
src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ICSharpCodeCoreNRefactoryResourceResolver.cs

@ -28,7 +28,7 @@ namespace Hornung.ResourceToolkit.Resolver @@ -28,7 +28,7 @@ namespace Hornung.ResourceToolkit.Resolver
/// Tries to find a resource reference in the specified expression.
/// </summary>
/// <param name="expressionResult">The ExpressionResult for the expression.</param>
/// <param name="expr">The AST representation of the expression.</param>
/// <param name="expr">The AST representation of the full expression.</param>
/// <param name="resolveResult">SharpDevelop's ResolveResult for the expression.</param>
/// <param name="caretLine">The line where the expression is located.</param>
/// <param name="caretColumn">The column where the expression is located.</param>

73
src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ICSharpCodeCoreResourceResolver.cs

@ -207,13 +207,20 @@ namespace Hornung.ResourceToolkit.Resolver @@ -207,13 +207,20 @@ namespace Hornung.ResourceToolkit.Resolver
return null;
}
string localFile;
foreach (string relativePath in AddInTree.BuildItems<string>("/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<string>("/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;
}
/// <summary>
@ -223,37 +230,45 @@ namespace Hornung.ResourceToolkit.Resolver @@ -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 (project == null ||
!NRefactoryAstCacheService.CacheEnabled || !cachedHostResourceFiles.TryGetValue(project, out hostFile)) {
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;
// 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<string>("/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 @@ -296,5 +311,27 @@ namespace Hornung.ResourceToolkit.Resolver
return coreAssemblyFullPath;
}
#region ICSharpCode.Core resource file mapping cache
static Dictionary<IProject, string> cachedLocalResourceFiles;
static Dictionary<IProject, string> cachedHostResourceFiles;
static ICSharpCodeCoreResourceResolver()
{
cachedLocalResourceFiles = new Dictionary<IProject, string>();
cachedHostResourceFiles = new Dictionary<IProject, string>();
NRefactoryAstCacheService.CacheEnabledChanged += NRefactoryCacheEnabledChanged;
}
static void NRefactoryCacheEnabledChanged(object sender, EventArgs e)
{
if (!NRefactoryAstCacheService.CacheEnabled) {
// Clear cache when disabled.
cachedLocalResourceFiles.Clear();
cachedHostResourceFiles.Clear();
}
}
#endregion
}
}

2
src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/INRefactoryResourceResolver.cs

@ -24,7 +24,7 @@ namespace Hornung.ResourceToolkit.Resolver @@ -24,7 +24,7 @@ namespace Hornung.ResourceToolkit.Resolver
/// Tries to find a resource reference in the specified expression.
/// </summary>
/// <param name="expressionResult">The ExpressionResult for the expression.</param>
/// <param name="expr">The AST representation of the expression.</param>
/// <param name="expr">The AST representation of the full expression.</param>
/// <param name="resolveResult">SharpDevelop's ResolveResult for the expression.</param>
/// <param name="caretLine">The line where the expression is located.</param>
/// <param name="caretColumn">The column where the expression is located.</param>

51
src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/MemberEqualityComparer.cs

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Christian Hornung" email="c-hornung@gmx.de"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using ICSharpCode.SharpDevelop.Dom;
namespace Hornung.ResourceToolkit.Resolver
{
/// <summary>
/// Determines equality of DOM members by region and fully qualified name.
/// </summary>
public class MemberEqualityComparer : IEqualityComparer<IMember>
{
public bool Equals(IMember x, IMember y)
{
if (x == null || y == null) {
return false;
}
if (x.Region.CompareTo(y.Region) != 0) {
return false;
}
IComparer<string> 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();
}
}
}

207
src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/MemberFindAstVisitor.cs

@ -0,0 +1,207 @@ @@ -0,0 +1,207 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Christian Hornung" email="c-hornung@gmx.de"/>
// <version>$Revision$</version>
// </file>
using System;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Visitors;
using ICSharpCode.SharpDevelop.Dom;
namespace Hornung.ResourceToolkit.Resolver
{
/// <summary>
/// Finds a certain member inside the AST.
/// </summary>
public class MemberFindAstVisitor : AbstractAstVisitor
{
readonly IMember memberToFind;
INode memberNode;
/// <summary>
/// Initializes a new instance of the <see cref="MemberFindAstVisitor"/> class.
/// </summary>
/// <param name="member">The member to find.</param>
[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;
}
/// <summary>
/// Gets the INode that belongs to the member specified in the constructor call,
/// or a null reference, if the member cannot be found.
/// </summary>
public INode MemberNode {
get {
return this.memberNode;
}
}
// ********************************************************************************************************************************
/// <summary>
/// Tests whether the specified node is the node belonging to the member we are
/// looking for.
/// </summary>
/// <returns><c>true</c>, if this is the right node or the node has already been found before, otherwise <c>false</c>.</returns>
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);
}
}
}

136
src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NRefactoryAstCacheService.cs

@ -14,16 +14,23 @@ using ICSharpCode.NRefactory; @@ -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
{
/// <summary>
/// Parses files using NRefactory and caches the AST on demand.
/// Provides an event to monitor the cache status and
/// the <see cref="ResolveLowLevel"/> method to resolve expressions
/// faster by making use of the cache.
/// </summary>
public static class NRefactoryAstCacheService
{
static bool cacheEnabled;
static Dictionary<string, CompilationUnit> cachedAstInfo = new Dictionary<string, CompilationUnit>();
static Dictionary<IMember, INode> cachedMemberMappings = new Dictionary<IMember, INode>(new MemberEqualityComparer());
/// <summary>
/// Gets a flag that indicates whether the AST cache is currently enabled.
@ -34,6 +41,21 @@ namespace Hornung.ResourceToolkit.Resolver @@ -34,6 +41,21 @@ namespace Hornung.ResourceToolkit.Resolver
}
}
/// <summary>
/// Occurs when the cache is enabled or disabled.
/// </summary>
public static event EventHandler CacheEnabledChanged;
/// <summary>
/// Raises the CacheEnabledChanged event.
/// </summary>
private static void OnCacheEnabledChanged(EventArgs e)
{
if (CacheEnabledChanged != null) {
CacheEnabledChanged(null, e);
}
}
/// <summary>
/// Enables the AST cache.
/// </summary>
@ -46,6 +68,7 @@ namespace Hornung.ResourceToolkit.Resolver @@ -46,6 +68,7 @@ namespace Hornung.ResourceToolkit.Resolver
}
cacheEnabled = true;
LoggingService.Info("ResourceToolkit: NRefactoryAstCacheService cache enabled");
OnCacheEnabledChanged(EventArgs.Empty);
}
/// <summary>
@ -55,7 +78,9 @@ namespace Hornung.ResourceToolkit.Resolver @@ -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);
}
/// <summary>
@ -91,5 +116,116 @@ namespace Hornung.ResourceToolkit.Resolver @@ -91,5 +116,116 @@ namespace Hornung.ResourceToolkit.Resolver
}
return null;
}
// ********************************************************************************************************************************
/// <summary>
/// Resolves an expression using low-level NRefactoryResolver methods and making
/// use of the cache if possible.
/// </summary>
/// <param name="fileName">The file name of the source code file that contains the expression to be resolved.</param>
/// <param name="caretLine">The 1-based line number of the expression.</param>
/// <param name="caretColumn">The 1-based column number of the expression.</param>
/// <param name="compilationUnit">The CompilationUnit that contains the NRefactory AST for this file. May be <c>null</c> (then the CompilationUnit is retrieved from the cache or the file is parsed).</param>
/// <param name="expression">The expression to be resolved.</param>
/// <param name="context">The ExpressionContext of the expression.</param>
/// <returns>A ResolveResult or <c>null</c> if the expression cannot be resolved.</returns>
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);
}
}
/// <summary>
/// Resolves an expression using low-level NRefactoryResolver methods and making
/// use of the cache if possible.
/// </summary>
/// <param name="fileName">The file name of the source code file that contains the expression to be resolved.</param>
/// <param name="caretLine">The 1-based line number of the expression.</param>
/// <param name="caretColumn">The 1-based column number of the expression.</param>
/// <param name="compilationUnit">The CompilationUnit that contains the NRefactory AST for this file. May be <c>null</c> (then the CompilationUnit is retrieved from the cache or the file is parsed).</param>
/// <param name="expressionString">The expression to be resolved as a string. If this parameter is <c>null</c>, the expression string is generated by using the code generator.</param>
/// <param name="expression">The parsed expression to be resolved.</param>
/// <param name="context">The ExpressionContext of the expression.</param>
/// <returns>A ResolveResult or <c>null</c> if the expression cannot be resolved.</returns>
[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);
}
}
}

33
src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NRefactoryResourceResolver.cs

@ -128,23 +128,30 @@ namespace Hornung.ResourceToolkit.Resolver @@ -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 @@ -163,14 +170,14 @@ namespace Hornung.ResourceToolkit.Resolver
/// Tries to resolve the resource reference using all available
/// NRefactory resource resolvers.
/// </summary>
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;
}
}

41
src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/PositionTrackingAstVisitor.cs

@ -82,40 +82,33 @@ namespace Hornung.ResourceToolkit.Resolver @@ -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);
}
// ********************************************************************************************************************************
/// <summary>
/// Resolves an expression in the current node's context.
/// </summary>
/// <param name="expression">The expression to be resolved.</param>
/// <param name="memberInThisFile">Any member declared in the source file in question. Used to get the language, file name and file content.</param>
public ResolveResult Resolve(Expression expression, IMember memberInThisFile)
/// <param name="fileName">The file name of the source file that contains the expression to be resolved.</param>
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);
}
// ********************************************************************************************************************************

24
src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/PropertyFieldAssociationVisitor.cs

@ -100,8 +100,24 @@ namespace Hornung.ResourceToolkit.Resolver @@ -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 @@ -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 @@ -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 @@ -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

Loading…
Cancel
Save