Browse Source

ResourceToolkit: The scope for the "Find missing resource keys" operation can now be selected from one of "whole solution", "current project", "current file" and "all open files". Added some debugging code. Converted project to .NET 3.5.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@3252 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Christian Hornung 17 years ago
parent
commit
70f9463da3
  1. 41
      src/AddIns/Misc/ResourceToolkit/Project/Hornung.ResourceToolkit.addin
  2. 11
      src/AddIns/Misc/ResourceToolkit/Project/ResourceToolkit.csproj
  3. 54
      src/AddIns/Misc/ResourceToolkit/Project/Src/Commands/RefactoringCommands.cs
  4. 129
      src/AddIns/Misc/ResourceToolkit/Project/Src/Refactoring/ResourceRefactoringService.cs
  5. 27
      src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/BclNRefactoryResourceResolver.cs
  6. 13
      src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/PositionTrackingAstVisitor.cs

41
src/AddIns/Misc/ResourceToolkit/Project/Hornung.ResourceToolkit.addin

@ -1,7 +1,6 @@ @@ -1,7 +1,6 @@
<AddIn name = "Hornung.ResourceToolkit"
author = "Christian Hornung"
copyright = "2006 Christian Hornung"
url = "http://dev.hornung.dynalias.com/index.php?p=restk_home"
copyright = "2006-2008 Christian Hornung"
description = "Provides tooltips and code completion for resource entries to simplify working with localizable resources using the standard .NET framework classes or ICSharpCode.Core.">
<Manifest>
@ -52,21 +51,39 @@ @@ -52,21 +51,39 @@
<Path name="/Workspace/Tools">
<MenuItem id="ResourceToolkit" label="${res:Hornung.ResourceToolkit.ToolsMenuLabel}" type="Menu">
<ComplexCondition action="Disable">
<Or>
<Condition name="SolutionOpen"/>
<Condition name="WindowOpen" openwindow="ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor.ITextEditorControlProvider"/>
</Or>
<MenuItem id="FindMissingResourceKeys" label="${res:Hornung.ResourceToolkit.FindMissingResourceKeys}" type="Menu">
<MenuItem id = "FindMissingResourceKeys"
label = "${res:Hornung.ResourceToolkit.FindMissingResourceKeys}"
class = "Hornung.ResourceToolkit.Commands.FindMissingResourceKeysCommand" />
<Condition name="SolutionOpen" action="Disable">
<MenuItem id = "FindMissingResourceKeysWholeSolution"
label = "${res:Dialog.NewProject.SearchReplace.LookIn.WholeSolution}"
class = "Hornung.ResourceToolkit.Commands.FindMissingResourceKeysWholeSolutionCommand" />
</Condition>
<Condition name="ProjectActive" activeproject="*" action="Disable">
<MenuItem id = "FindMissingResourceKeysCurrentProject"
label = "${res:Dialog.NewProject.SearchReplace.LookIn.WholeProject}"
class = "Hornung.ResourceToolkit.Commands.FindMissingResourceKeysCurrentProjectCommand" />
</Condition>
<Condition name="WindowOpen" openwindow="*" action="Disable">
<MenuItem id = "FindMissingResourceKeysOpenFiles"
label = "${res:Dialog.NewProject.SearchReplace.LookIn.AllOpenDocuments}"
class = "Hornung.ResourceToolkit.Commands.FindMissingResourceKeysOpenFilesCommand" />
</Condition>
<Condition name="WindowActive" activewindow="*" action="Disable">
<MenuItem id = "FindMissingResourceKeysCurrentFile"
label = "${res:Dialog.NewProject.SearchReplace.LookIn.CurrentDocument}"
class = "Hornung.ResourceToolkit.Commands.FindMissingResourceKeysCurrentFileCommand" />
</Condition>
</MenuItem>
<Condition name="SolutionOpen" action="Disable">
<MenuItem id = "FindUnusedResourceKeys"
label = "${res:Hornung.ResourceToolkit.FindUnusedResourceKeys}"
class = "Hornung.ResourceToolkit.Commands.FindUnusedResourceKeysCommand" />
</ComplexCondition>
</Condition>
</MenuItem>
</Path>

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

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<OutputType>Library</OutputType>
<RootNamespace>Hornung.ResourceToolkit</RootNamespace>
@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<RunCodeAnalysis>False</RunCodeAnalysis>
<CodeAnalysisRules>-Microsoft.Design#CA1020</CodeAnalysisRules>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<BaseIntermediateOutputPath>obj\</BaseIntermediateOutputPath>
@ -39,9 +40,15 @@ @@ -39,9 +40,15 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Drawing" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Src\CodeCompletion\AbstractNRefactoryResourceCodeCompletionBinding.cs" />
@ -140,4 +147,4 @@ @@ -140,4 +147,4 @@
<Folder Include="Src\Conditions" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project>
</Project>

