/*******************************************************************************
* Copyright (c) 2000, 2009 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
*******************************************************************************/
package org.eclipse.jdt.internal.core;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.CompletionRequestor;
import org.eclipse.jdt.core.IBuffer;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.ICodeAssist;
import org.eclipse.jdt.core.ICodeCompletionRequestor;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.ICompletionRequestor;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaModelStatus;
import org.eclipse.jdt.core.IJavaModelStatusConstants;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IParent;
import org.eclipse.jdt.core.IProblemRequestor;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.ISourceReference;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaConventions;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.SourceRange;
import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.env.IDependent;
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
import org.eclipse.jdt.internal.core.util.MementoTokenizer;
import org.eclipse.jdt.internal.core.util.Util;
/**
* @see IClassFile
*/
public class ClassFile extends Openable implements IClassFile, SuffixConstants {
protected String name;
protected BinaryType binaryType= null;
/*
* Creates a handle to a class file.
*/
protected ClassFile(PackageFragment parent, String nameWithoutExtension) {
super(parent);
this.name= nameWithoutExtension;
}
/*
* @see IClassFile#becomeWorkingCopy(IProblemRequestor, WorkingCopyOwner, IProgressMonitor)
*/
public ICompilationUnit becomeWorkingCopy(IProblemRequestor problemRequestor, WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException {
JavaModelManager manager= JavaModelManager.getJavaModelManager();
CompilationUnit workingCopy= new ClassFileWorkingCopy(this, owner == null ? DefaultWorkingCopyOwner.PRIMARY : owner);
JavaModelManager.PerWorkingCopyInfo perWorkingCopyInfo= manager.getPerWorkingCopyInfo(workingCopy, false/*don't create*/, true /*record usage*/, null/*no problem requestor needed*/);
if (perWorkingCopyInfo == null) {
// close cu and its children
close();
BecomeWorkingCopyOperation operation= new BecomeWorkingCopyOperation(workingCopy, problemRequestor);
operation.runOperation(monitor);
return workingCopy;
}
return perWorkingCopyInfo.workingCopy;
}
/**
* Creates the children elements for this class file adding the resulting new handles and info
* objects to the newElements table. Returns true if successful, or false if an error is
* encountered parsing the class file.
*
* @see Openable
* @see Signature
*/
protected boolean buildStructure(OpenableElementInfo info, IProgressMonitor pm, Map newElements, IResource underlyingResource) throws JavaModelException {
IBinaryType typeInfo= getBinaryTypeInfo((IFile)underlyingResource);
if (typeInfo == null) {
// The structure of a class file is unknown if a class file format errors occurred
//during the creation of the diet class file representative of this ClassFile.
info.setChildren(new IJavaElement[] {});
return false;
}
// Make the type
IType type= getType();
info.setChildren(new IJavaElement[] { type });
newElements.put(type, typeInfo);
// Read children
((ClassFileInfo)info).readBinaryChildren(this, (HashMap)newElements, typeInfo);
return true;
}
/**
* @see ICodeAssist#codeComplete(int, ICompletionRequestor)
* @deprecated
*/
public void codeComplete(int offset, ICompletionRequestor requestor) throws JavaModelException {
codeComplete(offset, requestor, DefaultWorkingCopyOwner.PRIMARY);
}
/**
* @see ICodeAssist#codeComplete(int, ICompletionRequestor, WorkingCopyOwner)
* @deprecated
*/
public void codeComplete(int offset, ICompletionRequestor requestor, WorkingCopyOwner owner) throws JavaModelException {
if (requestor == null) {
throw new IllegalArgumentException("Completion requestor cannot be null"); //$NON-NLS-1$
}
codeComplete(offset, new org.eclipse.jdt.internal.codeassist.CompletionRequestorWrapper(requestor), owner);
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor)
*/
public void codeComplete(int offset, CompletionRequestor requestor) throws JavaModelException {
codeComplete(offset, requestor, DefaultWorkingCopyOwner.PRIMARY);
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor, org.eclipse.core.runtime.IProgressMonitor)
*/
public void codeComplete(int offset, CompletionRequestor requestor, IProgressMonitor monitor) throws JavaModelException {
codeComplete(offset, requestor, DefaultWorkingCopyOwner.PRIMARY, monitor);
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor, org.eclipse.jdt.core.WorkingCopyOwner)
*/
public void codeComplete(int offset, CompletionRequestor requestor, WorkingCopyOwner owner) throws JavaModelException {
codeComplete(offset, requestor, owner, null);
}
/* (non-Javadoc)
* @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor, org.eclipse.jdt.core.WorkingCopyOwner, org.eclipse.core.runtime.IProgressMonitor)
*/
public void codeComplete(int offset, CompletionRequestor requestor, WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException {
String source= getSource();
if (source != null) {
BinaryType type= (BinaryType)getType();
BasicCompilationUnit cu=
new BasicCompilationUnit(
getSource().toCharArray(),
null,
type.sourceFileName((IBinaryType)type.getElementInfo()),
getJavaProject()); // use project to retrieve corresponding .java IFile
codeComplete(cu, cu, offset, requestor, owner, null/*extended context isn't computed*/, monitor);
}
}
/**
* @see ICodeAssist#codeSelect(int, int)
*/
public IJavaElement[] codeSelect(int offset, int length) throws JavaModelException {
return codeSelect(offset, length, DefaultWorkingCopyOwner.PRIMARY);
}
/**
* @see ICodeAssist#codeSelect(int, int, WorkingCopyOwner)
*/
public IJavaElement[] codeSelect(int offset, int length, WorkingCopyOwner owner) throws JavaModelException {
IBuffer buffer= getBuffer();
char[] contents;
if (buffer != null && (contents= buffer.getCharacters()) != null) {
BinaryType type= (BinaryType)getType();
BasicCompilationUnit cu= new BasicCompilationUnit(contents, null, type.sourceFileName((IBinaryType)type.getElementInfo()));
return super.codeSelect(cu, offset, length, owner);
} else {
//has no associated souce
return new IJavaElement[] {};
}
}
/**
* Returns a new element info for this element.
*/
protected Object createElementInfo() {
return new ClassFileInfo();
}
public boolean equals(Object o) {
if (!(o instanceof ClassFile))
return false;
ClassFile other= (ClassFile)o;
return this.name.equals(other.name) && this.parent.equals(other.parent);
}
public boolean existsUsingJarTypeCache() {
if (getPackageFragmentRoot().isArchive()) {
JavaModelManager manager= JavaModelManager.getJavaModelManager();
IType type= getType();
Object info= manager.getInfo(type);
if (info == JavaModelCache.NON_EXISTING_JAR_TYPE_INFO)
return false;
else if (info != null)
return true;
// info is null
JavaElementInfo parentInfo= (JavaElementInfo)manager.getInfo(getParent());
if (parentInfo != null) {
// if parent is open, this class file must be in its children
IJavaElement[] children= parentInfo.getChildren();
for (int i= 0, length= children.length; i < length; i++) {
if (this.name.equals(((ClassFile)children[i]).name))
return true;
}
return false;
}
try {
info= getJarBinaryTypeInfo((PackageFragment)getParent(), true/*fully initialize so as to not keep a reference to the byte array*/);
} catch (CoreException e) {
// leave info null
} catch (IOException e) {
// leave info null
} catch (ClassFormatException e) {
// leave info null
}
manager.putJarTypeInfo(type, info == null ? JavaModelCache.NON_EXISTING_JAR_TYPE_INFO : info);
return info != null;
} else
return exists();
}
/**
* Finds the deepest <code>IJavaElement</code> in the hierarchy of
* <code>elt</elt>'s children (including <code>elt</code> itself) which has a source range that
* encloses <code>position</code> according to <code>mapper</code>.
*/
protected IJavaElement findElement(IJavaElement elt, int position, SourceMapper mapper) {
SourceRange range= mapper.getSourceRange(elt);
if (range == null || position < range.getOffset() || range.getOffset() + range.getLength() - 1 < position) {
return null;
}
if (elt instanceof IParent) {
try {
IJavaElement[] children= ((IParent)elt).getChildren();
for (int i= 0; i < children.length; i++) {
IJavaElement match= findElement(children[i], position, mapper);
if (match != null) {
return match;
}
}
} catch (JavaModelException npe) {
// elt doesn't exist: return the element
}
}
return elt;
}
/**
* @see ITypeRoot#findPrimaryType()
*/
public IType findPrimaryType() {
IType primaryType= getType();
if (primaryType.exists()) {
return primaryType;
}
return null;
}
public String getAttachedJavadoc(IProgressMonitor monitor) throws JavaModelException {
return getType().getAttachedJavadoc(monitor);
}
/**
* Returns the <code>ClassFileReader</code>specific for this IClassFile, based on its underlying
* resource, or <code>null</code> if unable to create the diet class file. There are two cases
* to consider:
* <ul>
* <li>a class file corresponding to an IFile resource</li>
* <li>a class file corresponding to a zip entry in a JAR</li>
* </ul>
*
* @exception JavaModelException when the IFile resource or JAR is not available or when this
* class file is not present in the JAR
*/
public IBinaryType getBinaryTypeInfo(IFile file) throws JavaModelException {
return getBinaryTypeInfo(file, true/*fully initialize so as to not keep a reference to the byte array*/);
}
public IBinaryType getBinaryTypeInfo(IFile file, boolean fullyInitialize) throws JavaModelException {
JavaElement pkg= (JavaElement)getParent();
if (pkg instanceof JarPackageFragment) {
try {
IBinaryType info= getJarBinaryTypeInfo((PackageFragment)pkg, fullyInitialize);
if (info == null) {
throw newNotPresentException();
}
return info;
} catch (ClassFormatException cfe) {
//the structure remains unknown
if (JavaCore.getPlugin().isDebugging()) {
cfe.printStackTrace(System.err);
}
return null;
} catch (IOException ioe) {
throw new JavaModelException(ioe, IJavaModelStatusConstants.IO_EXCEPTION);
} catch (CoreException e) {
if (e instanceof JavaModelException) {
throw (JavaModelException)e;
} else {
throw new JavaModelException(e);
}
}
} else {
byte[] contents= Util.getResourceContentsAsByteArray(file);
try {
return new ClassFileReader(contents, file.getFullPath().toString().toCharArray(), fullyInitialize);
} catch (ClassFormatException cfe) {
//the structure remains unknown
return null;
}
}
}
public byte[] getBytes() throws JavaModelException {
JavaElement pkg= (JavaElement)getParent();
if (pkg instanceof JarPackageFragment) {
JarPackageFragmentRoot root= (JarPackageFragmentRoot)pkg.getParent();
ZipFile zip= null;
try {
zip= root.getJar();
String entryName= Util.concatWith(((PackageFragment)pkg).names, getElementName(), '/');
ZipEntry ze= zip.getEntry(entryName);
if (ze != null) {
return org.eclipse.jdt.internal.compiler.util.Util.getZipEntryByteContent(ze, zip);
}
throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
} catch (IOException ioe) {
throw new JavaModelException(ioe, IJavaModelStatusConstants.IO_EXCEPTION);
} catch (CoreException e) {
if (e instanceof JavaModelException) {
throw (JavaModelException)e;
} else {
throw new JavaModelException(e);
}
} finally {
JavaModelManager.getJavaModelManager().closeZipFile(zip);
}
} else {
IFile file= (IFile)resource();
return Util.getResourceContentsAsByteArray(file);
}
}
private IBinaryType getJarBinaryTypeInfo(PackageFragment pkg, boolean fullyInitialize) throws CoreException, IOException, ClassFormatException {
JarPackageFragmentRoot root= (JarPackageFragmentRoot)pkg.getParent();
ZipFile zip= null;
try {
zip= root.getJar();
String entryName= Util.concatWith(pkg.names, getElementName(), '/');
ZipEntry ze= zip.getEntry(entryName);
if (ze != null) {
byte contents[]= org.eclipse.jdt.internal.compiler.util.Util.getZipEntryByteContent(ze, zip);
String fileName= root.getHandleIdentifier() + IDependent.JAR_FILE_ENTRY_SEPARATOR + entryName;
return new ClassFileReader(contents, fileName.toCharArray(), fullyInitialize);
}
} finally {
JavaModelManager.getJavaModelManager().closeZipFile(zip);
}
return null;
}
public IBuffer getBuffer() throws JavaModelException {
IStatus status= validateClassFile();
if (status.isOK()) {
return super.getBuffer();
} else {
// .class file not on classpath, create a new buffer to be nice (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=41444)
Object info= ((ClassFile)getClassFile()).getBinaryTypeInfo((IFile)resource());
IBuffer buffer= openBuffer(null, info);
if (buffer != null && !(buffer instanceof NullBuffer))
return buffer;
switch (status.getCode()) {
case IJavaModelStatusConstants.ELEMENT_NOT_ON_CLASSPATH: // don't throw a JavaModelException to be able to open .class file outside the classpath (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=138507 )
case IJavaModelStatusConstants.INVALID_ELEMENT_TYPES: // don't throw a JavaModelException to be able to open .class file in proj==src case without source (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=221904 )
return null;
default:
throw new JavaModelException((IJavaModelStatus)status);
}
}
}
/**
* @see IMember
*/
public IClassFile getClassFile() {
return this;
}
/**
* @see IMember#getTypeRoot()
*/
public ITypeRoot getTypeRoot() {
return this;
}
/**
* A class file has a corresponding resource unless it is contained in a jar.
*
* @see IJavaElement
*/
public IResource getCorrespondingResource() throws JavaModelException {
IPackageFragmentRoot root= (IPackageFragmentRoot)getParent().getParent();
if (root.isArchive()) {
return null;
} else {
return getUnderlyingResource();
}
}
/**
* @see IClassFile
*/
public IJavaElement getElementAt(int position) throws JavaModelException {
IJavaElement parentElement= getParent();
while (parentElement.getElementType() != IJavaElement.PACKAGE_FRAGMENT_ROOT) {
parentElement= parentElement.getParent();
}
PackageFragmentRoot root= (PackageFragmentRoot)parentElement;
SourceMapper mapper= root.getSourceMapper();
if (mapper == null) {
return null;
} else {
// ensure this class file's buffer is open so that source ranges are computed
getBuffer();
IType type= getType();
return findElement(type, position, mapper);
}
}
public IJavaElement getElementAtConsideringSibling(int position) throws JavaModelException {
IPackageFragment fragment= (IPackageFragment)getParent();
PackageFragmentRoot root= (PackageFragmentRoot)fragment.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
SourceMapper mapper= root.getSourceMapper();
if (mapper == null) {
return null;
} else {
int index= this.name.indexOf('$');
int prefixLength= index < 0 ? this.name.length() : index;
IType type= null;
int start= -1;
int end= Integer.MAX_VALUE;
IJavaElement[] children= fragment.getChildren();
for (int i= 0; i < children.length; i++) {
String childName= children[i].getElementName();
int childIndex= childName.indexOf('$');
int childPrefixLength= childIndex < 0 ? childName.indexOf('.') : childIndex;
if (prefixLength == childPrefixLength && this.name.regionMatches(0, childName, 0, prefixLength)) {
IClassFile classFile= (IClassFile)children[i];
// ensure this class file's buffer is open so that source ranges are computed
classFile.getBuffer();
SourceRange range= mapper.getSourceRange(classFile.getType());
if (range == SourceMapper.UNKNOWN_RANGE)
continue;
int newStart= range.getOffset();
int newEnd= newStart + range.getLength() - 1;
if (newStart > start && newEnd < end
&& newStart <= position && newEnd >= position) {
type= classFile.getType();
start= newStart;
end= newEnd;
}
}
}
if (type != null) {
return findElement(type, position, mapper);
}
return null;
}
}
public String getElementName() {
return this.name + SuffixConstants.SUFFIX_STRING_class;
}
/**
* @see IJavaElement
*/
public int getElementType() {
return CLASS_FILE;
}
/*
* @see JavaElement
*/
public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner owner) {
switch (token.charAt(0)) {
case JEM_TYPE:
if (!memento.hasMoreTokens())
return this;
String typeName= memento.nextToken();
JavaElement type= new BinaryType(this, typeName);
return type.getHandleFromMemento(memento, owner);
}
return null;
}
/**
* @see JavaElement#getHandleMemento()
*/
protected char getHandleMementoDelimiter() {
return JavaElement.JEM_CLASSFILE;
}
/*
* @see IJavaElement
*/
public IPath getPath() {
PackageFragmentRoot root= getPackageFragmentRoot();
if (root.isArchive()) {
return root.getPath();
} else {
return getParent().getPath().append(getElementName());
}
}
/*
* @see IJavaElement
*/
public IResource resource(PackageFragmentRoot root) {
return ((IContainer)((Openable)this.parent).resource(root)).getFile(new Path(getElementName()));
}
/**
* @see ISourceReference
*/
public String getSource() throws JavaModelException {
IBuffer buffer= getBuffer();
if (buffer == null) {
return null;
}
return buffer.getContents();
}
/**
* @see ISourceReference
*/
public ISourceRange getSourceRange() throws JavaModelException {
IBuffer buffer= getBuffer();
if (buffer != null) {
String contents= buffer.getContents();
if (contents == null)
return null;
return new SourceRange(0, contents.length());
} else {
return null;
}
}
/*
* Returns the name of the toplevel type of this class file.
*/
public String getTopLevelTypeName() {
String topLevelTypeName= getElementName();
int firstDollar= topLevelTypeName.indexOf('$');
if (firstDollar != -1) {
topLevelTypeName= topLevelTypeName.substring(0, firstDollar);
} else {
topLevelTypeName= topLevelTypeName.substring(0, topLevelTypeName.length() - SUFFIX_CLASS.length);
}
return topLevelTypeName;
}
/**
* @see IClassFile
*/
public IType getType() {
if (this.binaryType == null) {
this.binaryType= new BinaryType(this, getTypeName());
}
return this.binaryType;
}
public String getTypeName() {
// Internal class file name doesn't contain ".class" file extension
int lastDollar= this.name.lastIndexOf('$');
return lastDollar > -1 ? Util.localTypeName(this.name, lastDollar, this.name.length()) : this.name;
}
/*
* @see IClassFile
*/
public ICompilationUnit getWorkingCopy(WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException {
CompilationUnit workingCopy= new ClassFileWorkingCopy(this, owner == null ? DefaultWorkingCopyOwner.PRIMARY : owner);
JavaModelManager manager= JavaModelManager.getJavaModelManager();
JavaModelManager.PerWorkingCopyInfo perWorkingCopyInfo=
manager.getPerWorkingCopyInfo(workingCopy, false/*don't create*/, true/*record usage*/, null/*not used since don't create*/);
if (perWorkingCopyInfo != null) {
return perWorkingCopyInfo.getWorkingCopy(); // return existing handle instead of the one created above
}
BecomeWorkingCopyOperation op= new BecomeWorkingCopyOperation(workingCopy, null);
op.runOperation(monitor);
return workingCopy;
}
/**
* @see IClassFile
* @deprecated
*/
public IJavaElement getWorkingCopy(IProgressMonitor monitor, org.eclipse.jdt.core.IBufferFactory factory) throws JavaModelException {
return getWorkingCopy(BufferFactoryWrapper.create(factory), monitor);
}
/**
* @see Openable
*/
protected boolean hasBuffer() {
return true;
}
public int hashCode() {
return Util.combineHashCodes(this.name.hashCode(), this.parent.hashCode());
}
/**
* @see IClassFile
*/
public boolean isClass() throws JavaModelException {
return getType().isClass();
}
/**
* @see IClassFile
*/
public boolean isInterface() throws JavaModelException {
return getType().isInterface();
}
/**
* Returns true - class files are always read only.
*/
public boolean isReadOnly() {
return true;
}
private IStatus validateClassFile() {
IPackageFragmentRoot root= getPackageFragmentRoot();
try {
if (root.getKind() != IPackageFragmentRoot.K_BINARY)
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, root);
} catch (JavaModelException e) {
return e.getJavaModelStatus();
}
IJavaProject project= getJavaProject();
return JavaConventions.validateClassFileName(getElementName(), project.getOption(JavaCore.COMPILER_SOURCE, true), project.getOption(JavaCore.COMPILER_COMPLIANCE, true));
}
/**
* Opens and returns buffer on the source code associated with this class file. Maps the source
* code to the children elements of this class file. If no source code is associated with this
* class file, <code>null</code> is returned.
*
* @see Openable
*/
protected IBuffer openBuffer(IProgressMonitor pm, Object info) throws JavaModelException {
// Check the cache for the top-level type first
IType outerMostEnclosingType= getOuterMostEnclosingType();
IBuffer buffer= getBufferManager().getBuffer(outerMostEnclosingType.getClassFile());
if (buffer == null) {
SourceMapper mapper= getSourceMapper();
IBinaryType typeInfo= info instanceof IBinaryType ? (IBinaryType)info : null;
if (mapper != null) {
buffer= mapSource(mapper, typeInfo, outerMostEnclosingType.getClassFile());
}
}
return buffer;
}
/** Loads the buffer via SourceMapper, and maps it in SourceMapper */
private IBuffer mapSource(SourceMapper mapper, IBinaryType info, IClassFile bufferOwner) {
char[] contents= mapper.findSource(getType(), info);
if (contents != null) {
// create buffer
IBuffer buffer= BufferManager.createBuffer(bufferOwner);
if (buffer == null)
return null;
BufferManager bufManager= getBufferManager();
bufManager.addBuffer(buffer);
// set the buffer source
if (buffer.getCharacters() == null) {
buffer.setContents(contents);
}
// listen to buffer changes
buffer.addBufferChangedListener(this);
// do the source mapping
mapper.mapSource(getOuterMostEnclosingType(), contents, info);
return buffer;
} else {
// create buffer
IBuffer buffer= BufferManager.createNullBuffer(bufferOwner);
if (buffer == null)
return null;
BufferManager bufManager= getBufferManager();
bufManager.addBuffer(buffer);
// listen to buffer changes
buffer.addBufferChangedListener(this);
return buffer;
}
}
/* package */static String simpleName(char[] className) {
if (className == null)
return null;
String simpleName= new String(unqualifiedName(className));
int lastDollar= simpleName.lastIndexOf('$');
if (lastDollar != -1)
return Util.localTypeName(simpleName, lastDollar, simpleName.length());
else
return simpleName;
}
/** Returns the type of the top-level declaring class used to find the source code */
private IType getOuterMostEnclosingType() {
IType type= getType();
IType enclosingType= type.getDeclaringType();
while (enclosingType != null) {
type= enclosingType;
enclosingType= type.getDeclaringType();
}
return type;
}
/**
* Returns the Java Model representation of the given name which is provided in diet class file
* format, or <code>null</code> if the given name is <code>null</code>.
*
* <p>
* <code>ClassFileReader</code> format is similar to "java/lang/Object", and corresponding Java
* Model format is "java.lang.Object".
*/
public static char[] translatedName(char[] name) {
if (name == null)
return null;
int nameLength= name.length;
char[] newName= new char[nameLength];
for (int i= 0; i < nameLength; i++) {
if (name[i] == '/') {
newName[i]= '.';
} else {
newName[i]= name[i];
}
}
return newName;
}
/**
* Returns the Java Model representation of the given names which are provided in diet class
* file format, or <code>null</code> if the given names are <code>null</code>.
*
* <p>
* <code>ClassFileReader</code> format is similar to "java/lang/Object", and corresponding Java
* Model format is "java.lang.Object".
*/
/* package */static char[][] translatedNames(char[][] names) {
if (names == null)
return null;
int length= names.length;
char[][] newNames= new char[length][];
for (int i= 0; i < length; i++) {
newNames[i]= translatedName(names[i]);
}
return newNames;
}
/**
* Returns the Java Model format of the unqualified class name for the given className which is
* provided in diet class file format, or <code>null</code> if the given className is
* <code>null</code>. (This removes the package name, but not enclosing type names).
*
* <p>
* <code>ClassFileReader</code> format is similar to "java/lang/Object", and corresponding Java
* Model simple name format is "Object".
*/
/* package */static char[] unqualifiedName(char[] className) {
if (className == null)
return null;
int count= 0;
for (int i= className.length - 1; i > -1; i--) {
if (className[i] == '/') {
char[] name= new char[count];
System.arraycopy(className, i + 1, name, 0, count);
return name;
}
count++;
}
return className;
}
/**
* @see ICodeAssist#codeComplete(int, ICodeCompletionRequestor)
* @deprecated - should use codeComplete(int, ICompletionRequestor) instead
*/
public void codeComplete(int offset, final org.eclipse.jdt.core.ICodeCompletionRequestor requestor) throws JavaModelException {
if (requestor == null) {
codeComplete(offset, (ICompletionRequestor)null);
return;
}
codeComplete(
offset,
new ICompletionRequestor() {
public void acceptAnonymousType(char[] superTypePackageName, char[] superTypeName, char[][] parameterPackageNames, char[][] parameterTypeNames, char[][] parameterNames,
char[] completionName, int modifiers, int completionStart, int completionEnd, int relevance) {
// ignore
}
public void acceptClass(char[] packageName, char[] className, char[] completionName, int modifiers, int completionStart, int completionEnd, int relevance) {
requestor.acceptClass(packageName, className, completionName, modifiers, completionStart, completionEnd);
}
public void acceptError(IProblem error) {
// was disabled in 1.0
}
public void acceptField(char[] declaringTypePackageName, char[] declaringTypeName, char[] fieldName, char[] typePackageName, char[] typeName, char[] completionName, int modifiers,
int completionStart, int completionEnd, int relevance) {
requestor.acceptField(declaringTypePackageName, declaringTypeName, fieldName, typePackageName, typeName, completionName, modifiers, completionStart, completionEnd);
}
public void acceptInterface(char[] packageName, char[] interfaceName, char[] completionName, int modifiers, int completionStart, int completionEnd, int relevance) {
requestor.acceptInterface(packageName, interfaceName, completionName, modifiers, completionStart, completionEnd);
}
public void acceptKeyword(char[] keywordName, int completionStart, int completionEnd, int relevance) {
requestor.acceptKeyword(keywordName, completionStart, completionEnd);
}
public void acceptLabel(char[] labelName, int completionStart, int completionEnd, int relevance) {
requestor.acceptLabel(labelName, completionStart, completionEnd);
}
public void acceptLocalVariable(char[] localVarName, char[] typePackageName, char[] typeName, int modifiers, int completionStart, int completionEnd, int relevance) {
// ignore
}
public void acceptMethod(char[] declaringTypePackageName, char[] declaringTypeName, char[] selector, char[][] parameterPackageNames, char[][] parameterTypeNames,
char[][] parameterNames, char[] returnTypePackageName, char[] returnTypeName, char[] completionName, int modifiers, int completionStart, int completionEnd, int relevance) {
// skip parameter names
requestor.acceptMethod(declaringTypePackageName, declaringTypeName, selector, parameterPackageNames, parameterTypeNames, returnTypePackageName, returnTypeName, completionName,
modifiers, completionStart, completionEnd);
}
public void acceptMethodDeclaration(char[] declaringTypePackageName, char[] declaringTypeName, char[] selector, char[][] parameterPackageNames, char[][] parameterTypeNames,
char[][] parameterNames, char[] returnTypePackageName, char[] returnTypeName, char[] completionName, int modifiers, int completionStart, int completionEnd, int relevance) {
// ignore
}
public void acceptModifier(char[] modifierName, int completionStart, int completionEnd, int relevance) {
requestor.acceptModifier(modifierName, completionStart, completionEnd);
}
public void acceptPackage(char[] packageName, char[] completionName, int completionStart, int completionEnd, int relevance) {
requestor.acceptPackage(packageName, completionName, completionStart, completionEnd);
}
public void acceptType(char[] packageName, char[] typeName, char[] completionName, int completionStart, int completionEnd, int relevance) {
requestor.acceptType(packageName, typeName, completionName, completionStart, completionEnd);
}
public void acceptVariableName(char[] typePackageName, char[] typeName, char[] varName, char[] completionName, int completionStart, int completionEnd, int relevance) {
// ignore
}
});
}
protected IStatus validateExistence(IResource underlyingResource) {
// check whether the class file can be opened
IStatus status= validateClassFile();
if (!status.isOK())
return status;
if (underlyingResource != null) {
if (!underlyingResource.isAccessible())
return newDoesNotExistStatus();
PackageFragmentRoot root;
if ((underlyingResource instanceof IFolder) && (root= getPackageFragmentRoot()).isArchive()) { // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=204652
return root.newDoesNotExistStatus();
}
}
return JavaModelStatus.VERIFIED_OK;
}
}