/*
* Copyright 2009-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.groovy.eclipse.refactoring.actions;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.codehaus.groovy.eclipse.core.GroovyCore;
import org.codehaus.jdt.groovy.model.GroovyCompilationUnit;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.TypeNameMatch;
import org.eclipse.jdt.internal.corext.util.TypeNameMatchCollector;
public class TypeSearch {
/**
* From {@link OrganizeImportsOperation.TypeReferenceProcessor.UnresolvedTypeData}
*/
public static class UnresolvedTypeData {
final String ref;
final boolean isAnnotation;
final ISourceRange range;
final List<TypeNameMatch> foundInfos = new LinkedList<TypeNameMatch>();
public UnresolvedTypeData(String ref, boolean annotation, ISourceRange range) {
this.ref = ref;
this.isAnnotation = annotation;
this.range = range;
}
public void addInfo(TypeNameMatch info) {
for (int i = foundInfos.size() - 1; i >= 0; i -= 1) {
TypeNameMatch curr= foundInfos.get(i);
if (curr.getTypeContainerName().equals(info.getTypeContainerName())) {
return; // not added; already contains type with same name
}
}
foundInfos.add(info);
}
public List<TypeNameMatch> getFoundInfos() {
return foundInfos;
}
}
/**
* Use a SearchEngine to look for the types.
* <p>
* NOTE: This will not find inner types.
*
* @see OrganizeImportsOperation.TypeReferenceProcessor#process(org.eclipse.core.runtime.IProgressMonitor)
*/
public void searchForTypes(GroovyCompilationUnit unit, Map<String, UnresolvedTypeData> missingTypes, IProgressMonitor monitor) throws JavaModelException, OperationCanceledException {
char[][] allTypes = new char[missingTypes.size()][];
int i = 0;
for (String simpleName : missingTypes.keySet()) {
allTypes[i++] = simpleName.toCharArray();
}
final List<TypeNameMatch> typesFound = new ArrayList<TypeNameMatch>();
TypeNameMatchCollector collector = new TypeNameMatchCollector(typesFound);
IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] {unit.getJavaProject()});
int policy = (monitor == null ? IJavaSearchConstants.CANCEL_IF_NOT_READY_TO_SEARCH : IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH);
new SearchEngine().searchAllTypeNames(null, allTypes, scope, collector, policy, monitor);
for (TypeNameMatch match : typesFound) {
UnresolvedTypeData data = missingTypes.get(match.getSimpleTypeName());
if (data == null) {
GroovyCore.logException("GRECLIPSE-735: Match not found in missing types: " + match.getFullyQualifiedName(), new Exception());
continue;
}
if (isOfKind(match, data.isAnnotation)) {
data.addInfo(match);
}
}
}
/**
* If looking for an annotation, then filter out non-annoations, otherwise everything is acceptable.
*/
protected boolean isOfKind(TypeNameMatch match, boolean isAnnotation) {
boolean isRegularAnnotation = isAnnotation ? Flags.isAnnotation(match.getModifiers()) : true;
// annotations that are annotated with {@link AnnotationCollector} are not treated as annotations, so additional check is required
boolean isCollectedByAnnotationCollector = (match.getType().getAnnotation("AnnotationCollector") != null);
return isRegularAnnotation || isCollectedByAnnotationCollector;
}
}