Browse Source

ResourceToolkit: Support resolving calls to ComponentResourceManager.ApplyResources which are generated by the forms designer PropertyReflection localization model. Added new ResourcePrefixResolveResult for this purpose, to indicate that a call refers to all resources starting with a specified prefix. Resources used by ApplyResources are no longer listed as unused.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@3299 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Christian Hornung 18 years ago
parent
commit
69b69f77bb
  1. 46
      src/AddIns/Misc/ResourceToolkit/Project/Src/Refactoring/ResourceRefactoringService.cs
  2. 2
      src/AddIns/Misc/ResourceToolkit/Project/Src/Refactoring/SpecificResourceReferenceFinder.cs
  3. 33
      src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/BclNRefactoryResourceResolver.cs
  4. 39
      src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ResourceResolveResult.cs
  5. 28
      src/AddIns/Misc/ResourceToolkit/Test/CSharp/BclNRefactoryResourceResolverTests.cs

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

@ -109,26 +109,32 @@ namespace Hornung.ResourceToolkit.Refactoring
TextLocation docPos = doc.OffsetToPosition(pos); TextLocation docPos = doc.OffsetToPosition(pos);
ResourceResolveResult rrr = ResourceResolverService.Resolve(fileName, doc, docPos.Y, docPos.X, null); ResourceResolveResult rrr = ResourceResolverService.Resolve(fileName, doc, docPos.Y, docPos.X, null);
if (rrr != null && rrr.ResourceFileContent != null && rrr.Key != null) { if (rrr != null && rrr.ResourceFileContent != null) {
if (finder.IsReferenceToResource(rrr)) { if (finder.IsReferenceToResource(rrr)) {
// The actual location of the key string may be after 'pos' because if (rrr.Key != null) {
// the resolvers may find an expression just before it.
string keyString = rrr.Key;
int keyPos = fileContent.IndexOf(keyString, pos, StringComparison.InvariantCultureIgnoreCase);
if (keyPos < pos) { // The actual location of the key string may be after 'pos' because
// The key may be escaped in some way in the document. // the resolvers may find an expression just before it.
// Try using the code generator to find this out. string keyString = rrr.Key;
keyPos = FindStringLiteral(fileName, fileContent, rrr.Key, pos, out keyString); int keyPos = fileContent.IndexOf(keyString, pos, StringComparison.InvariantCultureIgnoreCase);
}
if (keyPos < pos) {
// The key may be escaped in some way in the document.
// Try using the code generator to find this out.
keyPos = FindStringLiteral(fileName, fileContent, rrr.Key, pos, out keyString);
}
if (keyPos < pos) {
if (monitor != null) monitor.ShowingDialog = true;
MessageService.ShowWarning("ResourceToolkit: The key '"+rrr.Key+"' could not be located at the resolved position in the file '"+fileName+"'.");
if (monitor != null) monitor.ShowingDialog = false;
} else {
references.Add(new Reference(fileName, keyPos, keyString.Length, keyString, rrr));
}
if (keyPos < pos) {
if (monitor != null) monitor.ShowingDialog = true;
MessageService.ShowWarning("ResourceToolkit: The key '"+rrr.Key+"' could not be located at the resolved position in the file '"+fileName+"'.");
if (monitor != null) monitor.ShowingDialog = false;
} else { } else {
references.Add(new Reference(fileName, keyPos, keyString.Length, keyString, rrr)); references.Add(new Reference(fileName, pos, 0, null, rrr));
} }
} }
@ -216,15 +222,22 @@ namespace Hornung.ResourceToolkit.Refactoring
// Generate a dictonary of resource file names and the // Generate a dictonary of resource file names and the
// corresponding referenced keys. // corresponding referenced keys.
Dictionary<string, List<string>> referencedKeys = new Dictionary<string, List<string>>(); Dictionary<string, List<string>> referencedKeys = new Dictionary<string, List<string>>();
Dictionary<string, List<string>> referencedPrefixes = new Dictionary<string, List<string>>();
foreach (Reference reference in references) { foreach (Reference reference in references) {
ResourceResolveResult rrr = (ResourceResolveResult)reference.ResolveResult; ResourceResolveResult rrr = (ResourceResolveResult)reference.ResolveResult;
if (rrr.ResourceFileContent != null) { if (rrr.ResourceFileContent != null) {
string fileName = rrr.FileName; string fileName = rrr.FileName;
if (!referencedKeys.ContainsKey(fileName)) { if (!referencedKeys.ContainsKey(fileName)) {
referencedKeys.Add(fileName, new List<string>()); referencedKeys.Add(fileName, new List<string>());
referencedPrefixes.Add(fileName, new List<string>());
} }
if (rrr.Key != null && !referencedKeys[fileName].Contains(rrr.Key)) { if (rrr.Key != null && !referencedKeys[fileName].Contains(rrr.Key)) {
referencedKeys[fileName].Add(rrr.Key); referencedKeys[fileName].Add(rrr.Key);
} else {
ResourcePrefixResolveResult rprr = rrr as ResourcePrefixResolveResult;
if (rprr != null && rprr.Prefix != null && !referencedPrefixes[fileName].Contains(rprr.Prefix)) {
referencedPrefixes[fileName].Add(rprr.Prefix);
}
} }
} else { } else {
if (monitor != null) monitor.ShowingDialog = true; if (monitor != null) monitor.ShowingDialog = true;
@ -239,7 +252,8 @@ namespace Hornung.ResourceToolkit.Refactoring
LoggingService.Debug("ResourceToolkit: FindUnusedKeys: Referenced resource file '"+fileName+"'"); LoggingService.Debug("ResourceToolkit: FindUnusedKeys: Referenced resource file '"+fileName+"'");
#endif #endif
foreach (KeyValuePair<string, object> entry in ResourceFileContentRegistry.GetResourceFileContent(fileName).Data) { foreach (KeyValuePair<string, object> entry in ResourceFileContentRegistry.GetResourceFileContent(fileName).Data) {
if (!referencedKeys[fileName].Contains(entry.Key)) { if (!referencedKeys[fileName].Contains(entry.Key) &&
!referencedPrefixes[fileName].Any(prefix => entry.Key.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase))) {
unused.Add(new ResourceItem(fileName, entry.Key)); unused.Add(new ResourceItem(fileName, entry.Key));
} }
} }

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

@ -65,7 +65,7 @@ namespace Hornung.ResourceToolkit.Refactoring
public bool IsReferenceToResource(ResourceResolveResult result) public bool IsReferenceToResource(ResourceResolveResult result)
{ {
return FileUtility.IsEqualFileName(this.ResourceFileName, result.FileName) && return FileUtility.IsEqualFileName(this.ResourceFileName, result.FileName) &&
result.Key.Equals(this.Key, StringComparison.InvariantCultureIgnoreCase); this.Key.Equals(result.Key, StringComparison.InvariantCultureIgnoreCase);
} }
// ******************************************************************************************************************************** // ********************************************************************************************************************************

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

@ -45,6 +45,7 @@ namespace Hornung.ResourceToolkit.Resolver
* *
* Something.GetString( * Something.GetString(
* Something.GetString("...") * Something.GetString("...")
* Something.ApplyResources(obj, "...")
* Something[ * Something[
* Something["..."] * Something["..."]
* *
@ -65,7 +66,7 @@ namespace Hornung.ResourceToolkit.Resolver
MethodGroupResolveResult methrr = resolveResult as MethodGroupResolveResult; MethodGroupResolveResult methrr = resolveResult as MethodGroupResolveResult;
if (methrr != null) { if (methrr != null) {
if ((methrr.Name == "GetString" || methrr.Name == "GetObject" || methrr.Name == "GetStream") && if ((methrr.Name == "GetString" || methrr.Name == "GetObject" || methrr.Name == "GetStream" || methrr.Name == "ApplyResources") &&
(resolveResult = NRefactoryAstCacheService.ResolveNextOuterExpression(ref expressionResult, caretLine, caretColumn, fileName, fileContent, expressionFinder)) != null) { (resolveResult = NRefactoryAstCacheService.ResolveNextOuterExpression(ref expressionResult, caretLine, caretColumn, fileName, fileContent, expressionFinder)) != null) {
return ResolveResource(resolveResult, expr); return ResolveResource(resolveResult, expr);
@ -98,7 +99,7 @@ namespace Hornung.ResourceToolkit.Resolver
if (mrr != null) { if (mrr != null) {
if (mrr.ResolvedMember is IMethod && if (mrr.ResolvedMember is IMethod &&
(mrr.ResolvedMember.Name == "GetString" || mrr.ResolvedMember.Name == "GetObject" || mrr.ResolvedMember.Name == "GetStream")) { (mrr.ResolvedMember.Name == "GetString" || mrr.ResolvedMember.Name == "GetObject" || mrr.ResolvedMember.Name == "GetStream" || mrr.ResolvedMember.Name == "ApplyResources")) {
// Something.GetString("...") // Something.GetString("...")
// This is a MemberResolveResult and we need the reference to "Something". // This is a MemberResolveResult and we need the reference to "Something".
@ -216,10 +217,14 @@ namespace Hornung.ResourceToolkit.Resolver
} }
if (rsr != null) { if (rsr != null) {
string key = GetKeyFromExpression(expr); bool isPrefixOnly;
string key = GetKeyFromExpression(expr, out isPrefixOnly);
// TODO: Add information about return type (of the resource, if present). if (isPrefixOnly) {
return new ResourceResolveResult(resolveResult.CallingClass, resolveResult.CallingMember, null, rsr, key); return new ResourcePrefixResolveResult(resolveResult.CallingClass, resolveResult.CallingMember, null, rsr, key);
} else {
return new ResourceResolveResult(resolveResult.CallingClass, resolveResult.CallingMember, null, rsr, key);
}
} }
return null; return null;
@ -683,8 +688,9 @@ namespace Hornung.ResourceToolkit.Resolver
/// <summary> /// <summary>
/// Tries to infer the resource key being referenced from the given expression. /// Tries to infer the resource key being referenced from the given expression.
/// </summary> /// </summary>
static string GetKeyFromExpression(Expression expr) static string GetKeyFromExpression(Expression expr, out bool isPrefixOnly)
{ {
isPrefixOnly = false;
#if DEBUG #if DEBUG
LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver trying to get key from expression: "+expr.ToString()); LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver trying to get key from expression: "+expr.ToString());
#endif #endif
@ -722,6 +728,20 @@ namespace Hornung.ResourceToolkit.Resolver
} }
} }
} }
} else if (fre.MemberName == "ApplyResources") {
if (invocation.Arguments.Count >= 2) {
PrimitiveExpression p = invocation.Arguments[1] as PrimitiveExpression;
if (p != null) {
string key = p.Value as string;
if (key != null) {
#if DEBUG
LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver found key prefix: "+key);
#endif
isPrefixOnly = true;
return key;
}
}
}
} }
} }
} }
@ -743,6 +763,7 @@ namespace Hornung.ResourceToolkit.Resolver
"GetString", "GetString",
"GetObject", "GetObject",
"GetStream", "GetStream",
"ApplyResources",
(NRefactoryResourceResolver.GetLanguagePropertiesForFile(fileName) ?? LanguageProperties.None).IndexerExpressionStartToken (NRefactoryResourceResolver.GetLanguagePropertiesForFile(fileName) ?? LanguageProperties.None).IndexerExpressionStartToken
}; };
} }