54
src/AddIns/Misc/ResourceToolkit/Project/Src/Commands/RefactoringCommands.cs

@ -18,22 +18,62 @@ using SearchAndReplace; @@ -18,22 +18,62 @@ using SearchAndReplace;
namespace Hornung.ResourceToolkit.Commands
{
/// <summary>
/// Find missing resource keys in the whole solution.
/// </summary>
public class FindMissingResourceKeysCommand : AbstractMenuCommand
public static class FindMissingResourceKeysHelper
{
public override void Run()
{
public static void Run(SearchScope scope) {
// Allow the menu to close
Application.DoEvents();
using(AsynchronousWaitDialog monitor = AsynchronousWaitDialog.ShowWaitDialog("${res:Hornung.ResourceToolkit.FindMissingResourceKeys}")) {
FindReferencesAndRenameHelper.ShowAsSearchResults(StringParser.Parse("${res:Hornung.ResourceToolkit.ReferencesToMissingKeys}"),
ResourceRefactoringService.FindReferencesToMissingKeys(monitor));
ResourceRefactoringService.FindReferencesToMissingKeys(monitor, scope));
}
}
}
/// <summary>
/// Find missing resource keys in the whole solution.
/// </summary>
public class FindMissingResourceKeysWholeSolutionCommand : AbstractMenuCommand
{
public override void Run()
{
FindMissingResourceKeysHelper.Run(SearchScope.WholeSolution);
}
}
/// <summary>
/// Find missing resource keys in the current project.
/// </summary>
public class FindMissingResourceKeysCurrentProjectCommand : AbstractMenuCommand
{
public override void Run()
{
FindMissingResourceKeysHelper.Run(SearchScope.CurrentProject);
}
}
/// <summary>
/// Find missing resource keys in the current file.
/// </summary>
public class FindMissingResourceKeysCurrentFileCommand : AbstractMenuCommand
{
public override void Run()
{
FindMissingResourceKeysHelper.Run(SearchScope.CurrentFile);
}
}
/// <summary>
/// Find missing resource keys in all open files.
/// </summary>
public class FindMissingResourceKeysOpenFilesCommand : AbstractMenuCommand
{
public override void Run()
{
FindMissingResourceKeysHelper.Run(SearchScope.OpenFiles);
}
}
/// <summary>
/// Find unused resource keys in the whole solution.
/// </summary>

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

@ -9,6 +9,7 @@ using System; @@ -9,6 +9,7 @@ using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using Hornung.ResourceToolkit.Resolver;
using Hornung.ResourceToolkit.ResourceFileContent;
@ -39,7 +40,7 @@ namespace Hornung.ResourceToolkit.Refactoring @@ -39,7 +40,7 @@ namespace Hornung.ResourceToolkit.Refactoring
/// <returns>A list of references to this resource.</returns>
public static List<Reference> FindReferences(string resourceFileName, string key, IProgressMonitor monitor)
{
return FindReferences(new SpecificResourceReferenceFinder(resourceFileName, key), monitor);
return FindReferences(new SpecificResourceReferenceFinder(resourceFileName, key), monitor, SearchScope.WholeSolution);
}
/// <summary>
@ -48,8 +49,9 @@ namespace Hornung.ResourceToolkit.Refactoring @@ -48,8 +49,9 @@ namespace Hornung.ResourceToolkit.Refactoring
/// </summary>
/// <param name="finder">The <see cref="IResourceReferenceFinder"/> to use to find resource references.</param>
/// <param name="monitor">An object implementing <see cref="IProgressMonitor"/> to report the progress of the operation. Can be <c>null</c>.</param>
/// <param name="scope">The scope which should be searched.</param>
/// <returns>A list of references to resources.</returns>
public static List<Reference> FindReferences(IResourceReferenceFinder finder, IProgressMonitor monitor)
public static List<Reference> FindReferences(IResourceReferenceFinder finder, IProgressMonitor monitor, SearchScope scope)
{
if (finder == null) {
throw new ArgumentNullException("finder");
@ -70,7 +72,7 @@ namespace Hornung.ResourceToolkit.Refactoring @@ -70,7 +72,7 @@ namespace Hornung.ResourceToolkit.Refactoring
NRefactoryAstCacheService.EnableCache();
ICollection<string> files = GetPossibleFiles();
ICollection<string> files = GetPossibleFiles(scope);
if (monitor != null) {
monitor.BeginTask("${res:SharpDevelop.Refactoring.FindingReferences}", files.Count, true);
@ -151,20 +153,22 @@ namespace Hornung.ResourceToolkit.Refactoring @@ -151,20 +153,22 @@ namespace Hornung.ResourceToolkit.Refactoring
/// Finds all references to resources (except the definitions).
/// </summary>
/// <param name="monitor">An object implementing <see cref="IProgressMonitor"/> to report the progress of the operation. Can be <c>null</c>.</param>
/// <param name="scope">The scope which should be searched.</param>
/// <returns>A list of references to resources.</returns>
public static List<Reference> FindAllReferences(IProgressMonitor monitor)
public static List<Reference> FindAllReferences(IProgressMonitor monitor, SearchScope scope)
{
return FindReferences(new AnyResourceReferenceFinder(), monitor);
return FindReferences(new AnyResourceReferenceFinder(), monitor, scope);
}
/// <summary>
/// Finds all references to missing resource keys.
/// </summary>
/// <param name="monitor">An object implementing <see cref="IProgressMonitor"/> to report the progress of the operation. Can be <c>null</c>.</param>
/// <param name="scope">The scope which should be searched.</param>
/// <returns>A list of all references to missing resource keys.</returns>
public static List<Reference> FindReferencesToMissingKeys(IProgressMonitor monitor)
public static List<Reference> FindReferencesToMissingKeys(IProgressMonitor monitor, SearchScope scope)
{
List<Reference> references = FindAllReferences(monitor);
List<Reference> references = FindAllReferences(monitor, scope);
if (references == null) {
return null;
}
@ -197,7 +201,7 @@ namespace Hornung.ResourceToolkit.Refactoring @@ -197,7 +201,7 @@ namespace Hornung.ResourceToolkit.Refactoring
/// <returns>A collection of <see cref="ResourceItem"/> classes that represent the unused resource keys.</returns>
public static ICollection<ResourceItem> FindUnusedKeys(IProgressMonitor monitor)
{
List<Reference> references = FindAllReferences(monitor);
List<Reference> references = FindAllReferences(monitor, SearchScope.WholeSolution);
if (references == null) {
return null;
}
@ -319,53 +323,86 @@ namespace Hornung.ResourceToolkit.Refactoring @@ -319,53 +323,86 @@ namespace Hornung.ResourceToolkit.Refactoring
/// Gets a list of names of files which can possibly contain resource references.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
public static ICollection<string> GetPossibleFiles()
public static ICollection<string> GetPossibleFiles(SearchScope scope)
{
List<string> files = new List<string>();
if (ProjectService.OpenSolution == null) {
foreach (IViewContent vc in WorkbenchSingleton.Workbench.ViewContentCollection) {
string name = vc.PrimaryFileName;
if (IsPossibleFile(name)) {
files.Add(name);
switch(scope) {
case SearchScope.WholeSolution:
Solution s = ProjectService.OpenSolution;
if (s == null) {
throw new InvalidOperationException("Cannot search in whole solution when no solution is open.");
}
}
} else {
foreach (IProject p in ProjectService.OpenSolution.Projects) {
foreach (ProjectItem pi in p.Items) {
if (pi is FileProjectItem) {
string name = pi.FileName;
if (IsPossibleFile(name)) {
files.Add(name);
// Add the file to the project dictionary here.
// This saves the lookup time when the corresponding project
// is needed later.
ProjectFileDictionaryService.AddFile(name, p);
}
}
AddFilesFromSolution(files, s);
break;
case SearchScope.CurrentProject:
IProject p = ProjectService.CurrentProject;
if (p == null) {
throw new InvalidOperationException("Cannot search in current project when no project is active.");
}
}
AddFilesFromProject(files, p);
break;
case SearchScope.CurrentFile:
IViewContent vc = WorkbenchSingleton.Workbench.ActiveViewContent;
if (vc == null) {
throw new InvalidOperationException("Cannot search in current file when no file is open.");
}
AddFilesFromViewContent(files, vc);
break;
case SearchScope.OpenFiles:
foreach (IViewContent v in WorkbenchSingleton.Workbench.ViewContentCollection) {
AddFilesFromViewContent(files, v);
}
break;
default:
throw new ArgumentOutOfRangeException("scope", "The scope parameter is not set to one of the SearchScope values.");
}
return files.AsReadOnly();
}
static void AddFilesFromSolution(IList<string> files, Solution s)
{
foreach (IProject p in s.Projects) {
AddFilesFromProject(files, p);
}
}
static void AddFilesFromProject(IList<string> files, IProject p)
{
foreach (ProjectItem pi in p.Items) {
if (pi is FileProjectItem) {
string name = pi.FileName;
if (IsPossibleFile(name)) {
files.Add(name);
// Add the file to the project dictionary here.
// This saves the lookup time when the corresponding project
// is needed later.
ProjectFileDictionaryService.AddFile(name, p);
}
}
}
}
static void AddFilesFromViewContent(IList<string> files, IViewContent vc)
{
files.AddRange(vc.Files
.Select(f => f.FileName)
.Where(name => name != null && IsPossibleFile(name))
);
}
/// <summary>
/// Determines whether the specified file could possibly contain resource references
/// that can be detected by at least one registered resource resolver.
/// </summary>
public static bool IsPossibleFile(string name)
{
foreach (IResourceResolver resolver in ResourceResolverService.Resolvers) {
if (resolver.SupportsFile(name)) {
return true;
}
}
return false;
return ResourceResolverService.Resolvers.Any(resolver => resolver.SupportsFile(name));
}
// ********************************************************************************************************************************
@ -405,4 +442,18 @@ namespace Hornung.ResourceToolkit.Refactoring @@ -405,4 +442,18 @@ namespace Hornung.ResourceToolkit.Refactoring
return -1;
}
}
/// <summary>
/// Determines a search scope for finding references to resources.
/// </summary>
public enum SearchScope {
/// <summary>Search the whole solution.</summary>
WholeSolution,
/// <summary>Search the current project.</summary>
CurrentProject,
/// <summary>Search the current file (in the active view content).</summary>
CurrentFile,
/// <summary>Search all currently open files (all open view contents).</summary>
OpenFiles
}
}

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

@ -193,8 +193,8 @@ namespace Hornung.ResourceToolkit.Resolver @@ -193,8 +193,8 @@ namespace Hornung.ResourceToolkit.Resolver
/// <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
/// 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)
@ -569,6 +569,10 @@ namespace Hornung.ResourceToolkit.Resolver @@ -569,6 +569,10 @@ namespace Hornung.ResourceToolkit.Resolver
mrr.ResolvedMember.DeclaringType.IsTypeInInheritanceTree(this.resourceManagerMember.ReturnType.GetUnderlyingClass()))
) {
#if DEBUG
LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver: This is the correct constructor.");
#endif
// This most probably is the resource manager initialization we are looking for.
// Find a parameter that indicates the resources being referenced.
@ -600,7 +604,23 @@ namespace Hornung.ResourceToolkit.Resolver @@ -600,7 +604,23 @@ 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.DeclaringType.CompilationUnit.FileName) as TypeResolveResult;
#if DEBUG
LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver: Found TypeOfExpression in constructor call: " + t.ToString());
#endif
ResolveResult rr = this.Resolve(new TypeReferenceExpression(t.TypeReference), this.resourceManagerMember.DeclaringType.CompilationUnit.FileName, ExpressionContext.Type);
#if DEBUG
if (rr == null) {
LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver: The TypeReference of the TypeOfExpression could not be resolved.");
} else {
LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver: The TypeReference resolved to: " + rr.ToString());
}
#endif
TypeResolveResult trr = rr as TypeResolveResult;
if (trr != null) {
#if DEBUG
@ -617,6 +637,7 @@ namespace Hornung.ResourceToolkit.Resolver @@ -617,6 +637,7 @@ namespace Hornung.ResourceToolkit.Resolver
break;
}
}
}

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

@ -95,6 +95,17 @@ namespace Hornung.ResourceToolkit.Resolver @@ -95,6 +95,17 @@ namespace Hornung.ResourceToolkit.Resolver
/// <param name="expression">The expression to be resolved.</param>
/// <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)
{
return this.Resolve(expression, fileName, ExpressionContext.Default);
}
/// <summary>
/// Resolves an expression in the current node's context.
/// </summary>
/// <param name="expression">The expression to be resolved.</param>
/// <param name="fileName">The file name of the source file that contains the expression to be resolved.</param>
/// <param name="context">The ExpressionContext.</param>
public ResolveResult Resolve(Expression expression, string fileName, ExpressionContext context)
{
if (!this.PositionAvailable) {
LoggingService.Info("ResourceToolkit: PositionTrackingAstVisitor: Resolve failed due to position information being unavailable. Expression: "+expression.ToString());
@ -105,7 +116,7 @@ namespace Hornung.ResourceToolkit.Resolver @@ -105,7 +116,7 @@ namespace Hornung.ResourceToolkit.Resolver
LoggingService.Debug("ResourceToolkit: PositionTrackingAstVisitor: Using this parent node for resolve: "+this.parentNodes.Peek().ToString());
#endif
return NRefactoryAstCacheService.ResolveLowLevel(fileName, this.CurrentNodeStartLocation.Y, this.CurrentNodeStartLocation.X+1, this.compilationUnit, null, expression, ExpressionContext.Default);
return NRefactoryAstCacheService.ResolveLowLevel(fileName, this.CurrentNodeStartLocation.Y, this.CurrentNodeStartLocation.X+1, this.compilationUnit, null, expression, context);
}
// ********************************************************************************************************************************

Loading…
Cancel
Save