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 17 years ago
parent
commit
69b69f77bb
  1. 50
      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

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

@ -109,26 +109,32 @@ namespace Hornung.ResourceToolkit.Refactoring @@ -109,26 +109,32 @@ namespace Hornung.ResourceToolkit.Refactoring
TextLocation docPos = doc.OffsetToPosition(pos);
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)) {
// The actual location of the key string may be after 'pos' because
// 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 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;
if (rrr.Key != null) {
// The actual location of the key string may be after 'pos' because
// 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 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));
}
} 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 @@ -216,15 +222,22 @@ namespace Hornung.ResourceToolkit.Refactoring
// Generate a dictonary of resource file names and the
// corresponding referenced keys.
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) {
ResourceResolveResult rrr = (ResourceResolveResult)reference.ResolveResult;
if (rrr.ResourceFileContent != null) {
string fileName = rrr.FileName;
if (!referencedKeys.ContainsKey(fileName)) {
referencedKeys.Add(fileName, new List<string>());
referencedPrefixes.Add(fileName, new List<string>());
}
if (rrr.Key != null && !referencedKeys[fileName].Contains(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 {
if (monitor != null) monitor.ShowingDialog = true;
@ -239,7 +252,8 @@ namespace Hornung.ResourceToolkit.Refactoring @@ -239,7 +252,8 @@ namespace Hornung.ResourceToolkit.Refactoring
LoggingService.Debug("ResourceToolkit: FindUnusedKeys: Referenced resource file '"+fileName+"'");
#endif
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));
}
}

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

@ -65,7 +65,7 @@ namespace Hornung.ResourceToolkit.Refactoring @@ -65,7 +65,7 @@ namespace Hornung.ResourceToolkit.Refactoring
public bool IsReferenceToResource(ResourceResolveResult result)
{
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 @@ -45,6 +45,7 @@ namespace Hornung.ResourceToolkit.Resolver
*
* Something.GetString(
* Something.GetString("...")
* Something.ApplyResources(obj, "...")
* Something[
* Something["..."]
*
@ -65,7 +66,7 @@ namespace Hornung.ResourceToolkit.Resolver @@ -65,7 +66,7 @@ namespace Hornung.ResourceToolkit.Resolver
MethodGroupResolveResult methrr = resolveResult as MethodGroupResolveResult;
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) {
return ResolveResource(resolveResult, expr);
@ -98,7 +99,7 @@ namespace Hornung.ResourceToolkit.Resolver @@ -98,7 +99,7 @@ namespace Hornung.ResourceToolkit.Resolver
if (mrr != null) {
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("...")
// This is a MemberResolveResult and we need the reference to "Something".
@ -216,10 +217,14 @@ namespace Hornung.ResourceToolkit.Resolver @@ -216,10 +217,14 @@ namespace Hornung.ResourceToolkit.Resolver
}
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).
return new ResourceResolveResult(resolveResult.CallingClass, resolveResult.CallingMember, null, rsr, key);
if (isPrefixOnly) {
return new ResourcePrefixResolveResult(resolveResult.CallingClass, resolveResult.CallingMember, null, rsr, key);
} else {
return new ResourceResolveResult(resolveResult.CallingClass, resolveResult.CallingMember, null, rsr, key);
}
}
return null;
@ -683,8 +688,9 @@ namespace Hornung.ResourceToolkit.Resolver @@ -683,8 +688,9 @@ namespace Hornung.ResourceToolkit.Resolver
/// <summary>
/// Tries to infer the resource key being referenced from the given expression.
/// </summary>
static string GetKeyFromExpression(Expression expr)
static string GetKeyFromExpression(Expression expr, out bool isPrefixOnly)
{
isPrefixOnly = false;
#if DEBUG
LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver trying to get key from expression: "+expr.ToString());
#endif
@ -722,6 +728,20 @@ namespace Hornung.ResourceToolkit.Resolver @@ -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 @@ -743,6 +763,7 @@ namespace Hornung.ResourceToolkit.Resolver
"GetString",
"GetObject",
"GetStream",
"ApplyResources",
(NRefactoryResourceResolver.GetLanguagePropertiesForFile(fileName) ?? LanguageProperties.None).IndexerExpressionStartToken
};
}

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

@ -17,8 +17,8 @@ namespace Hornung.ResourceToolkit.Resolver @@ -17,8 +17,8 @@ namespace Hornung.ResourceToolkit.Resolver
public class ResourceResolveResult : ResolveResult
{
ResourceSetReference resourceSetReference;
string key;
readonly ResourceSetReference resourceSetReference;
readonly string key;
/// <summary>
/// Gets the <see cref="ResourceSetReference"/> that describes the resource set being referenced.
@ -44,7 +44,7 @@ namespace Hornung.ResourceToolkit.Resolver @@ -44,7 +44,7 @@ namespace Hornung.ResourceToolkit.Resolver
/// <summary>
/// Gets the resource key being referenced. May be null if the key is unknown/not yet typed.
/// </summary>
public string Key {
public virtual string Key {
get { return this.key; }
}
@ -90,4 +90,37 @@ namespace Hornung.ResourceToolkit.Resolver @@ -90,4 +90,37 @@ namespace Hornung.ResourceToolkit.Resolver
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; @@ -11,6 +11,7 @@ using System.Collections.Generic;
using Hornung.ResourceToolkit;
using Hornung.ResourceToolkit.Resolver;
using NUnit.Framework;
using NUnit.Framework.SyntaxHelpers;
namespace ResourceToolkit.Tests.CSharp
{
@ -262,6 +263,30 @@ class A @@ -262,6 +263,30 @@ class A
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
// ********************************************************************************************************************************
@ -755,8 +780,9 @@ namespace Test { @@ -755,8 +780,9 @@ namespace Test {
Assert.Contains("GetString", patterns);
Assert.Contains("GetStream", patterns);
Assert.Contains("GetObject", patterns);
Assert.Contains("ApplyResources", 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]

Loading…
Cancel
Save