39
src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ResourceResolveResult.cs

@ -17,8 +17,8 @@ namespace Hornung.ResourceToolkit.Resolver
public class ResourceResolveResult : ResolveResult public class ResourceResolveResult : ResolveResult
{ {
ResourceSetReference resourceSetReference; readonly ResourceSetReference resourceSetReference;
string key; readonly string key;
/// <summary> /// <summary>
/// Gets the <see cref="ResourceSetReference"/> that describes the resource set being referenced. /// Gets the <see cref="ResourceSetReference"/> that describes the resource set being referenced.
@ -44,7 +44,7 @@ namespace Hornung.ResourceToolkit.Resolver
/// <summary> /// <summary>
/// Gets the resource key being referenced. May be null if the key is unknown/not yet typed. /// Gets the resource key being referenced. May be null if the key is unknown/not yet typed.
/// </summary> /// </summary>
public string Key { public virtual string Key {
get { return this.key; } get { return this.key; }
} }
@ -90,4 +90,37 @@ namespace Hornung.ResourceToolkit.Resolver
this.ResourceSetReference, this.Key); this.ResourceSetReference, this.Key);
} }
} }
/// <summary>
/// Describes a reference to a group of resource keys with a common prefix.
/// </summary>
public sealed class ResourcePrefixResolveResult : ResourceResolveResult
{
/// <summary>
/// Initializes a new instance of the <see cref="ResourceResolveResult"/> class.
/// </summary>
/// <param name="callingClass">The class that contains the reference to the resource.</param>
/// <param name="callingMember">The member that contains the reference to the resource.</param>
/// <param name="returnType">The type of the resource being referenced.</param>
/// <param name="resourceSetReference">The <see cref="ResourceSetReference"/> that describes the resource set being referenced.</param>
/// <param name="prefix">The prefix of the resource keys being referenced.</param>
public ResourcePrefixResolveResult(IClass callingClass, IMember callingMember, IReturnType returnType, ResourceSetReference resourceSetReference, string prefix)
: base(callingClass, callingMember, returnType, resourceSetReference, prefix)
{
}
public override string Key {
get { return null; }
}
public string Prefix {
get { return base.Key; }
}
public override ResolveResult Clone()
{
return new ResourcePrefixResolveResult(this.CallingClass, this.CallingMember, this.ResolvedType,
this.ResourceSetReference, this.Prefix);
}
}
} }

