Browse Source

ResourceToolkit:

The resource resolvers now examine expressions more precisely and also take the code completion trigger character into account instead of simply trying to resolve every possible sub-expression.
This saves a few unneeded attempts to resolve expressions and fixes some problems where the resource code completion window opened when it should not, e.g. after typing something like 'ResourceService.GetString("...").Replace('.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2118 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Christian Hornung 19 years ago
parent
commit
42e127b823
  1. 2
      src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/AbstractNRefactoryResourceCodeCompletionBinding.cs
  2. 2
      src/AddIns/Misc/ResourceToolkit/Project/Src/Commands/TextEditorContextMenuBuilder.cs
  3. 2
      src/AddIns/Misc/ResourceToolkit/Project/Src/ProjectFileDictionaryService.cs
  4. 2
      src/AddIns/Misc/ResourceToolkit/Project/Src/Refactoring/ResourceRefactoringService.cs
  5. 13
      src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/AbstractResourceResolver.cs
  6. 176
      src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/BclNRefactoryResourceResolver.cs
  7. 26
      src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ICSharpCodeCoreNRefactoryResourceResolver.cs
  8. 9
      src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ICSharpCodeCoreResourceResolver.cs
  9. 4
      src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/INRefactoryResourceResolver.cs
  10. 6
      src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/IResourceResolver.cs
  11. 52
      src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NRefactoryAstCacheService.cs
  12. 38
      src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NRefactoryResourceResolver.cs
  13. 10
      src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceResolverService.cs
  14. 2
      src/AddIns/Misc/ResourceToolkit/Project/Src/ToolTips/ResourceToolTipProvider.cs

2
src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/AbstractNRefactoryResourceCodeCompletionBinding.cs

