* Copyright (C) 2010 Robert Futrell
* robert_futrell at users.sourceforge.net
* http://fifesoft.com/rsyntaxtextarea
* This library is distributed under a modified BSD license. See the included
* RSTALanguageSupport.License.txt file for details.
package org.fife.rsta.ac.java;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.TreeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import org.fife.rsta.ac.ShorthandCompletionCache;
import org.fife.rsta.ac.java.buildpath.LibraryInfo;
import org.fife.rsta.ac.java.buildpath.SourceLocation;
import org.fife.rsta.ac.java.classreader.ClassFile;
import org.fife.rsta.ac.java.classreader.FieldInfo;
import org.fife.rsta.ac.java.classreader.MemberInfo;
import org.fife.rsta.ac.java.classreader.MethodInfo;
import org.fife.rsta.ac.java.rjc.ast.CodeBlock;
import org.fife.rsta.ac.java.rjc.ast.CompilationUnit;
import org.fife.rsta.ac.java.rjc.ast.Field;
import org.fife.rsta.ac.java.rjc.ast.FormalParameter;
import org.fife.rsta.ac.java.rjc.ast.ImportDeclaration;
import org.fife.rsta.ac.java.rjc.ast.LocalVariable;
import org.fife.rsta.ac.java.rjc.ast.Member;
import org.fife.rsta.ac.java.rjc.ast.Method;
import org.fife.rsta.ac.java.rjc.ast.NormalClassDeclaration;
import org.fife.rsta.ac.java.rjc.ast.TypeDeclaration;
import org.fife.rsta.ac.java.rjc.lang.Type;
import org.fife.rsta.ac.java.rjc.lang.TypeArgument;
import org.fife.rsta.ac.java.rjc.lang.TypeParameter;
import org.fife.ui.autocomplete.DefaultCompletionProvider;
import org.fife.ui.rsyntaxtextarea.RSyntaxDocument;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities;
import org.fife.ui.rsyntaxtextarea.Token;
* Parses a Java AST for code completions. It currently scans the following:
* Also, if the caret is inside a method, local variables up to the caret
* position are also returned.
class SourceCompletionProvider extends DefaultCompletionProvider {
* The parent completion provider.
private JavaCompletionProvider javaProvider;
* Used to get information about what classes match imports.
private JarManager jarManager;
private static final String JAVA_LANG_PACKAGE = "java.lang.*";
private static final String THIS = "this";
//Shorthand completions (templates and comments)
private ShorthandCompletionCache shorthandCache;
public SourceCompletionProvider() {
* @param jarManager The jar manager for this provider.
public SourceCompletionProvider(JarManager jarManager) {
jarManager = new JarManager();
this.jarManager = jarManager;
setParameterizedCompletionParams('(', ", ", ')');
setAutoActivationRules(false, "."); // Default - only activate after '.'
setParameterChoicesProvider(new SourceParamChoicesProvider());
private void addCompletionsForStaticMembers(Set set,
CompilationUnit cu, ClassFile cf, String pkg) {
// Check us first, so if we override anything, we get the "newest"
int methodCount = cf.getMethodCount();
for (int i=0; i<methodCount; i++) {
MethodInfo info = cf.getMethodInfo(i);
if (isAccessible(info, pkg) && info.isStatic()) {
MethodCompletion mc = new MethodCompletion(this, info);
int fieldCount = cf.getFieldCount();
for (int i=0; i<fieldCount; i++) {
FieldInfo info = cf.getFieldInfo(i);
if (isAccessible(info, pkg) && info.isStatic()) {
FieldCompletion fc = new FieldCompletion(this, info);
ClassFile superClass = getClassFileFor(cu, cf.getSuperClassName(true));
addCompletionsForStaticMembers(set, cu, superClass, pkg);
* Adds completions for accessible methods and fields of super classes.
* This is only called when the caret is inside of a class.
* TODO: Handle accessibility correctly!
* @param cu The compilation unit.
* @param cf A class in the chain of classes that a type being parsed
* @param pkg The package of the source being parsed.
* @param typeParamMap A mapping of type parameters to type arguments
* for the object whose fields/methods/etc. are currently being
private void addCompletionsForExtendedClass(Set set,
CompilationUnit cu, ClassFile cf, String pkg,
// Reset this class's type-arguments-to-type-parameters map, so that
// when methods and fields need to know type arguments, they can query
cf.setTypeParamsToTypeArgs(typeParamMap);
// Check us first, so if we override anything, we get the "newest"
int methodCount = cf.getMethodCount();
for (int i=0; i<methodCount; i++) {
MethodInfo info = cf.getMethodInfo(i);
// Don't show constructors
if (isAccessible(info, pkg) && !info.isConstructor()) {
MethodCompletion mc = new MethodCompletion(this, info);
int fieldCount = cf.getFieldCount();
for (int i=0; i<fieldCount; i++) {
FieldInfo info = cf.getFieldInfo(i);
if (isAccessible(info, pkg)) {
FieldCompletion fc = new FieldCompletion(this, info);
// Add completions for any non-overridden super-class methods.
ClassFile superClass = getClassFileFor(cu, cf.getSuperClassName(true));
addCompletionsForExtendedClass(set, cu, superClass, pkg, typeParamMap);
// Add completions for any interface methods, in case this class is
// abstract and hasn't implemented some of them yet.
// TODO: Do this only if "top-level" class is declared abstract
for (int i=0; i<cf.getImplementedInterfaceCount(); i++) {
String inter = cf.getImplementedInterfaceName(i, true);
cf = getClassFileFor(cu, inter);
addCompletionsForExtendedClass(set, cu, cf, pkg, typeParamMap);
* Adds completions for all methods and public fields of a local variable.
* This will add nothing if the local variable is a primitive type.
* @param cu The compilation unit being parsed.
* @param var The local variable.
* @param retVal The set to add completions to.
private void addCompletionsForLocalVarsMethods(CompilationUnit cu,
LocalVariable var, Set retVal) {
Type type = var.getType();
String pkg = cu.getPackageName();
ClassFile cf = getClassFileFor(cu, "java.lang.Object");
addCompletionsForExtendedClass(retVal, cu, cf, pkg, null);
FieldCompletion fc = FieldCompletion.
createLengthCompletion(this, type);
else if (!type.isBasicType()) {
String typeStr = type.getName(true, false);
ClassFile cf = getClassFileFor(cu, typeStr);
Map typeParamMap = createTypeParamMap(type, cf);
addCompletionsForExtendedClass(retVal, cu, cf, pkg, typeParamMap);
* Adds simple shorthand completions relevant to Java.
* @param set The set to add to.
private void addShorthandCompletions(Set set) {
if(shorthandCache != null) {
set.addAll(shorthandCache.getShorthandCompletions());
* Set template completion cache for source completion provider
public void setShorthandCache(ShorthandCompletionCache shorthandCache) {
this.shorthandCache = shorthandCache;
* Gets the {@link ClassFile} for a class.
* @param cu The compilation unit being parsed.
* @param className The name of the class (fully qualified or not).
* @return The {@link ClassFile} for the class, or <code>null</code> if
* <code>cf</code> represents <code>java.lang.Object</code> (or
* if the super class could not be determined).
private ClassFile getClassFileFor(CompilationUnit cu, String className) {
//System.err.println(">>> Getting class file for: " + className);
ClassFile superClass = null;
// Determine the fully qualified class to grab
if (!Util.isFullyQualified(className)) {
// Check in this source file's package first
String pkg = cu.getPackageName();
String temp = pkg + "." + className;
superClass = jarManager.getClassEntry(temp);
// Next, go through the imports (order is important)
for (Iterator i=cu.getImportIterator(); i.hasNext(); ) {
ImportDeclaration id = (ImportDeclaration)i.next();
String imported = id.getName();
if (imported.endsWith(".*")) {
String temp = imported.substring(
0, imported.length()-1) + className;
superClass = jarManager.getClassEntry(temp);
else if (imported.endsWith("." + className)) {
superClass = jarManager.getClassEntry(imported);
// Finally, try java.lang
String temp = "java.lang." + className;
superClass = jarManager.getClassEntry(temp);
superClass = jarManager.getClassEntry(className);
* Adds completions for local variables in a method.
* @param offs The caret's offset into the source. This should be inside
* of <code>method</code>.
private void addLocalVarCompletions(Set set, Method method, int offs) {
for (int i=0; i<method.getParameterCount(); i++) {
FormalParameter param = method.getParameter(i);
set.add(new LocalVariableCompletion(this, param));
CodeBlock body = method.getBody();
addLocalVarCompletions(set, body, offs);
* Adds completions for local variables in a code block inside of a method.
* @param block The code block.
* @param offs The caret's offset into the source. This should be inside
private void addLocalVarCompletions(Set set, CodeBlock block, int offs) {
for (int i=0; i<block.getLocalVarCount(); i++) {
LocalVariable var = block.getLocalVar(i);
if (var.getNameEndOffset()<=offs) {
set.add(new LocalVariableCompletion(this, var));
else { // This and all following declared after offs
for (int i=0; i<block.getChildBlockCount(); i++) {
CodeBlock child = block.getChildBlock(i);
if (child.containsOffset(offs)) {
addLocalVarCompletions(set, child, offs);
break; // All other blocks are past this one
// If we've reached a block that's past the offset we're
else if (child.getNameStartOffset()>offs) {
* Adds a jar to read from.
* @param info The jar to add. If this is <code>null</code>, then
* the current JVM's main JRE jar (rt.jar, or classes.jar on OS X)
* will be added. If this jar has already been added, adding it
* again will do nothing (except possibly update its attached source
* @throws IOException If an IO error occurs.
public void addJar(LibraryInfo info) throws IOException {
jarManager.addClassFileSource(info);
* Checks whether the user is typing a completion for a String member after
* @param comp The text component.
* @param alreadyEntered The text already entered.
* @param cu The compilation unit being parsed.
* @param set The set to add possible completions to.
* @return Whether the user is indeed typing a completion for a String
private boolean checkStringLiteralMember(JTextComponent comp,
CompilationUnit cu, Set set) {
boolean stringLiteralMember = false;
int offs = comp.getCaretPosition() - alreadyEntered.length() - 1;
RSyntaxTextArea textArea = (RSyntaxTextArea)comp;
RSyntaxDocument doc = (RSyntaxDocument)textArea.getDocument();
//System.out.println(doc.charAt(offs) + ", " + doc.charAt(offs+1));
if (doc.charAt(offs)=='"' && doc.charAt(offs+1)=='.') {
int curLine = textArea.getLineOfOffset(offs);
Token list = textArea.getTokenListForLine(curLine);
Token prevToken = RSyntaxUtilities.getTokenAtOffset(list, offs);
prevToken.getType()==Token.LITERAL_STRING_DOUBLE_QUOTE) {
ClassFile cf = getClassFileFor(cu, "java.lang.String");
addCompletionsForExtendedClass(set, cu, cf,
cu.getPackageName(), null);
stringLiteralMember = true;
System.out.println(prevToken);
} catch (BadLocationException ble) { // Never happens
return stringLiteralMember;
* Removes all jars from the "build path."
* @see #addClassFileSource(JarInfo)
public void clearJars() {
jarManager.clearClassFileSources();
// The memory used by the completions can be quite large, so go ahead
// and clear out the completions list so no-longer-needed ones are
* Creates and returns a mapping of type parameters to type arguments.
* @param type The type of a variable/field/etc. whose fields/methods/etc.
* are being code completed, as declared in the source. This
* includes type arguments.
* @param cf The <code>ClassFile</code> representing the actual type of
* the variable/field/etc. being code completed
* @return A mapping of type parameter names to type arguments (both
private Map createTypeParamMap(Type type, ClassFile cf) {
List typeArgs = type.getTypeArguments(type.getIdentifierCount()-1);
typeParamMap = new HashMap();
List paramTypes = cf.getParamTypes();
// Should be the same size! Otherwise, the source code has
// too many/too few type arguments listed for this type.
int min = Math.min(paramTypes==null ? 0 : paramTypes.size(),
for (int i=0; i<min; i++) {
TypeArgument typeArg = (TypeArgument)typeArgs.get(i);
typeParamMap.put(paramTypes.get(i), typeArg.toString());
public List getCompletionsAt(JTextComponent tc, Point p) {
getCompletionsImpl(tc); // Force loading of completions
return super.getCompletionsAt(tc, p);
protected List getCompletionsImpl(JTextComponent comp) {
comp.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
CompilationUnit cu = javaProvider.getCompilationUnit();
return completions; // empty
// Cut down the list to just those matching what we've typed.
// Note: getAlreadyEnteredText() never returns null
String text = getAlreadyEnteredText(comp);
// Special case - end of a String literal
boolean stringLiteralMember = checkStringLiteralMember(comp, text, cu,
// Not after a String literal - regular code completion
if (!stringLiteralMember) {
// Don't add shorthand completions if they're typing something
if (text.indexOf('.')==-1) {
addShorthandCompletions(set);
loadImportCompletions(set, text, cu);
// Add completions for fully-qualified stuff (e.g. "com.sun.jav")
//long startTime = System.currentTimeMillis();
jarManager.addCompletions(this, text, set);
//long time = System.currentTimeMillis() - startTime;
//System.out.println("jar completions loaded in: " + time);
// Loop through all types declared in this source, and provide
// completions depending on in what type/method/etc. the caret's in.
loadCompletionsForCaretPosition(cu, comp, text, set);
// Do a final sort of all of our completions and we're good to go!
completions = new ArrayList(set);
Collections.sort(completions);
// Only match based on stuff after the final '.', since that's what is
// displayed for all of our completions.
text = text.substring(text.lastIndexOf('.')+1);
int start = Collections.binarySearch(completions, text, comparator);
// There might be multiple entries with the same input text.
comparator.compare(completions.get(start-1), text)==0) {
int end = Collections.binarySearch(completions, text+'{', comparator);
return completions.subList(start, end);
comp.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
* Returns the jars on the "build path."
* @return A list of {@link JarInfo}s. Modifying a <tt>JarInfo</tt> in
* this list will have no effect on this completion provider; in
* order to do that, you must re-add the jar via
* {@link #addClassFileSource(JarInfo)}. If there are no jars on the
* "build path," this will be an empty list.
* @see #addClassFileSource(JarInfo)
return jarManager.getClassFileSources();
public SourceLocation getSourceLocForClass(String className) {
return jarManager.getSourceLocForClass(className);
* Returns whether a method defined by a super class is accessible to
* @param info Information about the member.
* @param pkg The package of the source currently being parsed.
* @return Whether or not the method is accessible.
private boolean isAccessible(MemberInfo info, String pkg) {
boolean accessible = false;
int access = info.getAccessFlags();
if (org.fife.rsta.ac.java.classreader.Util.isPublic(access) ||
org.fife.rsta.ac.java.classreader.Util.isProtected(access)) {
else if (org.fife.rsta.ac.java.classreader.Util.isDefault(access)) {
String pkg2 = info.getClassFile().getPackageName();
accessible = (pkg==null && pkg2==null) ||
(pkg!=null && pkg.equals(pkg2));
protected boolean isValidChar(char ch) {
return Character.isJavaIdentifierPart(ch) || ch=='.';
* Loads completions based on the current caret location in the source. In
* <li>If the caret is anywhere in a class, the names of all methods and
* fields in the class are loaded. Methods and fields in super
* classes are also loaded. TODO: Get super methods/fields added
* <li>If the caret is in a field, local variables currently accessible
private void loadCompletionsForCaretPosition(CompilationUnit cu,
JTextComponent comp, String alreadyEntered, Set retVal) {
// Get completions for all fields and methods of all type declarations.
//long startTime = System.currentTimeMillis();
int caret = comp.getCaretPosition();
//List temp = new ArrayList();
int lastDot = alreadyEntered.lastIndexOf('.');
boolean qualified = lastDot>-1;
String prefix = qualified ? alreadyEntered.substring(0, lastDot) : null;
for (Iterator i=cu.getTypeDeclarationIterator(); i.hasNext(); ) {
TypeDeclaration td = (TypeDeclaration)i.next();
start = td.getBodyStartOffset();
end = td.getBodyEndOffset();
if (caret>start && caret<=end) {
loadCompletionsForCaretPosition(cu, comp, alreadyEntered,
retVal, td, prefix, caret);
break; // We've passed any type declarations we could be in
//long time = System.currentTimeMillis() - startTime;
//System.out.println("methods/fields/localvars loaded in: " + time);
* Loads completions based on the current caret location in the source.
* This method is called when the caret is found to be in a specific type
* declaration. This method checks if the caret is in a child type
* declaration first, then adds completions for itself next.
* <li>If the caret is anywhere in a class, the names of all methods and
* fields in the class are loaded. Methods and fields in super
* classes are also loaded. TODO: Get super methods/fields added
* <li>If the caret is in a field, local variables currently accessible
private void loadCompletionsForCaretPosition(CompilationUnit cu,
JTextComponent comp, String alreadyEntered, Set retVal,
TypeDeclaration td, String prefix, int caret) {
// Do any child types first, so if any vars, etc. have duplicate names,
// we pick up the one "closest" to us first.
for (int i=0; i<td.getChildTypeCount(); i++) {
TypeDeclaration childType = td.getChildType(i);
loadCompletionsForCaretPosition(cu, comp, alreadyEntered, retVal,
childType, prefix, caret);
Method currentMethod = null;
Map typeParamMap = new HashMap();
if (td instanceof NormalClassDeclaration) {
NormalClassDeclaration ncd = (NormalClassDeclaration)td;
List typeParams = ncd.getTypeParameters();
for (int i=0; i<typeParams.size(); i++) {
TypeParameter typeParam = (TypeParameter)typeParams.get(i);
String typeVar = typeParam.getName();
// For non-qualified completions, use type var name.
typeParamMap.put(typeVar, typeVar);
// Get completions for this class's methods, fields and local
// vars. Do this before checking super classes so that, if
// we overrode anything, we get the "newest" version.
String pkg = cu.getPackageName();
for (Iterator j=td.getMemberIterator(); j.hasNext(); ) {
Member m = (Member)j.next();
if (m instanceof Method) {
Method method = (Method)m;
if (prefix==null || THIS.equals(prefix)) {
retVal.add(new MethodCompletion(this, method));
if (caret>=method.getBodyStartOffset() && caret<method.getBodyEndOffset()) {
// Don't add completions for local vars if there is
// a prefix, even "this".
addLocalVarCompletions(retVal, method, caret);
else if (m instanceof Field) {
if (prefix==null || THIS.equals(prefix)) {
retVal.add(new FieldCompletion(this, field));
// Completions for superclass methods.
// TODO: Implement me better
if (prefix==null || THIS.equals(prefix)) {
if (td instanceof NormalClassDeclaration) {
NormalClassDeclaration ncd = (NormalClassDeclaration)td;
Type extended = ncd.getExtendedType();
if (extended!=null) { // e.g., not java.lang.Object
String superClassName = extended.toString();
ClassFile cf = getClassFileFor(cu, superClassName);
addCompletionsForExtendedClass(retVal, cu, cf, pkg, null);
System.out.println("[DEBUG]: Couldn't find ClassFile for: " + superClassName);
// Completions for methods of fields, return values of methods,
// static fields/methods, etc.
if (prefix!=null && !THIS.equals(prefix)) {
loadCompletionsForCaretPositionQualified(cu,
td, currentMethod, prefix, caret);
* Loads completions for the text at the current caret position, if there
* is a "prefix" of chars and at least one '.' character in the text up to
* the caret. This is currently very limited and needs to be improved.
* @param td The type declaration the caret is in.
* @param currentMethod The method the caret is in, or <code>null</code> if
* @param prefix The text up to the current caret position. This is
* guaranteed to be non-<code>null</code> not equal to
* @param offs The offset of the caret in the document.
private void loadCompletionsForCaretPositionQualified(CompilationUnit cu,
String alreadyEntered, Set retVal,
TypeDeclaration td, Method currentMethod, String prefix, int offs) {
// TODO: Remove this restriction.
int dot = prefix.indexOf('.');
System.out.println("[DEBUG]: Qualified non-this completions currently only go 1 level deep");
// TODO: Remove this restriction.
else if (!prefix.matches("[A-Za-z_][A-Za-z0-9_\\$]*")) {
System.out.println("[DEBUG]: Only identifier non-this completions are currently supported");
String pkg = cu.getPackageName();
for (Iterator j=td.getMemberIterator(); j.hasNext(); ) {
Member m = (Member)j.next();
// The prefix might be a field in the local class.
if (m instanceof Field) {
if (field.getName().equals(prefix)) {
//System.out.println("FOUND: " + prefix + " (" + pkg + ")");
Type type = field.getType();
ClassFile cf = getClassFileFor(cu, "java.lang.Object");
addCompletionsForExtendedClass(retVal, cu, cf, pkg, null);
FieldCompletion fc = FieldCompletion.
createLengthCompletion(this, type);
else if (!type.isBasicType()) {
String typeStr = type.getName(true, false);
ClassFile cf = getClassFileFor(cu, typeStr);
// Add completions for extended class type chain
Map typeParamMap = createTypeParamMap(type, cf);
addCompletionsForExtendedClass(retVal, cu, cf, pkg, typeParamMap);
// Add completions for all implemented interfaces
// TODO: Only do this if type is abstract!
for (int i=0; i<cf.getImplementedInterfaceCount(); i++) {
String inter = cf.getImplementedInterfaceName(i, true);
cf = getClassFileFor(cu, inter);
// The prefix might be for a local variable in the current method.
if (currentMethod!=null) {
// Check parameters to the current method
for (int i=0; i<currentMethod.getParameterCount(); i++) {
FormalParameter param = currentMethod.getParameter(i);
String name = param.getName();
// Assuming prefix is "one level deep" and contains no '.'...
if (prefix.equals(name)) {
addCompletionsForLocalVarsMethods(cu, param, retVal);
// If a formal param wasn't matched, check local variables.
CodeBlock body = currentMethod.getBody();
loadCompletionsForCaretPositionQualifiedCodeBlock(cu,
retVal, td, body, prefix, offs);
// Could be a class name, in which case we'll need to add completions
// for static fields and methods.
List imports = cu.getImports();
List matches = jarManager.getClassesWithUnqualifiedName(
for (int i=0; i<matches.size(); i++) {
ClassFile cf = (ClassFile)matches.get(i);
addCompletionsForStaticMembers(retVal, cu, cf, pkg);
private void loadCompletionsForCaretPositionQualifiedCodeBlock(
CompilationUnit cu, Set retVal,
TypeDeclaration td, CodeBlock block, String prefix, int offs) {
for (int i=0; i<block.getLocalVarCount(); i++) {
LocalVariable var = block.getLocalVar(i);
if (var.getNameEndOffset()<=offs) {
// TODO: This assumes prefix is "1 level deep"
if (prefix.equals(var.getName())) {
addCompletionsForLocalVarsMethods(cu, var, retVal);
else { // This and all following declared after offs
for (int i=0; i<block.getChildBlockCount(); i++) {
CodeBlock child = block.getChildBlock(i);
if (child.containsOffset(offs)) {
loadCompletionsForCaretPositionQualifiedCodeBlock(cu, retVal,
td, child, prefix, offs);
break; // All other blocks are past this one
// If we've reached a block that's past the offset we're
else if (child.getNameStartOffset()>offs) {
* Loads completions for a single import statement.
* @param importStr The import statement.
* @param pkgName The package of the source currently being parsed.
private void loadCompletionsForImport(Set set, String importStr, String pkgName) {
if (importStr.endsWith(".*")) {
String pkg = importStr.substring(0, importStr.length()-2);
boolean inPkg = pkg.equals(pkgName);
List classes = jarManager.getClassesInPackage(pkg, inPkg);
for (Iterator i=classes.iterator(); i.hasNext(); ) {
ClassFile cf = (ClassFile)i.next();
set.add(new ClassCompletion(this, cf));
ClassFile cf = jarManager.getClassEntry(importStr);
set.add(new ClassCompletion(this, cf));
* Loads completions for all import statements.
* @param cu The compilation unit being parsed.
private void loadImportCompletions(Set set, String text,
// Fully-qualified completions are handled elsewhere, so no need to
// duplicate the work here
if (text.indexOf('.')>-1) {
//long startTime = System.currentTimeMillis();
String pkgName = cu.getPackageName();
loadCompletionsForImport(set, JAVA_LANG_PACKAGE, pkgName);
for (Iterator i=cu.getImportIterator(); i.hasNext(); ) {
ImportDeclaration id = (ImportDeclaration)i.next();
String name = id.getName();
if (!JAVA_LANG_PACKAGE.equals(name)) {
loadCompletionsForImport(set, name, pkgName);
// Collections.sort(completions);
//long time = System.currentTimeMillis() - startTime;
//System.out.println("imports loaded in: " + time);
* Removes a jar from the "build path."
* @param jar The jar to remove.
* @return Whether the jar was removed. This will be <code>false</code>
* if the jar was not on the build path.
* @see #addClassFileSource(JarInfo)
public boolean removeJar(File jar) {
boolean removed = jarManager.removeClassFileSource(jar);
// The memory used by the completions can be quite large, so go ahead
// and clear out the completions list so no-longer-needed ones are
* Sets the parent Java provider.
* @param javaProvider The parent completion provider.
void setJavaProvider(JavaCompletionProvider javaProvider) {
this.javaProvider = javaProvider;