1 /*******************************************************************************
2 * Copyright (c) 2000, 2011 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.corext.refactoring;
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.Iterator;
18 import java.util.List;
22 import org.eclipse.core.runtime.CoreException;
23 import org.eclipse.core.runtime.IProgressMonitor;
25 import org.eclipse.core.resources.IResource;
27 import org.eclipse.ltk.core.refactoring.IRefactoringStatusEntryComparator;
28 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
29 import org.eclipse.ltk.core.refactoring.RefactoringStatusEntry;
31 import org.eclipse.jdt.core.ICompilationUnit;
32 import org.eclipse.jdt.core.IJavaElement;
33 import org.eclipse.jdt.core.JavaCore;
34 import org.eclipse.jdt.core.JavaModelException;
35 import org.eclipse.jdt.core.WorkingCopyOwner;
36 import org.eclipse.jdt.core.search.IJavaSearchScope;
37 import org.eclipse.jdt.core.search.SearchEngine;
38 import org.eclipse.jdt.core.search.SearchMatch;
39 import org.eclipse.jdt.core.search.SearchPattern;
40 import org.eclipse.jdt.core.search.SearchRequestor;
42 import org.eclipse.jdt.internal.corext.util.SearchUtils;
45 * Convenience wrapper for {@link SearchEngine} - performs searching and sorts the results by {@link IResource}.
46 * TODO: throw CoreExceptions from search(..) methods instead of wrapped JavaModelExceptions.
48 public class RefactoringSearchEngine {
50 private RefactoringSearchEngine(){
54 //TODO: throw CoreException
55 public static ICompilationUnit[] findAffectedCompilationUnits(SearchPattern pattern,
56 IJavaSearchScope scope, final IProgressMonitor pm, RefactoringStatus status, final boolean tolerateInAccurateMatches) throws JavaModelException {
58 boolean hasNonCuMatches= false;
60 class ResourceSearchRequestor extends SearchRequestor{
61 boolean hasPotentialMatches= false ;
62 Set<IResource> resources= new HashSet<IResource>(5);
63 private IResource fLastResource;
66 public void acceptSearchMatch(SearchMatch match) {
67 if (!tolerateInAccurateMatches && match.getAccuracy() == SearchMatch.A_INACCURATE) {
68 hasPotentialMatches= true;
70 if (fLastResource != match.getResource()) {
71 fLastResource= match.getResource();
72 resources.add(fLastResource);
76 ResourceSearchRequestor requestor = new ResourceSearchRequestor();
78 new SearchEngine().search(pattern, SearchUtils.getDefaultSearchParticipants(), scope, requestor, pm);
79 } catch (CoreException e) {
80 throw new JavaModelException(e);
83 List<IJavaElement> result= new ArrayList<IJavaElement>(requestor.resources.size());
84 for (Iterator<IResource> iter= requestor.resources.iterator(); iter.hasNext(); ) {
85 IResource resource= iter.next();
86 IJavaElement element= JavaCore.create(resource);
87 if (element instanceof ICompilationUnit) {
90 hasNonCuMatches= true;
93 addStatusErrors(status, requestor.hasPotentialMatches, hasNonCuMatches);
94 return result.toArray(new ICompilationUnit[result.size()]);
97 //TODO: throw CoreException
98 public static ICompilationUnit[] findAffectedCompilationUnits(SearchPattern pattern,
99 IJavaSearchScope scope, final IProgressMonitor pm, RefactoringStatus status) throws JavaModelException {
100 return findAffectedCompilationUnits(pattern, scope, pm, status, false);
104 * Performs a search and groups the resulting {@link SearchMatch}es by
105 * {@link SearchResultGroup#getCompilationUnit()}.
106 * @param pattern the search pattern
107 * @param scope the search scope
108 * @param monitor the progress monitor
109 * @param status an error is added here if inaccurate or non-cu matches have been found
110 * @return a {@link SearchResultGroup}[], where each {@link SearchResultGroup}
111 * has a different {@link SearchMatch#getResource() getResource()}s.
113 * @throws JavaModelException when the search failed
115 //TODO: throw CoreException
116 public static SearchResultGroup[] search(SearchPattern pattern, IJavaSearchScope scope, IProgressMonitor monitor, RefactoringStatus status)
117 throws JavaModelException {
118 return internalSearch(new SearchEngine(), pattern, scope, new CollectingSearchRequestor(), monitor, status);
121 //TODO: throw CoreException
122 public static SearchResultGroup[] search(SearchPattern pattern, WorkingCopyOwner owner, IJavaSearchScope scope, IProgressMonitor monitor, RefactoringStatus status)
123 throws JavaModelException {
124 return internalSearch(owner != null ? new SearchEngine(owner) : new SearchEngine(), pattern, scope, new CollectingSearchRequestor(), monitor, status);
127 //TODO: throw CoreException
128 public static SearchResultGroup[] search(SearchPattern pattern, IJavaSearchScope scope, CollectingSearchRequestor requestor,
129 IProgressMonitor monitor, RefactoringStatus status) throws JavaModelException {
130 return internalSearch(new SearchEngine(), pattern, scope, requestor, monitor, status);
133 //TODO: throw CoreException
134 public static SearchResultGroup[] search(SearchPattern pattern, WorkingCopyOwner owner, IJavaSearchScope scope,
135 CollectingSearchRequestor requestor, IProgressMonitor monitor, RefactoringStatus status) throws JavaModelException {
136 return internalSearch(owner != null ? new SearchEngine(owner) : new SearchEngine(), pattern, scope, requestor, monitor, status);
139 //TODO: throw CoreException
140 private static SearchResultGroup[] internalSearch(SearchEngine searchEngine, SearchPattern pattern, IJavaSearchScope scope,
141 CollectingSearchRequestor requestor, IProgressMonitor monitor, RefactoringStatus status) throws JavaModelException {
143 searchEngine.search(pattern, SearchUtils.getDefaultSearchParticipants(), scope, requestor, monitor);
144 } catch (CoreException e) {
145 throw new JavaModelException(e);
147 return groupByCu(requestor.getResults(), status);
150 public static SearchResultGroup[] groupByCu(SearchMatch[] matches, RefactoringStatus status) {
151 return groupByCu(Arrays.asList(matches), status);
155 * @param matchList a List of SearchMatch
156 * @param status the status to report errors.
157 * @return a SearchResultGroup[], grouped by SearchMatch#getResource()
159 public static SearchResultGroup[] groupByCu(List<SearchMatch> matchList, RefactoringStatus status) {
160 Map<IResource, List<SearchMatch>> grouped= new HashMap<IResource, List<SearchMatch>>();
161 boolean hasPotentialMatches= false;
162 boolean hasNonCuMatches= false;
164 for (Iterator<SearchMatch> iter= matchList.iterator(); iter.hasNext();) {
165 SearchMatch searchMatch= iter.next();
166 if (searchMatch.getAccuracy() == SearchMatch.A_INACCURATE)
167 hasPotentialMatches= true;
168 if (! grouped.containsKey(searchMatch.getResource()))
169 grouped.put(searchMatch.getResource(), new ArrayList<SearchMatch>(1));
170 grouped.get(searchMatch.getResource()).add(searchMatch);
173 for (Iterator<IResource> iter= grouped.keySet().iterator(); iter.hasNext();) {
174 IResource resource= iter.next();
175 IJavaElement element= JavaCore.create(resource);
176 if (! (element instanceof ICompilationUnit)) {
178 hasNonCuMatches= true;
182 SearchResultGroup[] result= new SearchResultGroup[grouped.keySet().size()];
184 for (Iterator<IResource> iter= grouped.keySet().iterator(); iter.hasNext();) {
185 IResource resource= iter.next();
186 List<SearchMatch> searchMatches= grouped.get(resource);
187 SearchMatch[] matchArray= searchMatches.toArray(new SearchMatch[searchMatches.size()]);
188 result[i]= new SearchResultGroup(resource, matchArray);
191 addStatusErrors(status, hasPotentialMatches, hasNonCuMatches);
195 public static SearchPattern createOrPattern(IJavaElement[] elements, int limitTo) {
196 if (elements == null || elements.length == 0)
198 Set<IJavaElement> set= new HashSet<IJavaElement>(Arrays.asList(elements));
199 Iterator<IJavaElement> iter= set.iterator();
200 IJavaElement first= iter.next();
201 SearchPattern pattern= SearchPattern.createPattern(first, limitTo, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE);
202 if (pattern == null) // check for bug 90138
203 throw new IllegalArgumentException("Invalid java element: " + first.getHandleIdentifier() + "\n" + first.toString()); //$NON-NLS-1$ //$NON-NLS-2$
204 while(iter.hasNext()){
205 IJavaElement each= iter.next();
206 SearchPattern nextPattern= SearchPattern.createPattern(each, limitTo, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE);
207 if (nextPattern == null) // check for bug 90138
208 throw new IllegalArgumentException("Invalid java element: " + each.getHandleIdentifier() + "\n" + each.toString()); //$NON-NLS-1$ //$NON-NLS-2$
209 pattern= SearchPattern.createOrPattern(pattern, nextPattern);
214 private static boolean containsStatusEntry(final RefactoringStatus status, final RefactoringStatusEntry other) {
215 return status.getEntries(new IRefactoringStatusEntryComparator() {
216 public final int compare(final RefactoringStatusEntry entry1, final RefactoringStatusEntry entry2) {
217 return entry1.getMessage().compareTo(entry2.getMessage());
219 }, other).length > 0;
222 private static void addStatusErrors(RefactoringStatus status, boolean hasPotentialMatches, boolean hasNonCuMatches) {
223 if (hasPotentialMatches) {
224 final RefactoringStatusEntry entry= new RefactoringStatusEntry(RefactoringStatus.ERROR, RefactoringCoreMessages.RefactoringSearchEngine_potential_matches);
225 if (!containsStatusEntry(status, entry))
226 status.addEntry(entry);
228 if (hasNonCuMatches) {
229 final RefactoringStatusEntry entry= new RefactoringStatusEntry(RefactoringStatus.ERROR, RefactoringCoreMessages.RefactoringSearchEngine_non_cu_matches);
230 if (!containsStatusEntry(status, entry))
231 status.addEntry(entry);