diff options
author | Mike Krüger <mkrueger@novell.com> | 2011-02-09 13:10:01 +0300 |
---|---|---|
committer | Mike Krüger <mkrueger@novell.com> | 2011-02-09 13:13:07 +0300 |
commit | 9de9e7553a988d6ef4d5caf3b81c2d7a9edf4ab8 (patch) | |
tree | 3bd96ec4dd8e67d08e1649c07d2f2579707e28b6 /main/src | |
parent | 0e820cfb369f1de7a2c9bc149c16c135327307e0 (diff) |
Overworked find all references model. It's now per file (=mime type)
instead of per project.
Change was required for supporting references in files that are part
of the project but are embedded in another language - see 'Bug 663095
- Find References does not find method references in ASPX'.
Diffstat (limited to 'main/src')
6 files changed, 252 insertions, 2 deletions
diff --git a/main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml b/main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml index 6c463a6594..67e203a66b 100644 --- a/main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml +++ b/main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml @@ -139,7 +139,12 @@ <ExtensionNode name="Formatter" type="MonoDevelop.Ide.CodeFormatting.CodeFormatterExtensionNode" /> </ExtensionPoint> - <!-- Extensions --> + <ExtensionPoint path = "/MonoDevelop/Ide/ReferenceFinder" name = "Reference finders"> + <Description>Reference finder.</Description> + <ExtensionNode name="ReferenceFinder" type="MonoDevelop.Ide.FindInFiles.ReferenceFinderCodon"/> + </ExtensionPoint> + + <!-- Extensions --> <Extension path = "/MonoDevelop/Core/Applications"> <Application id = "gsetup" diff --git a/main/src/core/MonoDevelop.Ide/Makefile.am b/main/src/core/MonoDevelop.Ide/Makefile.am index 0c782e037a..508f76f6fb 100644 --- a/main/src/core/MonoDevelop.Ide/Makefile.am +++ b/main/src/core/MonoDevelop.Ide/Makefile.am @@ -377,6 +377,7 @@ FILES = \ MonoDevelop.Ide.FindInFiles/FindInFilesDialog.cs \ MonoDevelop.Ide.FindInFiles/FindReplace.cs \ MonoDevelop.Ide.FindInFiles/ISearchProgressMonitor.cs \ + MonoDevelop.Ide.FindInFiles/ReferencesFinder.cs \ MonoDevelop.Ide.FindInFiles/Scope.cs \ MonoDevelop.Ide.FindInFiles/SearchProgressMonitor.cs \ MonoDevelop.Ide.FindInFiles/SearchResult.cs \ diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeFormatting/DefaultCodeFormatter.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeFormatting/DefaultCodeFormatter.cs index 0f89c56c1c..151a9e1072 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeFormatting/DefaultCodeFormatter.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeFormatting/DefaultCodeFormatter.cs @@ -53,7 +53,7 @@ namespace MonoDevelop.Ide.CodeFormatting string eolMarker = currentPolicy.GetEolMarker (); var result = new StringBuilder (); - for (int i = startOffset; i <= endOffset; i++) { + for (int i = startOffset; i <= endOffset && i < input.Length; i++) { char ch = input[i]; switch (ch) { case '\t': diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.FindInFiles/ReferencesFinder.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.FindInFiles/ReferencesFinder.cs new file mode 100644 index 0000000000..f0a9c56dbc --- /dev/null +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.FindInFiles/ReferencesFinder.cs @@ -0,0 +1,230 @@ +// +// ReferenceFinder.cs +// +// Author: +// Mike Krüger <mkrueger@novell.com> +// +// Copyright (c) 2011 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using MonoDevelop.Projects.Dom; +using System.Collections.Generic; +using System.Linq; +using Mono.Addins; +using MonoDevelop.Core; +using MonoDevelop.Projects.Dom.Parser; +using MonoDevelop.Projects.CodeGeneration; +using MonoDevelop.Projects; + +namespace MonoDevelop.Ide.FindInFiles +{ + public abstract class ReferenceFinder + { + public bool IncludeDocumentation { + get; + set; + } + + static List<ReferenceFinderCodon> referenceFinderCodons = new List<ReferenceFinderCodon> (); + + static ReferenceFinder () + { + AddinManager.AddExtensionNodeHandler ("/MonoDevelop/Ide/ReferenceFinder", delegate(object sender, ExtensionNodeEventArgs args) { + var codon = (ReferenceFinderCodon)args.ExtensionNode; + switch (args.Change) { + case ExtensionChange.Add: + referenceFinderCodons.Add (codon); + break; + case ExtensionChange.Remove: + referenceFinderCodons.Remove (codon); + break; + } + }); + } + + public static ReferenceFinder GetReferenceFinder (string mimeType) + { + var codon = referenceFinderCodons.FirstOrDefault (c => c.SupportedMimeTypes.Any (mt => mt == mimeType)); + return codon != null ? codon.ReferenceFinder : null; + } + + public abstract IEnumerable<MemberReference> FindReferences (ProjectDom dom, FilePath fileName, INode member); + + + public static IEnumerable<MemberReference> FindReferences (INode member) + { + return FindReferences (IdeApp.ProjectOperations.CurrentSelectedSolution, member); + } + + public static IEnumerable<MemberReference> FindReferences (Solution solution, INode member) + { + var scope = GetScope (member); + ReferenceFinder finder; + ProjectDom dom = null; + ICompilationUnit unit = null; + IEnumerable<INode> searchNodes = new INode[] { member }; + if (member is LocalVariable) { + dom = ((LocalVariable)member).DeclaringMember.DeclaringType.SourceProjectDom; + unit = ((LocalVariable)member).CompilationUnit; + } else if (member is IParameter) { + dom = ((IParameter)member).DeclaringMember.DeclaringType.SourceProjectDom; + unit = ((IParameter)member).DeclaringMember.DeclaringType.CompilationUnit; + } else if (member is IType) { + dom = ((IType)member).SourceProjectDom; + unit = ((IType)member).CompilationUnit; + } else if (member is IMember) { + dom = ((IMember)member).DeclaringType.SourceProjectDom; + unit = ((IMember)member).DeclaringType.CompilationUnit; + searchNodes = CollectMembers (dom, (IMember)member); + } + + switch (scope) { + case RefactoryScope.File: + case RefactoryScope.DeclaringType: + if (dom == null || unit == null) + yield break; + finder = GetReferenceFinder (DesktopService.GetMimeTypeForUri (unit.FileName)); + if (finder == null) + yield break; + foreach (var searchNode in searchNodes) { + foreach (var foundReference in finder.FindReferences (dom, unit.FileName, searchNode)) { + yield return foundReference; + } + } + break; + case RefactoryScope.Project: + if (dom == null) + yield break; + foreach (var file in dom.Project.Files) { + finder = GetReferenceFinder (DesktopService.GetMimeTypeForUri (file.FilePath)); + if (finder == null) + continue; + foreach (var searchNode in searchNodes) { + foreach (var foundReference in finder.FindReferences (dom, file.FilePath, searchNode)) { + yield return foundReference; + } + } + } + break; + + case RefactoryScope.Solution: + foreach (var project in solution.GetAllProjects ()) { + var currentDom = ProjectDomService.GetProjectDom (project); + foreach (var file in project.Files) { + finder = GetReferenceFinder (DesktopService.GetMimeTypeForUri (file.FilePath)); + if (finder == null) + continue; + foreach (var searchNode in searchNodes) { + foreach (var foundReference in finder.FindReferences (currentDom, file.FilePath, searchNode)) { + yield return foundReference; + } + } + } + } + break; + } + } + + internal static IEnumerable<INode> CollectMembers (ProjectDom dom, IMember member) + { + if (member is IMethod && ((IMethod)member).IsConstructor) { + yield return member; + } else { + bool isOverrideable = member.DeclaringType.ClassType == ClassType.Interface || member.IsOverride || member.IsVirtual || member.IsAbstract; + bool isLastMember = false; + // for members we need to collect the whole 'class' of members (overloads & implementing types) + HashSet<string> alreadyVisitedTypes = new HashSet<string> (); + foreach (IType type in dom.GetInheritanceTree (member.DeclaringType)) { + if (type.ClassType == ClassType.Interface || isOverrideable || type.DecoratedFullName == member.DeclaringType.DecoratedFullName) { + // search in the class for the member + foreach (IMember interfaceMember in type.SearchMember (member.Name, true)) { + if (interfaceMember.MemberType == member.MemberType) + yield return interfaceMember; + } + + // now search in all subclasses of this class for the member + isLastMember = !member.IsOverride; + foreach (IType implementingType in dom.GetSubclasses (type)) { + string name = implementingType.DecoratedFullName; + if (alreadyVisitedTypes.Contains (name)) + continue; + alreadyVisitedTypes.Add (name); + foreach (IMember typeMember in implementingType.SearchMember (member.Name, true)) { + if (typeMember.MemberType == member.MemberType) { + isLastMember = type.ClassType != ClassType.Interface && (typeMember.IsVirtual || typeMember.IsAbstract || !typeMember.IsOverride); + yield return typeMember; + } + } + if (!isOverrideable) + break; + } + if (isLastMember) + break; + } + } + } + } + + static RefactoryScope GetScope (INode node) + { + IMember member = node as IMember; + if (member == null) + return RefactoryScope.DeclaringType; + + if (member.DeclaringType != null && member.DeclaringType.ClassType == ClassType.Interface) + return GetScope (member.DeclaringType); + + if (member.IsPublic) + return RefactoryScope.Solution; + + if (member.IsProtected || member.IsInternal || member.DeclaringType == null) + return RefactoryScope.Project; + return RefactoryScope.DeclaringType; + } + } + + [ExtensionNode (Description="A reference finder. The specified class needs to inherit from MonoDevelop.Projects.CodeGeneration.ReferenceFinder")] + internal class ReferenceFinderCodon : TypeExtensionNode + { + [NodeAttribute("supportedmimetypes", "Mime types supported by this binding (to be shown in the Open File dialog)")] + string[] supportedMimetypes; + + public string[] SupportedMimeTypes { + get { + return supportedMimetypes; + } + set { + supportedMimetypes = value; + } + } + + public ReferenceFinder ReferenceFinder { + get { + return (ReferenceFinder)GetInstance (); + } + } + + public override string ToString () + { + return string.Format ("[ReferenceFinderCodon: SupportedMimeTypes={0}, ReferenceFinder={1}]", SupportedMimeTypes.Count () + ":" + String.Join (";", SupportedMimeTypes), ReferenceFinder); + } + } +} diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj index 9d06e65ef6..b02fe951ad 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj @@ -1419,6 +1419,7 @@ <Compile Include="gtk-gui\MonoDevelop.Ide.Projects.NewPolicySetDialog.cs" /> <Compile Include="MonoDevelop.Components\HeaderBox.cs" /> <Compile Include="MonoDevelop.Ide.Extensions\StartupHandlerExtensionAttribute.cs" /> + <Compile Include="MonoDevelop.Ide.FindInFiles\ReferencesFinder.cs" /> </ItemGroup> <ItemGroup> <None Include="ChangeLog" /> diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/ProjectOperations.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/ProjectOperations.cs index df5113e000..b8ee4e93d4 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/ProjectOperations.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/ProjectOperations.cs @@ -1810,5 +1810,18 @@ namespace MonoDevelop.Ide return new ProviderProxy (data); } + public TextEditorData GetTextEditorData (FilePath filePath) + { + foreach (var doc in IdeApp.Workbench.Documents) { + if (doc.FileName == filePath) { + return doc.Editor; + } + } + + TextEditorData data = new TextEditorData (); + data.Document.FileName = filePath; + data.Text = File.ReadAllText (filePath); + return data; + } } } |