@ -23,7 +23,7 @@ namespace Hornung.ResourceToolkit.CodeCompletion @@ -23,7 +23,7 @@ namespace Hornung.ResourceToolkit.CodeCompletion
if (this.CompletionPossible(editor, ch)) {
ResourceResolveResult result = ResourceResolverService.Resolve(editor);
ResourceResolveResult result = ResourceResolverService.Resolve(editor, ch);
if (result != null) {
if (result.ResourceFileContent != null) {
editor.ShowCompletionWindow(new ResourceCodeCompletionDataProvider(result.ResourceFileContent, this.OutputVisitor, result.CallingClass != null ? result.CallingClass.Name+"." : null), ch);

2
src/AddIns/Misc/ResourceToolkit/Project/Src/Commands/TextEditorContextMenuBuilder.cs

@ -34,7 +34,7 @@ namespace Hornung.ResourceToolkit.Commands @@ -34,7 +34,7 @@ namespace Hornung.ResourceToolkit.Commands
return new ToolStripItem[0];
}
ResourceResolveResult result = ResourceResolverService.Resolve(editor);
ResourceResolveResult result = ResourceResolverService.Resolve(editor, null);
if (result != null && result.ResourceFileContent != null && result.Key != null) {
List<ToolStripItem> items = new List<ToolStripItem>();

2
src/AddIns/Misc/ResourceToolkit/Project/Src/ProjectFileDictionaryService.cs

@ -55,7 +55,9 @@ namespace Hornung.ResourceToolkit @@ -55,7 +55,9 @@ namespace Hornung.ResourceToolkit
}
#if DEBUG
LoggingService.Debug("ResourceToolkit: ProjectFileDictionary: Could not determine project for file '"+(fileName ?? "<null>")+"'.");
#endif
return ProjectService.CurrentProject;
}

2
src/AddIns/Misc/ResourceToolkit/Project/Src/Refactoring/ResourceRefactoringService.cs

@ -104,7 +104,7 @@ namespace Hornung.ResourceToolkit.Refactoring @@ -104,7 +104,7 @@ namespace Hornung.ResourceToolkit.Refactoring
while ((pos = finder.GetNextPossibleOffset(fileName, fileContent, pos)) >= 0) {
Point docPos = doc.OffsetToPosition(pos);
ResourceResolveResult rrr = ResourceResolverService.Resolve(fileName, doc, docPos.Y, docPos.X);
ResourceResolveResult rrr = ResourceResolverService.Resolve(fileName, doc, docPos.Y, docPos.X, null);
if (rrr != null && rrr.ResourceFileContent != null && rrr.Key != null) {
if (finder.IsReferenceToResource(rrr)) {

13
src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/AbstractResourceResolver.cs

@ -29,8 +29,9 @@ namespace Hornung.ResourceToolkit.Resolver @@ -29,8 +29,9 @@ namespace Hornung.ResourceToolkit.Resolver
/// <param name="document">The document that contains the expression to be resolved.</param>
/// <param name="caretLine">The 0-based line in the file that contains the expression to be resolved.</param>
/// <param name="caretColumn">The 0-based column position of the expression to be resolved.</param>
/// <param name="charTyped">The character that has been typed at the caret position but is not yet in the buffer (this is used when invoked from code completion), or <c>null</c>.</param>
/// <returns>A <see cref="ResourceResolveResult"/> that describes which resource is referenced by the expression at the specified position in the specified file, or <c>null</c> if that expression does not reference a (known) resource or if the specified position is invalid.</returns>
public ResourceResolveResult Resolve(string fileName, IDocument document, int caretLine, int caretColumn)
public ResourceResolveResult Resolve(string fileName, IDocument document, int caretLine, int caretColumn, char? charTyped)
{
if (fileName == null || document == null) {
LoggingService.Debug("ResourceToolkit: "+this.GetType().ToString()+".Resolve called with null fileName or document argument");
@ -40,17 +41,18 @@ namespace Hornung.ResourceToolkit.Resolver @@ -40,17 +41,18 @@ namespace Hornung.ResourceToolkit.Resolver
LoggingService.Debug("ResourceToolkit: "+this.GetType().ToString()+".Resolve called with invalid position arguments");
return null;
}
return this.Resolve(fileName, document, caretLine, caretColumn, document.PositionToOffset(new Point(caretColumn, caretLine)));
return this.Resolve(fileName, document, caretLine, caretColumn, document.PositionToOffset(new Point(caretColumn, caretLine)), charTyped);
}
/// <summary>
/// Attempts to resolve a reference to a resource.
/// </summary>
/// <param name="editor">The text editor for which a resource resolution attempt should be performed.</param>
/// <param name="charTyped">The character that has been typed at the caret position but is not yet in the buffer (this is used when invoked from code completion), or <c>null</c>.</param>
/// <returns>A <see cref="ResourceResolveResult"/> that describes which resource is referenced by the expression at the caret in the specified editor, or <c>null</c> if that expression does not reference a (known) resource.</returns>
public ResourceResolveResult Resolve(TextEditorControl editor)
public ResourceResolveResult Resolve(TextEditorControl editor, char? charTyped)
{
return this.Resolve(editor.FileName, editor.Document, editor.ActiveTextAreaControl.Caret.Line, editor.ActiveTextAreaControl.Caret.Column);
return this.Resolve(editor.FileName, editor.Document, editor.ActiveTextAreaControl.Caret.Line, editor.ActiveTextAreaControl.Caret.Column, charTyped);
}
// ********************************************************************************************************************************
@ -63,8 +65,9 @@ namespace Hornung.ResourceToolkit.Resolver @@ -63,8 +65,9 @@ namespace Hornung.ResourceToolkit.Resolver
/// <param name="caretLine">The 0-based line in the file that contains the expression to be resolved.</param>
/// <param name="caretColumn">The 0-based column position of the expression to be resolved.</param>
/// <param name="caretOffset">The offset of the position of the expression to be resolved.</param>
/// <param name="charTyped">The character that has been typed at the caret position but is not yet in the buffer (this is used when invoked from code completion), or <c>null</c>.</param>
/// <returns>A <see cref="ResourceResolveResult"/> that describes which resource is referenced by the expression at the specified position in the specified file, or <c>null</c> if that expression does not reference a (known) resource.</returns>
protected abstract ResourceResolveResult Resolve(string fileName, IDocument document, int caretLine, int caretColumn, int caretOffset);
protected abstract ResourceResolveResult Resolve(string fileName, IDocument document, int caretLine, int caretColumn, int caretOffset, char? charTyped);
/// <summary>
/// Determines whether this resolver supports resolving resources in the given file.

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

@ -35,31 +35,131 @@ namespace Hornung.ResourceToolkit.Resolver @@ -35,31 +35,131 @@ namespace Hornung.ResourceToolkit.Resolver
/// <param name="caretColumn">The column where the expression is located.</param>
/// <param name="fileName">The name of the source file where the expression is located.</param>
/// <param name="fileContent">The content of the source file where the expression is located.</param>
/// <param name="expressionFinder">The ExpressionFinder for the file.</param>
/// <param name="charTyped">The character that has been typed at the caret position but is not yet in the buffer (this is used when invoked from code completion), or <c>null</c>.</param>
/// <returns>A ResourceResolveResult describing the referenced resource, or <c>null</c>, if this expression does not reference a resource using the standard .NET framework classes.</returns>
public ResourceResolveResult Resolve(ExpressionResult expressionResult, Expression expr, ResolveResult resolveResult, int caretLine, int caretColumn, string fileName, string fileContent)
public ResourceResolveResult Resolve(ExpressionResult expressionResult, Expression expr, ResolveResult resolveResult, int caretLine, int caretColumn, string fileName, string fileContent, IExpressionFinder expressionFinder, char? charTyped)
{
IResourceFileContent rfc = null;
/*
* We need to catch the following cases here:
*
* Something.GetString(
* Something.GetString("...")
* Something[
* Something["..."]
*
*/
MemberResolveResult mrr = resolveResult as MemberResolveResult;
if (mrr != null) {
rfc = ResolveResourceFileContent(mrr.ResolvedMember);
} else {
if (charTyped == '(') {
LocalResolveResult lrr = resolveResult as LocalResolveResult;
if (lrr != null) {
if (!lrr.IsParameter) {
rfc = ResolveResourceFileContent(lrr.Field);
// Something.GetString
// This is a MethodResolveResult and we need the reference to "Something",
// which is the next outer expression.
// This is only valid when invoked from code completion
// and the method invocation character ('(' in C# and VB)
// has been typed.
// This code is also reused when reducing a complete InvocationExpression
// (MemberResolveResult) to the method reference by passing '(' as
// charTyped explicitly.
MethodResolveResult methrr = resolveResult as MethodResolveResult;
if (methrr != null) {
if ((methrr.Name == "GetString" || methrr.Name == "GetObject" || methrr.Name == "GetStream") &&
(resolveResult = NRefactoryAstCacheService.ResolveNextOuterExpression(ref expressionResult, caretLine, caretColumn, fileName, expressionFinder)) != null) {
return ResolveResource(resolveResult, expr);
} else {
return null;
}
}
}
// Do not use "else if" here.
// '(' is also the IndexerExpressionStartToken for VB,
// so the "else" block further down might still apply.
if (rfc != null) {
string key = GetKeyFromExpression(expr);
if (charTyped == null) {
// A MemberResolveResult with a complete expression
// must only be considered a valid resource reference
// when Resolve is not invoked from code completion
// (i.e. charTyped == null) because this indicates
// that the resource reference is already before the typed character
// and we are not interested in the following expression.
// This may happen when typing something like:
// Something.GetString("...")[
MemberResolveResult mrr = resolveResult as MemberResolveResult;
if (mrr != null) {
if (mrr.ResolvedMember is IMethod &&
(mrr.ResolvedMember.Name == "GetString" || mrr.ResolvedMember.Name == "GetObject" || mrr.ResolvedMember.Name == "GetStream")) {
// Something.GetString("...")
// This is a MemberResolveResult and we need the reference to "Something".
// The expression finder may only remove the string literal, so
// we have to call Resolve again in this case to resolve
// the method reference.
if ((resolveResult = NRefactoryAstCacheService.ResolveNextOuterExpression(ref expressionResult, caretLine, caretColumn, fileName, expressionFinder)) != null) {
if (resolveResult is MethodResolveResult) {
return this.Resolve(expressionResult, expr, resolveResult, caretLine, caretColumn, fileName, fileContent, expressionFinder, '(');
} else {
return ResolveResource(resolveResult, expr);
}
} else {
return null;
}
} else if (expr is IndexerExpression &&
IsResourceManager(mrr.ResolvedMember.DeclaringType.DefaultReturnType, fileName)) {
// Something["..."] is an IndexerExpression.
// We need the reference to Something and this is
// the next outer expression.
if ((resolveResult = NRefactoryAstCacheService.ResolveNextOuterExpression(ref expressionResult, caretLine, caretColumn, fileName, expressionFinder)) != null) {
return ResolveResource(resolveResult, expr);
} else {
return null;
}
}
}
} else {
// This request is triggered from code completion.
// The only case that has not been caught above is:
// Something[
// The reference to "Something" is already in this expression.
// So we have to test the trigger character against the
// indexer expression start token of the file's language.
LanguageProperties lp = NRefactoryResourceResolver.GetLanguagePropertiesForFile(fileName);
if (lp != null &&
!String.IsNullOrEmpty(lp.IndexerExpressionStartToken) &&
lp.IndexerExpressionStartToken[0] == charTyped) {
#if DEBUG
LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver: Indexer expression start typed, ResolveResult: "+resolveResult.ToString());
LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver: -> Expression: "+expr.ToString());
#endif
return ResolveResource(resolveResult, expr);
}
// TODO: Add information about return type (of the resource, if present).
return new ResourceResolveResult(resolveResult.CallingClass, resolveResult.CallingMember, null, rfc, key);
}
return null;
@ -87,6 +187,44 @@ namespace Hornung.ResourceToolkit.Resolver @@ -87,6 +187,44 @@ namespace Hornung.ResourceToolkit.Resolver
#endregion
/// <summary>
/// Tries to find a resource reference in the specified expression.
/// </summary>
/// <param name="resolveResult">The ResolveResult that describes the referenced member.</param>
/// <param name="expr">The AST representation of the full expression.</param>
/// <returns>
/// The ResourceResolveResult describing the referenced resource, if successful,
/// or a null reference, if the referenced member is not a resource manager
/// or if the resource file cannot be determined.
/// </returns>
static ResourceResolveResult ResolveResource(ResolveResult resolveResult, Expression expr)
{
IResourceFileContent rfc = null;
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);
}
}
}
if (rfc != null) {
string key = GetKeyFromExpression(expr);
// TODO: Add information about return type (of the resource, if present).
return new ResourceResolveResult(resolveResult.CallingClass, resolveResult.CallingMember, null, rfc, key);
}
return null;
}
/// <summary>
/// Tries to determine the resource file content which is referenced by the
/// resource manager which is assigned to the specified member.
@ -149,6 +287,8 @@ namespace Hornung.ResourceToolkit.Resolver @@ -149,6 +287,8 @@ namespace Hornung.ResourceToolkit.Resolver
/// Determines if the specified type is a ResourceManager type that can
/// be handled by this resolver.
/// </summary>
/// <param name="type">The type that will be checked if it is a ResourceManager.</param>
/// <param name="sourceFileName">The name of the source code file where the reference to this type occurs.</param>
static bool IsResourceManager(IReturnType type, string sourceFileName)
{
IProject p = ProjectFileDictionaryService.GetProjectForFile(sourceFileName);
@ -163,13 +303,13 @@ namespace Hornung.ResourceToolkit.Resolver @@ -163,13 +303,13 @@ namespace Hornung.ResourceToolkit.Resolver
return false;
}
IClass resourceManager = pc.GetClass("System.Resources.ResourceManager");
if (resourceManager == null) {
IClass c = type.GetUnderlyingClass();
if (c == null) {
return false;
}
IClass c = type.GetUnderlyingClass();
if (c == null) {
IClass resourceManager = pc.GetClass("System.Resources.ResourceManager");
if (resourceManager == null) {
return false;
}

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

@ -31,8 +31,10 @@ namespace Hornung.ResourceToolkit.Resolver @@ -31,8 +31,10 @@ namespace Hornung.ResourceToolkit.Resolver
/// <param name="caretColumn">The column where the expression is located.</param>
/// <param name="fileName">The name of the source file where the expression is located.</param>
/// <param name="fileContent">The content of the source file where the expression is located.</param>
/// <param name="expressionFinder">The ExpressionFinder for the file.</param>
/// <param name="charTyped">The character that has been typed at the caret position but is not yet in the buffer (this is used when invoked from code completion), or <c>null</c>.</param>
/// <returns>A ResourceResolveResult describing the referenced resource, or <c>null</c>, if this expression does not reference a resource using the ICSharpCode.Core.ResourceService class.</returns>
public ResourceResolveResult Resolve(ExpressionResult expressionResult, Expression expr, ResolveResult resolveResult, int caretLine, int caretColumn, string fileName, string fileContent)
public ResourceResolveResult Resolve(ExpressionResult expressionResult, Expression expr, ResolveResult resolveResult, int caretLine, int caretColumn, string fileName, string fileContent, IExpressionFinder expressionFinder, char? charTyped)
{
IMember member = null;
@ -41,12 +43,30 @@ namespace Hornung.ResourceToolkit.Resolver @@ -41,12 +43,30 @@ namespace Hornung.ResourceToolkit.Resolver
// has already been typed.
MemberResolveResult mrr = resolveResult as MemberResolveResult;
if (mrr != null) {
member = mrr.ResolvedMember;
// If it is a MemberResolveResult, this indicates that
// the complete expression is already in the buffer.
// So we only assign the member if Resolve is not invoked
// from code completion to prevent the code completion window
// from opening when typing something like:
// ResourceService.GetString(...)[
if (charTyped == null) {
member = mrr.ResolvedMember;
}
} else {
MethodResolveResult methrr = resolveResult as MethodResolveResult;
if (methrr != null) {
member = methrr.GetMethodIfSingleOverload();
// If it is a MethodResolveResult, the expression is incomplete.
// Accept only if '(' has been typed.
if (charTyped == '(') {
member = methrr.GetMethodIfSingleOverload();
}
}
}
if (member is IMethod &&

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

@ -91,9 +91,16 @@ namespace Hornung.ResourceToolkit.Resolver @@ -91,9 +91,16 @@ namespace Hornung.ResourceToolkit.Resolver
/// <param name="caretLine">The 0-based line in the file that contains the expression to be resolved.</param>
/// <param name="caretColumn">The 0-based column position of the expression to be resolved.</param>
/// <param name="caretOffset">The offset of the position of the expression to be resolved.</param>
/// <param name="charTyped">The character that has been typed at the caret position but is not yet in the buffer (this is used when invoked from code completion), or <c>null</c>.</param>
/// <returns>A <see cref="ResourceResolveResult"/> that describes which resource is referenced by the expression at the specified position in the specified file, or <c>null</c> if that expression does not reference a (known) resource.</returns>
protected override ResourceResolveResult Resolve(string fileName, IDocument document, int caretLine, int caretColumn, int caretOffset)
protected override ResourceResolveResult Resolve(string fileName, IDocument document, int caretLine, int caretColumn, int caretOffset, char? charTyped)
{
// If Resolve is invoked from code completion,
// we are only interested in the ':' character of '${res:'.
if (charTyped != null && charTyped != ':') {
return null;
}
// Find $ character to the left of the caret.
caretOffset += 1;
char ch;

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

@ -30,8 +30,10 @@ namespace Hornung.ResourceToolkit.Resolver @@ -30,8 +30,10 @@ namespace Hornung.ResourceToolkit.Resolver
/// <param name="caretColumn">The column where the expression is located.</param>
/// <param name="fileName">The name of the source file where the expression is located.</param>
/// <param name="fileContent">The content of the source file where the expression is located.</param>
/// <param name="expressionFinder">The ExpressionFinder for the file.</param>
/// <param name="charTyped">The character that has been typed at the caret position but is not yet in the buffer (this is used when invoked from code completion), or <c>null</c>.</param>
/// <returns>A ResourceResolveResult describing the referenced resource, or <c>null</c>, if this expression does not reference a resource in a known way.</returns>
ResourceResolveResult Resolve(ExpressionResult expressionResult, Expression expr, ResolveResult resolveResult, int caretLine, int caretColumn, string fileName, string fileContent);
ResourceResolveResult Resolve(ExpressionResult expressionResult, Expression expr, ResolveResult resolveResult, int caretLine, int caretColumn, string fileName, string fileContent, IExpressionFinder expressionFinder, char? charTyped);
/// <summary>
/// Gets a list of patterns that can be searched for in the specified file

6
src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/IResourceResolver.cs

@ -27,15 +27,17 @@ namespace Hornung.ResourceToolkit.Resolver @@ -27,15 +27,17 @@ namespace Hornung.ResourceToolkit.Resolver
/// <param name="document">The document that contains the expression to be resolved.</param>
/// <param name="caretLine">The 1-based line in the file that contains the expression to be resolved.</param>
/// <param name="caretColumn">The 1-based column position of the expression to be resolved.</param>
/// <param name="charTyped">The character that has been typed at the caret position but is not yet in the buffer (this is used when invoked from code completion), or <c>null</c>.</param>
/// <returns>A <see cref="ResourceResolveResult"/> that describes which resource is referenced by the expression at the specified position in the specified file, or <c>null</c> if that expression does not reference a (known) resource.</returns>
ResourceResolveResult Resolve(string fileName, IDocument document, int caretLine, int caretColumn);
ResourceResolveResult Resolve(string fileName, IDocument document, int caretLine, int caretColumn, char? charTyped);
/// <summary>
/// Attempts to resolve a reference to a resource.
/// </summary>
/// <param name="editor">The text editor for which a resource resolution attempt should be performed.</param>
/// <param name="charTyped">The character that has been typed at the caret position but is not yet in the buffer (this is used when invoked from code completion), or <c>null</c>.</param>
/// <returns>A <see cref="ResourceResolveResult"/> that describes which resource is referenced by the expression at the caret in the specified editor, or <c>null</c> if that expression does not reference a (known) resource.</returns>
ResourceResolveResult Resolve(TextEditorControl editor);
ResourceResolveResult Resolve(TextEditorControl editor, char? charTyped);
/// <summary>
/// Determines whether this resolver supports resolving resources in the given file.

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

@ -118,6 +118,24 @@ namespace Hornung.ResourceToolkit.Resolver @@ -118,6 +118,24 @@ namespace Hornung.ResourceToolkit.Resolver
// ********************************************************************************************************************************
/// <summary>
/// Parses an expression with NRefactory.
/// </summary>
/// <param name="fileName">The file name of the source code file that contains the expression.</param>
/// <param name="expression">The expression to parse.</param>
/// <returns>The parsed expression or <c>null</c> if the expression cannot be parsed or the language of the source code file is not supported.</returns>
public static Expression ParseExpression(string fileName, string expression)
{
SupportedLanguage? l = NRefactoryResourceResolver.GetFileLanguage(fileName);
if (l == null) {
return null;
}
using (ICSharpCode.NRefactory.IParser p = ICSharpCode.NRefactory.ParserFactory.CreateParser(l.Value, new System.IO.StringReader(expression))) {
return p.ParseExpression();
}
}
/// <summary>
/// Resolves an expression using low-level NRefactoryResolver methods and making
/// use of the cache if possible.
@ -131,13 +149,9 @@ namespace Hornung.ResourceToolkit.Resolver @@ -131,13 +149,9 @@ namespace Hornung.ResourceToolkit.Resolver
/// <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);
}
Expression expr = ParseExpression(fileName, expression);
if (expr == null) return null;
return ResolveLowLevel(fileName, caretLine, caretColumn, compilationUnit, expression, expr, context);
}
/// <summary>
@ -216,7 +230,7 @@ namespace Hornung.ResourceToolkit.Resolver @@ -216,7 +230,7 @@ namespace Hornung.ResourceToolkit.Resolver
if (resolver.CallingMember != null) {
// Cache member->node mappings to improves performance
// Cache member->node mappings to improve performance
// (if cache is enabled)
INode memberNode;
if (!CacheEnabled || !cachedMemberMappings.TryGetValue(resolver.CallingMember, out memberNode)) {
@ -238,5 +252,27 @@ namespace Hornung.ResourceToolkit.Resolver @@ -238,5 +252,27 @@ namespace Hornung.ResourceToolkit.Resolver
return resolver.ResolveInternal(expression, context);
}
/// <summary>
/// Resolves the next outer expression of the specified expression
/// using low-level NRefactoryResolver methods and making
/// use of the cache if possible.
/// </summary>
/// <param name="expressionResult">The ExpressionResult that contains the expression to be resolved. The contained expression will be set to the next outer expression or <c>null</c> if there is no such expression.</param>
/// <param name="caretLine">The 0-based line number of the expression.</param>
/// <param name="caretColumn">The 0-based column number of the expression.</param>
/// <param name="fileName">The file name of the source code file that contains the expression to be resolved.</param>
/// <param name="expressionFinder">The ExpressionFinder for this source code file.</param>
/// <returns>A ResolveResult or <c>null</c> if the outer expression cannot be resolved or if the specified expression is the outermost expression.</returns>
public static ResolveResult ResolveNextOuterExpression(ref ExpressionResult expressionResult, int caretLine, int caretColumn, string fileName, IExpressionFinder expressionFinder)
{
if (!String.IsNullOrEmpty(expressionResult.Expression = expressionFinder.RemoveLastPart(expressionResult.Expression))) {
Expression nextExpression;
if ((nextExpression = ParseExpression(fileName, expressionResult.Expression)) != null) {
return ResolveLowLevel(fileName, caretLine + 1, caretColumn + 1, null, expressionResult.Expression, nextExpression, expressionResult.Context);
}
}
return null;
}
}
}

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

@ -102,8 +102,9 @@ namespace Hornung.ResourceToolkit.Resolver @@ -102,8 +102,9 @@ namespace Hornung.ResourceToolkit.Resolver
/// <param name="caretLine">The 0-based line in the file that contains the expression to be resolved.</param>
/// <param name="caretColumn">The 0-based column position of the expression to be resolved.</param>
/// <param name="caretOffset">The offset of the position of the expression to be resolved.</param>
/// <param name="charTyped">The character that has been typed at the caret position but is not yet in the buffer (this is used when invoked from code completion), or <c>null</c>.</param>
/// <returns>A <see cref="ResourceResolveResult"/> that describes which resource is referenced by the expression at the specified position in the specified file, or <c>null</c> if that expression does not reference a (known) resource.</returns>
protected override ResourceResolveResult Resolve(string fileName, IDocument document, int caretLine, int caretColumn, int caretOffset)
protected override ResourceResolveResult Resolve(string fileName, IDocument document, int caretLine, int caretColumn, int caretOffset, char? charTyped)
{
IExpressionFinder ef = ParserService.GetExpressionFinder(fileName);
if (ef == null) {
@ -124,38 +125,13 @@ namespace Hornung.ResourceToolkit.Resolver @@ -124,38 +125,13 @@ namespace Hornung.ResourceToolkit.Resolver
if (result.Expression != null) {
ResourceResolveResult rrr = null;
Expression expr = NRefactoryAstCacheService.ParseExpression(fileName, result.Expression);
SupportedLanguage? language = GetFileLanguage(fileName);
if (language == null) {
if (expr == 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) {
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);
}
return rrr;
return TryResolve(result, expr, caretLine, caretColumn, fileName, document.TextContent, ef, charTyped);
}
@ -168,14 +144,14 @@ namespace Hornung.ResourceToolkit.Resolver @@ -168,14 +144,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, Expression fullExpr, int caretLine, int caretColumn, string fileName, string fileContent)
static ResourceResolveResult TryResolve(ExpressionResult result, Expression expr, int caretLine, int caretColumn, string fileName, string fileContent, IExpressionFinder expressionFinder, char? charTyped)
{
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, fullExpr, rr, caretLine, caretColumn, fileName, fileContent)) != null) {
if ((rrr = resolver.Resolve(result, expr, rr, caretLine, caretColumn, fileName, fileContent, expressionFinder, charTyped)) != null) {
return rrr;
}
}

10
src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceResolverService.cs

@ -50,12 +50,13 @@ namespace Hornung.ResourceToolkit @@ -50,12 +50,13 @@ namespace Hornung.ResourceToolkit
/// Attempts to resolve a reference to a resource using all registered resolvers.
/// </summary>
/// <param name="editor">The text editor for which a resource resolution attempt should be performed.</param>
/// <param name="charTyped">The character that has been typed at the caret position but is not yet in the buffer (this is used when invoked from code completion), or <c>null</c>.</param>
/// <returns>A <see cref="ResourceResolveResult"/> that describes which resource is referenced by the expression at the caret in the specified editor, or <c>null</c> if all registered resolvers return <c>null</c>.</returns>
public static ResourceResolveResult Resolve(TextEditorControl editor)
public static ResourceResolveResult Resolve(TextEditorControl editor, char? charTyped)
{
ResourceResolveResult result;
foreach (IResourceResolver resolver in Resolvers) {
if ((result = resolver.Resolve(editor)) != null) {
if ((result = resolver.Resolve(editor, charTyped)) != null) {
return result;
}
}
@ -69,12 +70,13 @@ namespace Hornung.ResourceToolkit @@ -69,12 +70,13 @@ namespace Hornung.ResourceToolkit
/// <param name="document">The document that contains the expression to be resolved.</param>
/// <param name="caretLine">The 0-based line in the file that contains the expression to be resolved.</param>
/// <param name="caretColumn">The 0-based column position of the expression to be resolved.</param>
/// <param name="charTyped">The character that has been typed at the caret position but is not yet in the buffer (this is used when invoked from code completion), or <c>null</c>.</param>
/// <returns>A <see cref="ResourceResolveResult"/> that describes which resource is referenced by the expression at the caret in the specified editor, or <c>null</c> if all registered resolvers return <c>null</c>.</returns>
public static ResourceResolveResult Resolve(string fileName, IDocument document, int caretLine, int caretColumn)
public static ResourceResolveResult Resolve(string fileName, IDocument document, int caretLine, int caretColumn, char? charTyped)
{
ResourceResolveResult result;
foreach (IResourceResolver resolver in Resolvers) {
if ((result = resolver.Resolve(fileName, document, caretLine, caretColumn)) != null) {
if ((result = resolver.Resolve(fileName, document, caretLine, caretColumn, charTyped)) != null) {
return result;
}
}

2
src/AddIns/Misc/ResourceToolkit/Project/Src/ToolTips/ResourceToolTipProvider.cs

@ -28,7 +28,7 @@ namespace Hornung.ResourceToolkit.ToolTips @@ -28,7 +28,7 @@ namespace Hornung.ResourceToolkit.ToolTips
return null;
}
ResourceResolveResult result = ResourceResolverService.Resolve(textArea.MotherTextEditorControl.FileName, doc, logicPos.Y, logicPos.X);
ResourceResolveResult result = ResourceResolverService.Resolve(textArea.MotherTextEditorControl.FileName, doc, logicPos.Y, logicPos.X, null);
if (result != null && result.ResourceFileContent != null) {
return new ToolTipInfo(ResourceResolverService.FormatResourceDescription(result.ResourceFileContent, result.Key));

Loading…
Cancel
Save