package org.eclipse.jdt.internal.core; | |
/* | |
* (c) Copyright IBM Corp. 2000, 2001. | |
* All Rights Reserved. | |
*/ | |
import org.eclipse.core.runtime.IProgressMonitor; | |
import java.util.ArrayList; | |
import org.eclipse.core.resources.*; | |
import org.eclipse.jdt.core.search.*; | |
import org.eclipse.jdt.internal.compiler.env.IBinaryType; | |
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; | |
import org.eclipse.jdt.internal.compiler.util.CharOperation; | |
import org.eclipse.jdt.internal.codeassist.CompletionEngine; | |
import org.eclipse.jdt.internal.codeassist.ISelectionRequestor; | |
import org.eclipse.jdt.core.*; | |
/** | |
* Parent is an IClassFile. | |
* | |
* @see IType | |
*/ | |
public class BinaryType extends BinaryMember implements IType { | |
private static final IField[] NO_FIELDS = new IField[0]; | |
private static final IMethod[] NO_METHODS = new IMethod[0]; | |
private static final IType[] NO_TYPES = new IType[0]; | |
private static final IInitializer[] NO_INITIALIZERS = new IInitializer[0]; | |
private static final String[] NO_STRINGS = new String[0]; | |
protected BinaryType(IJavaElement parent, String name) { | |
super(TYPE, parent, name); | |
Assert.isTrue(name.indexOf('.') == -1); | |
} | |
/** | |
* @see IOpenable#close() | |
*/ | |
public void close() throws JavaModelException { | |
Object info = fgJavaModelManager.peekAtInfo(this); | |
if (info != null) { | |
ClassFileInfo cfi = getClassFileInfo(); | |
if (cfi.hasReadBinaryChildren()) { | |
try { | |
IJavaElement[] children = getChildren(); | |
for (int i = 0, size = children.length; i < size; ++i) { | |
JavaElement child = (JavaElement) children[i]; | |
if (child instanceof BinaryType) { | |
((IOpenable)child.getParent()).close(); | |
} else { | |
child.close(); | |
} | |
} | |
} catch (JavaModelException e) { | |
} | |
} | |
closing(info); | |
fgJavaModelManager.removeInfo(this); | |
if (JavaModelManager.VERBOSE){ | |
System.out.println("-> Package cache size = " + fgJavaModelManager.cache.pkgSize()); //$NON-NLS-1$ | |
System.out.println("-> Openable cache filling rate = " + fgJavaModelManager.cache.openableFillingRate() + "%"); //$NON-NLS-1$//$NON-NLS-2$ | |
} | |
} | |
} | |
/** | |
* Remove my cached children from the Java Model | |
*/ | |
protected void closing(Object info) throws JavaModelException { | |
if (JavaModelManager.VERBOSE){ | |
System.out.println("CLOSING Element ("+ Thread.currentThread()+"): " + this.toStringWithAncestors()); //$NON-NLS-1$//$NON-NLS-2$ | |
} | |
ClassFileInfo cfi = getClassFileInfo(); | |
cfi.removeBinaryChildren(); | |
if (JavaModelManager.VERBOSE){ | |
System.out.println("-> Package cache size = " + fgJavaModelManager.cache.pkgSize()); //$NON-NLS-1$ | |
System.out.println("-> Openable cache filling rate = " + fgJavaModelManager.cache.openableFillingRate() + "%"); //$NON-NLS-1$//$NON-NLS-2$ | |
} | |
} | |
/** | |
* @see IType#codeComplete(char[], int, int, char[][], char[][], int[], boolean, ICompletionRequestor) | |
*/ | |
public void codeComplete(char[] snippet,int insertion,int position,char[][] localVariableTypeNames,char[][] localVariableNames,int[] localVariableModifiers,boolean isStatic,ICompletionRequestor requestor) throws JavaModelException { | |
if (requestor == null) { | |
throw new IllegalArgumentException(Util.bind("codeAssist.nullRequestor")); //$NON-NLS-1$ | |
} | |
SearchableEnvironment environment = (SearchableEnvironment) ((JavaProject) getJavaProject()).getSearchableNameEnvironment(); | |
NameLookup nameLookup = ((JavaProject) getJavaProject()).getNameLookup(); | |
CompletionEngine engine = new CompletionEngine(environment, new CompletionRequestorWrapper(requestor,nameLookup), JavaCore.getOptions()); | |
String source = getClassFile().getSource(); | |
if (source != null && insertion > -1 && insertion < source.length()) { | |
String encoding = (String) JavaCore.getOptions().get(CompilerOptions.OPTION_Encoding); | |
if ("".equals(encoding)) encoding = null; //$NON-NLS-1$ | |
char[] prefix = CharOperation.concat(source.substring(0, insertion).toCharArray(), new char[]{'{'}); | |
char[] suffix = CharOperation.concat(new char[]{'}'}, source.substring(insertion).toCharArray()); | |
char[] fakeSource = CharOperation.concat(prefix, snippet, suffix); | |
BasicCompilationUnit cu = | |
new BasicCompilationUnit( | |
fakeSource, | |
getElementName(), | |
encoding); | |
engine.complete(cu, prefix.length + position, prefix.length); | |
} else { | |
engine.complete(this, snippet, position, localVariableTypeNames, localVariableNames, localVariableModifiers, isStatic); | |
} | |
} | |
/** | |
* @see IType#createField(String, IJavaElement, boolean, IProgressMonitor) | |
*/ | |
public IField createField(String contents, IJavaElement sibling, boolean force, IProgressMonitor monitor) throws JavaModelException { | |
throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this)); | |
} | |
/** | |
* @see IType#createInitializer(String, IJavaElement, IProgressMonitor) | |
*/ | |
public IInitializer createInitializer(String contents, IJavaElement sibling, IProgressMonitor monitor) throws JavaModelException { | |
throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this)); | |
} | |
/** | |
* @see IType#createMethod(String, IJavaElement, boolean, IProgressMonitor) | |
*/ | |
public IMethod createMethod(String contents, IJavaElement sibling, boolean force, IProgressMonitor monitor) throws JavaModelException { | |
throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this)); | |
} | |
/** | |
* @see IType#createType(String, IJavaElement, boolean, IProgressMonitor) | |
*/ | |
public IType createType(String contents, IJavaElement sibling, boolean force, IProgressMonitor monitor) throws JavaModelException { | |
throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this)); | |
} | |
/** | |
* @see IType#findMethods(IMethod) | |
*/ | |
public IMethod[] findMethods(IMethod method) { | |
try { | |
return this.findMethods(method, this.getMethods()); | |
} catch (JavaModelException e) { | |
// if type doesn't exist, no matching method can exist | |
return null; | |
} | |
} | |
/** | |
* @see IParent#getChildren() | |
*/ | |
public IJavaElement[] getChildren() throws JavaModelException { | |
// ensure present | |
// fix for 1FWWVYT | |
if (!exists()) { | |
throw newNotPresentException(); | |
} | |
// get children | |
ClassFileInfo cfi = getClassFileInfo(); | |
return cfi.getBinaryChildren(); | |
} | |
protected ClassFileInfo getClassFileInfo() throws JavaModelException { | |
ClassFile cf = (ClassFile) fParent; | |
return (ClassFileInfo) cf.getElementInfo(); | |
} | |
/** | |
* @see IMember#getDeclaringType() | |
*/ | |
public IType getDeclaringType() { | |
IClassFile classFile = this.getClassFile(); | |
if (classFile.isOpen()) { | |
try { | |
char[] enclosingTypeName = ((IBinaryType) getRawInfo()).getEnclosingTypeName(); | |
if (enclosingTypeName == null) { | |
return null; | |
} | |
enclosingTypeName = ClassFile.unqualifiedName(enclosingTypeName); | |
// workaround problem with class files compiled with javac 1.1.* | |
// that return a non-null enclosing type name for local types defined in anonymous (e.g. A$1$B) | |
if (classFile.getElementName().length() > enclosingTypeName.length+1 | |
&& Character.isDigit(classFile.getElementName().charAt(enclosingTypeName.length+1))) { | |
return null; | |
} | |
return getPackageFragment().getClassFile(new String(enclosingTypeName) + ".class").getType(); //$NON-NLS-1$; | |
} catch (JavaModelException npe) { | |
return null; | |
} | |
} else { | |
// cannot access .class file without opening it | |
// and getDeclaringType() is supposed to be a handle-only method, | |
// so default to assuming $ is an enclosing type separator | |
String classFileName = classFile.getElementName(); | |
int lastDollar = -1; | |
for (int i = 0, length = classFileName.length(); i < length; i++) { | |
char c = classFileName.charAt(i); | |
if (Character.isDigit(c) && lastDollar == i-1) { | |
// anonymous or local type | |
return null; | |
} else if (c == '$') { | |
lastDollar = i; | |
} | |
} | |
if (lastDollar == -1) { | |
return null; | |
} else { | |
String enclosingName = classFileName.substring(0, lastDollar); | |
String enclosingClassFileName = enclosingName + ".class"; //$NON-NLS-1$ | |
return | |
new BinaryType( | |
this.getPackageFragment().getClassFile(enclosingClassFileName), | |
enclosingName.substring(enclosingName.lastIndexOf('$')+1)); | |
} | |
} | |
} | |
/** | |
* @see IType#getField(String name) | |
*/ | |
public IField getField(String name) { | |
return new BinaryField(this, name); | |
} | |
/** | |
* @see IType#getFields() | |
*/ | |
public IField[] getFields() throws JavaModelException { | |
ArrayList list = getChildrenOfType(FIELD); | |
int size; | |
if ((size = list.size()) == 0) { | |
return NO_FIELDS; | |
} else { | |
IField[] array= new IField[size]; | |
list.toArray(array); | |
return array; | |
} | |
} | |
/** | |
* @see IMember#getFlags() | |
*/ | |
public int getFlags() throws JavaModelException { | |
IBinaryType info = (IBinaryType) getRawInfo(); | |
return info.getModifiers(); | |
} | |
/** | |
* @see IType#getFullyQualifiedName() | |
*/ | |
public String getFullyQualifiedName() { | |
return this.getFullyQualifiedName('$'); | |
} | |
/** | |
* @see IType#getFullyQualifiedName(char enclosingTypeSeparator) | |
*/ | |
public String getFullyQualifiedName(char enclosingTypeSeparator) { | |
String packageName = getPackageFragment().getElementName(); | |
if (packageName.equals(IPackageFragment.DEFAULT_PACKAGE_NAME)) { | |
return getTypeQualifiedName(enclosingTypeSeparator); | |
} | |
return packageName + '.' + getTypeQualifiedName(enclosingTypeSeparator); | |
} | |
/** | |
* @see IType#getInitializer(int occurrenceCount) | |
*/ | |
public IInitializer getInitializer(int occurrenceCount) { | |
return new Initializer(this, occurrenceCount); | |
} | |
/** | |
* @see IType#getInitializers() | |
*/ | |
public IInitializer[] getInitializers() { | |
return NO_INITIALIZERS; | |
} | |
/** | |
* @see IType#getMethod(String name, String[] parameterTypeSignatures) | |
*/ | |
public IMethod getMethod(String name, String[] parameterTypeSignatures) { | |
return new BinaryMethod(this, name, parameterTypeSignatures); | |
} | |
/** | |
* @see IType#getMethods() | |
*/ | |
public IMethod[] getMethods() throws JavaModelException { | |
ArrayList list = getChildrenOfType(METHOD); | |
int size; | |
if ((size = list.size()) == 0) { | |
return NO_METHODS; | |
} else { | |
IMethod[] array= new IMethod[size]; | |
list.toArray(array); | |
return array; | |
} | |
} | |
/** | |
* @see IType#getPackageFragment() | |
*/ | |
public IPackageFragment getPackageFragment() { | |
IJavaElement parent = fParent; | |
while (parent != null) { | |
if (parent.getElementType() == IJavaElement.PACKAGE_FRAGMENT) { | |
return (IPackageFragment) parent; | |
} | |
else { | |
parent = parent.getParent(); | |
} | |
} | |
Assert.isTrue(false); // should not happen | |
return null; | |
} | |
/** | |
* @see IType#getSuperclassName() | |
*/ | |
public String getSuperclassName() throws JavaModelException { | |
IBinaryType info = (IBinaryType) getRawInfo(); | |
char[] superclassName = info.getSuperclassName(); | |
if (superclassName == null) { | |
return null; | |
} | |
return new String(ClassFile.translatedName(superclassName)); | |
} | |
/** | |
* @see IType#getSuperInterfaceNames() | |
*/ | |
public String[] getSuperInterfaceNames() throws JavaModelException { | |
IBinaryType info = (IBinaryType) getRawInfo(); | |
char[][] names= info.getInterfaceNames(); | |
int length; | |
if (names == null || (length = names.length) == 0) { | |
return NO_STRINGS; | |
} | |
names= ClassFile.translatedNames(names); | |
String[] strings= new String[length]; | |
for (int i= 0; i < length; i++) { | |
strings[i]= new String(names[i]); | |
} | |
return strings; | |
} | |
/** | |
* @see IType#getType(String) | |
*/ | |
public IType getType(String name) { | |
IClassFile classFile= getPackageFragment().getClassFile(getTypeQualifiedName() + "$" + name + ".class"); //$NON-NLS-2$ //$NON-NLS-1$ | |
return new BinaryType(classFile, name); | |
} | |
/** | |
* @see IType#getTypeQualifiedName() | |
*/ | |
public String getTypeQualifiedName() { | |
return this.getTypeQualifiedName('$'); | |
} | |
/** | |
* @see IType#getTypeQualifiedName(char) | |
*/ | |
public String getTypeQualifiedName(char enclosingTypeSeparator) { | |
IType declaringType = this.getDeclaringType(); | |
if (declaringType == null) { | |
String classFileName = this.getClassFile().getElementName(); | |
if (classFileName.indexOf('$') == -1) { | |
// top level class file: name of type is same as name of class file | |
return fName; | |
} else { | |
// anonymous or local class file | |
return classFileName.substring(0, classFileName.lastIndexOf('.')); // remove .class | |
} | |
} else { | |
return | |
declaringType.getTypeQualifiedName(enclosingTypeSeparator) | |
+ enclosingTypeSeparator | |
+ fName; | |
} | |
} | |
/** | |
* @see IType#getTypes() | |
*/ | |
public IType[] getTypes() throws JavaModelException { | |
ArrayList list = getChildrenOfType(TYPE); | |
int size; | |
if ((size = list.size()) == 0) { | |
return NO_TYPES; | |
} else { | |
IType[] array= new IType[size]; | |
list.toArray(array); | |
return array; | |
} | |
} | |
/** | |
* @see IParent#hasChildren() | |
*/ | |
public boolean hasChildren() throws JavaModelException { | |
return getChildren().length > 0; | |
} | |
/** | |
* @see IType#isClass() | |
*/ | |
public boolean isClass() throws JavaModelException { | |
return !isInterface(); | |
} | |
/** | |
* @see IType#isInterface() | |
*/ | |
public boolean isInterface() throws JavaModelException { | |
IBinaryType info = (IBinaryType) getRawInfo(); | |
return info.isInterface(); | |
} | |
/** | |
* @see IType#newSupertypeHierarchy(IProgressMonitor monitor) | |
*/ | |
public ITypeHierarchy newSupertypeHierarchy(IProgressMonitor monitor) throws JavaModelException { | |
CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(this, SearchEngine.createWorkspaceScope(), false); | |
runOperation(op, monitor); | |
return op.getResult(); | |
} | |
/** | |
* @see IType#newTypeHierarchy(IProgressMonitor monitor) | |
*/ | |
public ITypeHierarchy newTypeHierarchy(IProgressMonitor monitor) throws JavaModelException { | |
CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(this, SearchEngine.createWorkspaceScope(), true); | |
runOperation(op, monitor); | |
return op.getResult(); | |
} | |
/** | |
* @see IType#newTypeHierarchy(IJavaProject project, IProgressMonitor monitor) | |
*/ | |
public ITypeHierarchy newTypeHierarchy(IJavaProject project, IProgressMonitor monitor) throws JavaModelException { | |
if (project == null) { | |
throw new IllegalArgumentException(Util.bind("hierarchy.nullProject")); //$NON-NLS-1$ | |
} | |
CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation( | |
this, | |
SearchEngine.createJavaSearchScope(new IJavaElement[] {project}), | |
true); | |
runOperation(op, monitor); | |
return op.getResult(); | |
} | |
/** | |
* Removes all cached info from the Java Model, including all children, | |
* but does not close this element. | |
*/ | |
protected void removeInfo() { | |
Object info = fgJavaModelManager.peekAtInfo(this); | |
if (info != null) { | |
try { | |
IJavaElement[] children = getChildren(); | |
for (int i = 0, size = children.length; i < size; ++i) { | |
JavaElement child = (JavaElement) children[i]; | |
child.removeInfo(); | |
} | |
} catch (JavaModelException e) { | |
} | |
fgJavaModelManager.removeInfo(this); | |
try { | |
ClassFileInfo cfi = getClassFileInfo(); | |
cfi.removeBinaryChildren(); | |
} catch (JavaModelException npe) { | |
} | |
} | |
} | |
public String[][] resolveType(String typeName) throws JavaModelException { | |
// not implemented for binary types | |
return null; | |
} | |
/** | |
* @private Debugging purposes | |
*/ | |
protected void toStringInfo(int tab, StringBuffer buffer, Object info) { | |
buffer.append(this.tabString(tab)); | |
if (info == null) { | |
buffer.append(this.getElementName()); | |
buffer.append(" (not open)"); //$NON-NLS-1$ | |
} else if (info == NO_INFO) { | |
buffer.append(getElementName()); | |
} else { | |
try { | |
if (this.isInterface()) { | |
buffer.append("interface "); //$NON-NLS-1$ | |
} else { | |
buffer.append("class "); //$NON-NLS-1$ | |
} | |
buffer.append(this.getElementName()); | |
} catch (JavaModelException e) { | |
buffer.append("<JavaModelException in toString of " + getElementName()); //$NON-NLS-1$ | |
} | |
} | |
} | |
} |