28
src/AddIns/Misc/ResourceToolkit/Test/CSharp/BclNRefactoryResourceResolverTests.cs

@ -11,6 +11,7 @@ using System.Collections.Generic;
using Hornung.ResourceToolkit; using Hornung.ResourceToolkit;
using Hornung.ResourceToolkit.Resolver; using Hornung.ResourceToolkit.Resolver;
using NUnit.Framework; using NUnit.Framework;
using NUnit.Framework.SyntaxHelpers;
namespace ResourceToolkit.Tests.CSharp namespace ResourceToolkit.Tests.CSharp
{ {
@ -262,6 +263,30 @@ class A
TestHelper.CheckReference(rrr, "Test.TestResources", "TestKey", "A", "A.B"); TestHelper.CheckReference(rrr, "Test.TestResources", "TestKey", "A", "A.B");
} }
// ********************************************************************************************************************************
const string CodeLocalCRMDeferredInitUsingApplyResources = @"using System.ComponentModel;
class A
{
void B()
{
ComponentResourceManager mgr;
mgr = new ComponentResourceManager(typeof(A));
mgr.ApplyResources(this, ""$this"");
}
}
";
[Test]
public void LocalCRMDeferredInitUsingApplyResources()
{
ResourceResolveResult rrr = Resolve(CodeLocalCRMDeferredInitUsingApplyResources, 8, 20, null);
TestHelper.CheckReference(rrr, "A", null, "A", "A.B");
Assert.That(rrr, Is.InstanceOfType(typeof(ResourcePrefixResolveResult)));
ResourcePrefixResolveResult rprr = (ResourcePrefixResolveResult)rrr;
Assert.That(rprr.Prefix, Is.EqualTo("$this"), "Resource key prefix not detected correctly.");
}
#endregion #endregion
// ******************************************************************************************************************************** // ********************************************************************************************************************************
@ -755,8 +780,9 @@ namespace Test {
Assert.Contains("GetString", patterns); Assert.Contains("GetString", patterns);
Assert.Contains("GetStream", patterns); Assert.Contains("GetStream", patterns);
Assert.Contains("GetObject", patterns); Assert.Contains("GetObject", patterns);
Assert.Contains("ApplyResources", patterns);
Assert.Contains("[", patterns); Assert.Contains("[", patterns);
Assert.AreEqual(4, patterns.Count, "Incorrect number of resource access patterns for C# files."); Assert.AreEqual(5, patterns.Count, "Incorrect number of resource access patterns for C# files.");
} }
[Test] [Test]

Loading…
Cancel
Save