blob: 6455af5c2d2144917177074de3e3c746e44abc0c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.core;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.search.*;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.ITypeNameRequestor;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.internal.codeassist.ISearchRequestor;
import org.eclipse.jdt.internal.codeassist.ISearchableNameEnvironment;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.env.IConstants;
import org.eclipse.jdt.internal.compiler.env.ISourceType;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
/**
* This class provides a <code>SearchableBuilderEnvironment</code> for code assist which
* uses the Java model as a search tool.
*/
public class SearchableEnvironment
implements ISearchableNameEnvironment, IJavaSearchConstants {
public NameLookup nameLookup;
protected ICompilationUnit unitToSkip;
protected IJavaProject project;
protected IJavaSearchScope searchScope;
/**
* Creates a SearchableEnvironment on the given project
*/
public SearchableEnvironment(JavaProject project, org.eclipse.jdt.core.ICompilationUnit[] workingCopies) throws JavaModelException {
this.project = project;
this.nameLookup = project.newNameLookup(workingCopies);
// Create search scope with visible entry on the project's classpath
this.searchScope = SearchEngine.createJavaSearchScope(this.project.getAllPackageFragmentRoots());
}
/**
* Creates a SearchableEnvironment on the given project
*/
public SearchableEnvironment(JavaProject project, WorkingCopyOwner owner) throws JavaModelException {
this.project = project;
this.nameLookup = project.newNameLookup(owner);
// Create search scope with visible entry on the project's classpath
this.searchScope = SearchEngine.createJavaSearchScope(this.project.getAllPackageFragmentRoots());
}
/**
* Returns the given type in the the given package if it exists,
* otherwise <code>null</code>.
*/
protected NameEnvironmentAnswer find(String typeName, String packageName) {
if (packageName == null)
packageName = IPackageFragment.DEFAULT_PACKAGE_NAME;
IType type =
this.nameLookup.findType(
typeName,
packageName,
false,
NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
if (type != null) {
if (type instanceof BinaryType) {
try {
return new NameEnvironmentAnswer(
(IBinaryType) ((BinaryType) type).getElementInfo());
} catch (JavaModelException npe) {
return null;
}
} else { //SourceType
try {
// retrieve the requested type
SourceTypeElementInfo sourceType = (SourceTypeElementInfo)((SourceType)type).getElementInfo();
ISourceType topLevelType = sourceType;
while (topLevelType.getEnclosingType() != null) {
topLevelType = topLevelType.getEnclosingType();
}
// find all siblings (other types declared in same unit, since may be used for name resolution)
IType[] types = sourceType.getHandle().getCompilationUnit().getTypes();
ISourceType[] sourceTypes = new ISourceType[types.length];
// in the resulting collection, ensure the requested type is the first one
sourceTypes[0] = sourceType;
for (int i = 0, index = 1; i < types.length; i++) {
ISourceType otherType =
(ISourceType) ((JavaElement) types[i]).getElementInfo();
if (!otherType.equals(topLevelType))
sourceTypes[index++] = otherType;
}
return new NameEnvironmentAnswer(sourceTypes);
} catch (JavaModelException npe) {
return null;
}
}
}
return null;
}
/**
* @see ISearchableNameEnvironment#findPackages(char[], ISearchRequestor)
*/
public void findPackages(char[] prefix, ISearchRequestor requestor) {
this.nameLookup.seekPackageFragments(
new String(prefix),
true,
new SearchableEnvironmentRequestor(requestor));
}
/**
* @see org.eclipse.jdt.internal.compiler.env.INameEnvironment#findType(char[][])
*/
public NameEnvironmentAnswer findType(char[][] compoundTypeName) {
if (compoundTypeName == null) return null;
int length = compoundTypeName.length;
if (length <= 1) {
if (length == 0) return null;
return find(new String(compoundTypeName[0]), null);
}
int lengthM1 = length - 1;
char[][] packageName = new char[lengthM1][];
System.arraycopy(compoundTypeName, 0, packageName, 0, lengthM1);
return find(
new String(compoundTypeName[lengthM1]),
CharOperation.toString(packageName));
}
/**
* @see INameEnvironment#findType(char[], char[][])
*/
public NameEnvironmentAnswer findType(char[] name, char[][] packageName) {
if (name == null) return null;
return find(
new String(name),
packageName == null || packageName.length == 0 ? null : CharOperation.toString(packageName));
}
/**
* @see ISearchableNameEnvironment#findTypes(char[], ISearchRequestor)
*/
public void findTypes(char[] prefix, final ISearchRequestor storage) {
/*
if (true){
findTypes(new String(prefix), storage, NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
return;
}
*/
try {
final String excludePath;
if (this.unitToSkip != null) {
if (!(this.unitToSkip instanceof IJavaElement)) {
// revert to model investigation
findTypes(
new String(prefix),
storage,
NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
return;
}
excludePath = ((IJavaElement) this.unitToSkip).getPath().toString();
} else {
excludePath = null;
}
int lastDotIndex = CharOperation.lastIndexOf('.', prefix);
char[] qualification, simpleName;
if (lastDotIndex < 0) {
qualification = null;
simpleName = CharOperation.toLowerCase(prefix);
} else {
qualification = CharOperation.subarray(prefix, 0, lastDotIndex);
simpleName =
CharOperation.toLowerCase(
CharOperation.subarray(prefix, lastDotIndex + 1, prefix.length));
}
IProgressMonitor progressMonitor = new IProgressMonitor() {
boolean isCanceled = false;
public void beginTask(String name, int totalWork) {
// implements interface method
}
public void done() {
// implements interface method
}
public void internalWorked(double work) {
// implements interface method
}
public boolean isCanceled() {
return isCanceled;
}
public void setCanceled(boolean value) {
isCanceled = value;
}
public void setTaskName(String name) {
// implements interface method
}
public void subTask(String name) {
// implements interface method
}
public void worked(int work) {
// implements interface method
}
};
ITypeNameRequestor nameRequestor = new ITypeNameRequestor() {
public void acceptClass(
char[] packageName,
char[] simpleTypeName,
char[][] enclosingTypeNames,
String path) {
if (excludePath != null && excludePath.equals(path))
return;
if (enclosingTypeNames != null && enclosingTypeNames.length > 0)
return; // accept only top level types
storage.acceptClass(packageName, simpleTypeName, IConstants.AccPublic);
}
public void acceptInterface(
char[] packageName,
char[] simpleTypeName,
char[][] enclosingTypeNames,
String path) {
if (excludePath != null && excludePath.equals(path))
return;
if (enclosingTypeNames != null && enclosingTypeNames.length > 0)
return; // accept only top level types
storage.acceptInterface(packageName, simpleTypeName, IConstants.AccPublic);
}
};
try {
new SearchEngine().searchAllTypeNames(
this.project.getProject().getWorkspace(),
qualification,
simpleName,
SearchPattern.R_PREFIX_MATCH,
false, // not case sensitive
IJavaSearchConstants.TYPE,
this.searchScope,
nameRequestor,
CANCEL_IF_NOT_READY_TO_SEARCH,
progressMonitor);
} catch (OperationCanceledException e) {
findTypes(
new String(prefix),
storage,
NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
}
} catch (JavaModelException e) {
findTypes(
new String(prefix),
storage,
NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
}
}
/**
* Returns all types whose name starts with the given (qualified) <code>prefix</code>.
*
* If the <code>prefix</code> is unqualified, all types whose simple name matches
* the <code>prefix</code> are returned.
*/
private void findTypes(String prefix, ISearchRequestor storage, int type) {
SearchableEnvironmentRequestor requestor =
new SearchableEnvironmentRequestor(storage, this.unitToSkip);
int index = prefix.lastIndexOf('.');
if (index == -1) {
this.nameLookup.seekTypes(prefix, null, true, type, requestor);
} else {
String packageName = prefix.substring(0, index);
JavaElementRequestor elementRequestor = new JavaElementRequestor();
this.nameLookup.seekPackageFragments(packageName, false, elementRequestor);
IPackageFragment[] fragments = elementRequestor.getPackageFragments();
if (fragments != null) {
String className = prefix.substring(index + 1);
for (int i = 0, length = fragments.length; i < length; i++)
if (fragments[i] != null)
this.nameLookup.seekTypes(className, fragments[i], true, type, requestor);
}
}
}
/**
* @see org.eclipse.jdt.internal.compiler.env.INameEnvironment#isPackage(char[][], char[])
*/
public boolean isPackage(char[][] parentPackageName, char[] subPackageName) {
if (subPackageName == null || CharOperation.contains('.', subPackageName))
return false;
if (parentPackageName == null || parentPackageName.length == 0)
return isTopLevelPackage(subPackageName);
for (int i = 0, length = parentPackageName.length; i < length; i++)
if (parentPackageName[i] == null || CharOperation.contains('.', parentPackageName[i]))
return false;
String packageName = new String(CharOperation.concatWith(parentPackageName, subPackageName, '.'));
return this.nameLookup.findPackageFragments(packageName, false) != null;
}
public boolean isTopLevelPackage(char[] packageName) {
return packageName != null &&
!CharOperation.contains('.', packageName) &&
this.nameLookup.findPackageFragments(new String(packageName), false) != null;
}
/**
* Returns a printable string for the array.
*/
protected String toStringChar(char[] name) {
return "[" //$NON-NLS-1$
+ new String(name) + "]" ; //$NON-NLS-1$
}
/**
* Returns a printable string for the array.
*/
protected String toStringCharChar(char[][] names) {
StringBuffer result = new StringBuffer();
for (int i = 0; i < names.length; i++) {
result.append(toStringChar(names[i]));
}
return result.toString();
}
public void cleanup() {
// nothing to do
}
}