blob: 0c7de1594de24ff9b52dbd0e98393fd85df87622 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Stephan Herrmann - Contribution for
* Bug 440477 - [null] Infrastructure for feeding external annotations into compilation
*******************************************************************************/
package org.eclipse.jdt.internal.core.search.matching;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageDeclaration;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
import org.eclipse.jdt.internal.core.ClasspathEntry;
import org.eclipse.jdt.internal.core.JavaModel;
import org.eclipse.jdt.internal.core.JavaModelManager;
import org.eclipse.jdt.internal.core.JavaProject;
import org.eclipse.jdt.internal.core.PackageFragmentRoot;
import org.eclipse.jdt.internal.core.builder.ClasspathJar;
import org.eclipse.jdt.internal.core.builder.ClasspathLocation;
import org.eclipse.jdt.internal.core.util.Util;
/*
* A name environment based on the classpath of a Java project.
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public class JavaSearchNameEnvironment implements INameEnvironment, SuffixConstants {
LinkedHashSet<ClasspathLocation> locationSet;
/*
* A map from the fully qualified slash-separated name of the main type (String) to the working copy
*/
Map<String, org.eclipse.jdt.core.ICompilationUnit> workingCopies;
public JavaSearchNameEnvironment(IJavaProject javaProject, org.eclipse.jdt.core.ICompilationUnit[] copies) {
this.locationSet = computeClasspathLocations((JavaProject) javaProject);
this.workingCopies = getWorkingCopyMap(copies);
}
public static Map<String, org.eclipse.jdt.core.ICompilationUnit> getWorkingCopyMap(
org.eclipse.jdt.core.ICompilationUnit[] copies) {
int length = copies == null ? 0 : copies.length;
HashMap<String, org.eclipse.jdt.core.ICompilationUnit> result = new HashMap<>(length);
try {
if (copies != null) {
for (int i = 0; i < length; i++) {
org.eclipse.jdt.core.ICompilationUnit workingCopy = copies[i];
IPackageDeclaration[] pkgs = workingCopy.getPackageDeclarations();
String pkg = pkgs.length > 0 ? pkgs[0].getElementName() : ""; //$NON-NLS-1$
String cuName = workingCopy.getElementName();
String mainTypeName = Util.getNameWithoutJavaLikeExtension(cuName);
String qualifiedMainTypeName = pkg.length() == 0 ? mainTypeName : pkg.replace('.', '/') + '/' + mainTypeName;
result.put(qualifiedMainTypeName, workingCopy);
}
}
} catch (JavaModelException e) {
// working copy doesn't exist: cannot happen
}
return result;
}
public void cleanup() {
this.locationSet.clear();
}
void addProjectClassPath(JavaProject javaProject) {
LinkedHashSet<ClasspathLocation> locations = computeClasspathLocations(javaProject);
if (locations != null) this.locationSet.addAll(locations);
}
private LinkedHashSet<ClasspathLocation> computeClasspathLocations(JavaProject javaProject) {
IPackageFragmentRoot[] roots = null;
try {
roots = javaProject.getAllPackageFragmentRoots();
} catch (JavaModelException e) {
return null;// project doesn't exist
}
LinkedHashSet<ClasspathLocation> locations = new LinkedHashSet<ClasspathLocation>();
int length = roots.length;
JavaModelManager manager = JavaModelManager.getJavaModelManager();
for (int i = 0; i < length; i++) {
ClasspathLocation cp = mapToClassPathLocation(manager, (PackageFragmentRoot) roots[i]);
if (cp != null) locations.add(cp);
}
return locations;
}
private ClasspathLocation mapToClassPathLocation( JavaModelManager manager, PackageFragmentRoot root) {
ClasspathLocation cp = null;
IPath path = root.getPath();
try {
if (root.isArchive()) {
ClasspathEntry rawClasspathEntry = (ClasspathEntry) root.getRawClasspathEntry();
cp = new ClasspathJar(manager.getZipFile(path), rawClasspathEntry.getAccessRuleSet(), ClasspathEntry.getExternalAnnotationPath(rawClasspathEntry, ((IJavaProject)root.getParent()).getProject(), true));
} else {
Object target = JavaModel.getTarget(path, true);
if (target != null) {
if (root.getKind() == IPackageFragmentRoot.K_SOURCE) {
cp = new ClasspathSourceDirectory((IContainer)target, root.fullExclusionPatternChars(), root.fullInclusionPatternChars());
} else {
ClasspathEntry rawClasspathEntry = (ClasspathEntry) root.getRawClasspathEntry();
cp = ClasspathLocation.forBinaryFolder((IContainer) target, false, rawClasspathEntry.getAccessRuleSet(),
ClasspathEntry.getExternalAnnotationPath(rawClasspathEntry, ((IJavaProject)root.getParent()).getProject(), true));
}
}
}
} catch (CoreException e1) {
// problem opening zip file or getting root kind
// consider root corrupt and ignore
}
return cp;
}
private NameEnvironmentAnswer findClass(String qualifiedTypeName, char[] typeName) {
String
binaryFileName = null, qBinaryFileName = null,
sourceFileName = null, qSourceFileName = null,
qPackageName = null;
NameEnvironmentAnswer suggestedAnswer = null;
Iterator <ClasspathLocation> iter = this.locationSet.iterator();
while (iter.hasNext()) {
ClasspathLocation location = iter.next();
NameEnvironmentAnswer answer;
if (location instanceof ClasspathSourceDirectory) {
if (sourceFileName == null) {
qSourceFileName = qualifiedTypeName; // doesn't include the file extension
sourceFileName = qSourceFileName;
qPackageName = ""; //$NON-NLS-1$
if (qualifiedTypeName.length() > typeName.length) {
int typeNameStart = qSourceFileName.length() - typeName.length;
qPackageName = qSourceFileName.substring(0, typeNameStart - 1);
sourceFileName = qSourceFileName.substring(typeNameStart);
}
}
ICompilationUnit workingCopy = (ICompilationUnit) this.workingCopies.get(qualifiedTypeName);
if (workingCopy != null) {
answer = new NameEnvironmentAnswer(workingCopy, null /*no access restriction*/);
} else {
answer = location.findClass(
sourceFileName, // doesn't include the file extension
qPackageName,
qSourceFileName); // doesn't include the file extension
}
} else {
if (binaryFileName == null) {
qBinaryFileName = qualifiedTypeName + SUFFIX_STRING_class;
binaryFileName = qBinaryFileName;
qPackageName = ""; //$NON-NLS-1$
if (qualifiedTypeName.length() > typeName.length) {
int typeNameStart = qBinaryFileName.length() - typeName.length - 6; // size of ".class"
qPackageName = qBinaryFileName.substring(0, typeNameStart - 1);
binaryFileName = qBinaryFileName.substring(typeNameStart);
}
}
answer =
location.findClass(
binaryFileName,
qPackageName,
qBinaryFileName);
}
if (answer != null) {
if (!answer.ignoreIfBetter()) {
if (answer.isBetter(suggestedAnswer))
return answer;
} else if (answer.isBetter(suggestedAnswer))
// remember suggestion and keep looking
suggestedAnswer = answer;
}
}
if (suggestedAnswer != null)
// no better answer was found
return suggestedAnswer;
return null;
}
public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) {
if (typeName != null)
return findClass(
new String(CharOperation.concatWith(packageName, typeName, '/')),
typeName);
return null;
}
public NameEnvironmentAnswer findType(char[][] compoundName) {
if (compoundName != null)
return findClass(
new String(CharOperation.concatWith(compoundName, '/')),
compoundName[compoundName.length - 1]);
return null;
}
public boolean isPackage(char[][] compoundName, char[] packageName) {
return isPackage(new String(CharOperation.concatWith(compoundName, packageName, '/')));
}
public boolean isPackage(String qualifiedPackageName) {
Iterator<ClasspathLocation> iter = this.locationSet.iterator();
while (iter.hasNext()) {
if (iter.next().isPackage(qualifiedPackageName)) return true;
}
return false;
}
}