blob: ceb44c42275da7cd460b1a52d63a43c307fd038a [file] [log] [blame]
Stephan Herrmann7b7062f2010-04-01 19:56:59 +00001/*******************************************************************************
Stephan Herrmann0363ef22013-02-02 16:22:13 +01002 * Copyright (c) 2000, 2013 IBM Corporation and others.
Stephan Herrmann7b7062f2010-04-01 19:56:59 +00003 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 * $Id: ClassFile.java 23401 2010-02-02 23:56:05Z stephan $
8 *
9 * Contributors:
10 * IBM Corporation - initial API and implementation
11 * Fraunhofer FIRST - extended API and implementation
12 * Technical University Berlin - extended API and implementation
13 *******************************************************************************/
14package org.eclipse.jdt.internal.core;
15
16import java.io.IOException;
17import java.util.HashMap;
18import java.util.Map;
19import java.util.zip.ZipEntry;
20import java.util.zip.ZipFile;
21
22import org.eclipse.core.resources.IContainer;
23import org.eclipse.core.resources.IFile;
24import org.eclipse.core.resources.IFolder;
25import org.eclipse.core.resources.IResource;
26import org.eclipse.core.runtime.CoreException;
27import org.eclipse.core.runtime.IPath;
28import org.eclipse.core.runtime.IProgressMonitor;
29import org.eclipse.core.runtime.IStatus;
30import org.eclipse.core.runtime.Path;
31import org.eclipse.jdt.core.*;
32import org.eclipse.jdt.core.compiler.IProblem;
33import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
34import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
35import org.eclipse.jdt.internal.compiler.env.IBinaryType;
36import org.eclipse.jdt.internal.compiler.env.IDependent;
37import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
38import org.eclipse.jdt.internal.core.util.MementoTokenizer;
39import org.eclipse.jdt.internal.core.util.Util;
40import org.eclipse.objectteams.otdt.core.OTModelManager;
41
42/**
43 * @see IClassFile
44 */
45
Stephan Herrmann1002fa42013-12-17 17:50:02 +010046@SuppressWarnings({"rawtypes"})
Stephan Herrmann7b7062f2010-04-01 19:56:59 +000047public class ClassFile extends Openable implements IClassFile, SuffixConstants {
48
49 protected String name;
50 protected BinaryType binaryType = null;
51
52/*
53 * Creates a handle to a class file.
54 */
55protected ClassFile(PackageFragment parent, String nameWithoutExtension) {
56 super(parent);
57 this.name = nameWithoutExtension;
58}
59
60/*
61 * @see IClassFile#becomeWorkingCopy(IProblemRequestor, WorkingCopyOwner, IProgressMonitor)
62 */
63public ICompilationUnit becomeWorkingCopy(IProblemRequestor problemRequestor, WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException {
64 JavaModelManager manager = JavaModelManager.getJavaModelManager();
65 CompilationUnit workingCopy = new ClassFileWorkingCopy(this, owner == null ? DefaultWorkingCopyOwner.PRIMARY : owner);
66 JavaModelManager.PerWorkingCopyInfo perWorkingCopyInfo = manager.getPerWorkingCopyInfo(workingCopy, false/*don't create*/, true /*record usage*/, null/*no problem requestor needed*/);
67 if (perWorkingCopyInfo == null) {
68 // close cu and its children
69 close();
70
71 BecomeWorkingCopyOperation operation = new BecomeWorkingCopyOperation(workingCopy, problemRequestor);
72 operation.runOperation(monitor);
73
74 return workingCopy;
75 }
76 return perWorkingCopyInfo.workingCopy;
77}
78
79/**
80 * Creates the children elements for this class file adding the resulting
81 * new handles and info objects to the newElements table. Returns true
82 * if successful, or false if an error is encountered parsing the class file.
83 *
84 * @see Openable
85 * @see Signature
86 */
87protected boolean buildStructure(OpenableElementInfo info, IProgressMonitor pm, Map newElements, IResource underlyingResource) throws JavaModelException {
88 IBinaryType typeInfo = getBinaryTypeInfo((IFile) underlyingResource);
89 if (typeInfo == null) {
90 // The structure of a class file is unknown if a class file format errors occurred
91 //during the creation of the diet class file representative of this ClassFile.
92 info.setChildren(new IJavaElement[] {});
93 return false;
94 }
95
96 // Make the type
97//{ObjectTeams: pass the enclosing name and register ot types:
98/* orig:
99 IType type = getType();
100 :giro */
101 IType type = getType(typeInfo.getEnclosingTypeName());
102 // make it known to the OTModelManager (without opening):
103 OTModelManager.getSharedInstance().addUnopenedType(type);
104// SH}
105
106 info.setChildren(new IJavaElement[] {type});
107 newElements.put(type, typeInfo);
108
109 // Read children
110 ((ClassFileInfo) info).readBinaryChildren(this, (HashMap) newElements, typeInfo);
111
112 return true;
113}
114/**
115 * @see ICodeAssist#codeComplete(int, ICompletionRequestor)
116 * @deprecated
117 */
118public void codeComplete(int offset, ICompletionRequestor requestor) throws JavaModelException {
119 codeComplete(offset, requestor, DefaultWorkingCopyOwner.PRIMARY);
120}
121/**
122 * @see ICodeAssist#codeComplete(int, ICompletionRequestor, WorkingCopyOwner)
123 * @deprecated
124 */
125public void codeComplete(int offset, ICompletionRequestor requestor, WorkingCopyOwner owner) throws JavaModelException {
126 if (requestor == null) {
127 throw new IllegalArgumentException("Completion requestor cannot be null"); //$NON-NLS-1$
128 }
129 codeComplete(offset, new org.eclipse.jdt.internal.codeassist.CompletionRequestorWrapper(requestor), owner);
130}
131
132/* (non-Javadoc)
133 * @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor)
134 */
135public void codeComplete(int offset, CompletionRequestor requestor) throws JavaModelException {
136 codeComplete(offset, requestor, DefaultWorkingCopyOwner.PRIMARY);
137}
138/* (non-Javadoc)
139 * @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor, org.eclipse.core.runtime.IProgressMonitor)
140 */
141public void codeComplete(int offset, CompletionRequestor requestor, IProgressMonitor monitor) throws JavaModelException {
142 codeComplete(offset, requestor, DefaultWorkingCopyOwner.PRIMARY, monitor);
143}
144/* (non-Javadoc)
145 * @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor, org.eclipse.jdt.core.WorkingCopyOwner)
146 */
147public void codeComplete(int offset, CompletionRequestor requestor, WorkingCopyOwner owner) throws JavaModelException {
148 codeComplete(offset, requestor, owner, null);
149}
150/* (non-Javadoc)
151 * @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor, org.eclipse.jdt.core.WorkingCopyOwner, org.eclipse.core.runtime.IProgressMonitor)
152 */
153public void codeComplete(int offset, CompletionRequestor requestor, WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException {
154 String source = getSource();
155 if (source != null) {
156 BinaryType type = (BinaryType) getType();
157 BasicCompilationUnit cu =
158 new BasicCompilationUnit(
159 getSource().toCharArray(),
160 null,
161 type.sourceFileName((IBinaryType) type.getElementInfo()),
162 getJavaProject()); // use project to retrieve corresponding .java IFile
163 codeComplete(cu, cu, offset, requestor, owner, null/*extended context isn't computed*/, monitor);
164 }
165}
166
167/**
168 * @see ICodeAssist#codeSelect(int, int)
169 */
170public IJavaElement[] codeSelect(int offset, int length) throws JavaModelException {
171 return codeSelect(offset, length, DefaultWorkingCopyOwner.PRIMARY);
172}
173/**
174 * @see ICodeAssist#codeSelect(int, int, WorkingCopyOwner)
175 */
176public IJavaElement[] codeSelect(int offset, int length, WorkingCopyOwner owner) throws JavaModelException {
177 IBuffer buffer = getBuffer();
178 char[] contents;
179 if (buffer != null && (contents = buffer.getCharacters()) != null) {
180 BinaryType type = (BinaryType) getType();
181 BasicCompilationUnit cu = new BasicCompilationUnit(contents, null, type.sourceFileName((IBinaryType) type.getElementInfo()));
182 return super.codeSelect(cu, offset, length, owner);
183 } else {
184 //has no associated souce
185 return new IJavaElement[] {};
186 }
187}
188/**
189 * Returns a new element info for this element.
190 */
191protected Object createElementInfo() {
192 return new ClassFileInfo();
193}
194public boolean equals(Object o) {
195 if (!(o instanceof ClassFile)) return false;
196 ClassFile other = (ClassFile) o;
197 return this.name.equals(other.name) && this.parent.equals(other.parent);
198}
199public boolean existsUsingJarTypeCache() {
200 if (getPackageFragmentRoot().isArchive()) {
201 JavaModelManager manager = JavaModelManager.getJavaModelManager();
202 IType type = getType();
203 Object info = manager.getInfo(type);
204 if (info == JavaModelCache.NON_EXISTING_JAR_TYPE_INFO)
205 return false;
206 else if (info != null)
207 return true;
208 // info is null
209 JavaElementInfo parentInfo = (JavaElementInfo) manager.getInfo(getParent());
210 if (parentInfo != null) {
211 // if parent is open, this class file must be in its children
212 IJavaElement[] children = parentInfo.getChildren();
213 for (int i = 0, length = children.length; i < length; i++) {
214 if (this.name.equals(((ClassFile) children[i]).name))
215 return true;
216 }
217 return false;
218 }
219 try {
220 info = getJarBinaryTypeInfo((PackageFragment) getParent(), true/*fully initialize so as to not keep a reference to the byte array*/);
221 } catch (CoreException e) {
222 // leave info null
223 } catch (IOException e) {
224 // leave info null
225 } catch (ClassFormatException e) {
226 // leave info null
227 }
228 manager.putJarTypeInfo(type, info == null ? JavaModelCache.NON_EXISTING_JAR_TYPE_INFO : info);
229 return info != null;
230 } else
231 return exists();
232}
233
234/**
235 * Finds the deepest <code>IJavaElement</code> in the hierarchy of
236 * <code>elt</elt>'s children (including <code>elt</code> itself)
237 * which has a source range that encloses <code>position</code>
238 * according to <code>mapper</code>.
239 */
240protected IJavaElement findElement(IJavaElement elt, int position, SourceMapper mapper) {
241 SourceRange range = mapper.getSourceRange(elt);
242 if (range == null || position < range.getOffset() || range.getOffset() + range.getLength() - 1 < position) {
243 return null;
244 }
245 if (elt instanceof IParent) {
246 try {
247 IJavaElement[] children = ((IParent) elt).getChildren();
248 for (int i = 0; i < children.length; i++) {
249 IJavaElement match = findElement(children[i], position, mapper);
250 if (match != null) {
251 return match;
252 }
253 }
254 } catch (JavaModelException npe) {
255 // elt doesn't exist: return the element
256 }
257 }
258 return elt;
259}
260/**
261 * @see ITypeRoot#findPrimaryType()
262 */
263public IType findPrimaryType() {
264 IType primaryType= getType();
265 if (primaryType.exists()) {
266 return primaryType;
267 }
268 return null;
269}
270public String getAttachedJavadoc(IProgressMonitor monitor) throws JavaModelException {
271 return getType().getAttachedJavadoc(monitor);
272}
273/**
274 * Returns the <code>ClassFileReader</code>specific for this IClassFile, based
275 * on its underlying resource, or <code>null</code> if unable to create
276 * the diet class file.
277 * There are two cases to consider:<ul>
278 * <li>a class file corresponding to an IFile resource</li>
279 * <li>a class file corresponding to a zip entry in a JAR</li>
280 * </ul>
281 *
282 * @exception JavaModelException when the IFile resource or JAR is not available
283 * or when this class file is not present in the JAR
284 */
285public IBinaryType getBinaryTypeInfo(IFile file) throws JavaModelException {
286 return getBinaryTypeInfo(file, true/*fully initialize so as to not keep a reference to the byte array*/);
287}
288public IBinaryType getBinaryTypeInfo(IFile file, boolean fullyInitialize) throws JavaModelException {
289 JavaElement pkg = (JavaElement) getParent();
290 if (pkg instanceof JarPackageFragment) {
291 try {
292 IBinaryType info = getJarBinaryTypeInfo((PackageFragment) pkg, fullyInitialize);
293 if (info == null) {
294 throw newNotPresentException();
295 }
296 return info;
297 } catch (ClassFormatException cfe) {
298 //the structure remains unknown
299 if (JavaCore.getPlugin().isDebugging()) {
300 cfe.printStackTrace(System.err);
301 }
302 return null;
303 } catch (IOException ioe) {
304 throw new JavaModelException(ioe, IJavaModelStatusConstants.IO_EXCEPTION);
305 } catch (CoreException e) {
306 if (e instanceof JavaModelException) {
307 throw (JavaModelException)e;
308 } else {
309 throw new JavaModelException(e);
310 }
311 }
312 } else {
313 byte[] contents = Util.getResourceContentsAsByteArray(file);
314 try {
315 return new ClassFileReader(contents, file.getFullPath().toString().toCharArray(), fullyInitialize);
316 } catch (ClassFormatException cfe) {
317 //the structure remains unknown
318 return null;
319 }
320 }
321}
322
323public byte[] getBytes() throws JavaModelException {
324 JavaElement pkg = (JavaElement) getParent();
325 if (pkg instanceof JarPackageFragment) {
326 JarPackageFragmentRoot root = (JarPackageFragmentRoot) pkg.getParent();
327 ZipFile zip = null;
328 try {
329 zip = root.getJar();
330 String entryName = Util.concatWith(((PackageFragment) pkg).names, getElementName(), '/');
331 ZipEntry ze = zip.getEntry(entryName);
332 if (ze != null) {
333 return org.eclipse.jdt.internal.compiler.util.Util.getZipEntryByteContent(ze, zip);
334 }
335 throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
336 } catch (IOException ioe) {
337 throw new JavaModelException(ioe, IJavaModelStatusConstants.IO_EXCEPTION);
338 } catch (CoreException e) {
339 if (e instanceof JavaModelException) {
340 throw (JavaModelException)e;
341 } else {
342 throw new JavaModelException(e);
343 }
344 } finally {
345 JavaModelManager.getJavaModelManager().closeZipFile(zip);
346 }
347 } else {
348 IFile file = (IFile) resource();
349 return Util.getResourceContentsAsByteArray(file);
350 }
351}
352private IBinaryType getJarBinaryTypeInfo(PackageFragment pkg, boolean fullyInitialize) throws CoreException, IOException, ClassFormatException {
353 JarPackageFragmentRoot root = (JarPackageFragmentRoot) pkg.getParent();
354 ZipFile zip = null;
355 try {
356 zip = root.getJar();
357 String entryName = Util.concatWith(pkg.names, getElementName(), '/');
358 ZipEntry ze = zip.getEntry(entryName);
359 if (ze != null) {
360 byte contents[] = org.eclipse.jdt.internal.compiler.util.Util.getZipEntryByteContent(ze, zip);
361 String fileName = root.getHandleIdentifier() + IDependent.JAR_FILE_ENTRY_SEPARATOR + entryName;
362 return new ClassFileReader(contents, fileName.toCharArray(), fullyInitialize);
363 }
364 } finally {
365 JavaModelManager.getJavaModelManager().closeZipFile(zip);
366 }
367 return null;
368}
369public IBuffer getBuffer() throws JavaModelException {
370 IStatus status = validateClassFile();
371 if (status.isOK()) {
372 return super.getBuffer();
373 } else {
Stephan Herrmann7b7062f2010-04-01 19:56:59 +0000374 switch (status.getCode()) {
375 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 )
376 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 )
377 return null;
378 default:
379 throw new JavaModelException((IJavaModelStatus) status);
380 }
381 }
382}
383/**
384 * @see IMember
385 */
386public IClassFile getClassFile() {
387 return this;
388}
389/**
390 * @see IMember#getTypeRoot()
391 */
392public ITypeRoot getTypeRoot() {
393 return this;
394}
395/**
396 * A class file has a corresponding resource unless it is contained
397 * in a jar.
398 *
399 * @see IJavaElement
400 */
401public IResource getCorrespondingResource() throws JavaModelException {
402 IPackageFragmentRoot root= (IPackageFragmentRoot)getParent().getParent();
403 if (root.isArchive()) {
404 return null;
405 } else {
406 return getUnderlyingResource();
407 }
408}
409/**
410 * @see IClassFile
411 */
412public IJavaElement getElementAt(int position) throws JavaModelException {
413 IJavaElement parentElement = getParent();
414 while (parentElement.getElementType() != IJavaElement.PACKAGE_FRAGMENT_ROOT) {
415 parentElement = parentElement.getParent();
416 }
417 PackageFragmentRoot root = (PackageFragmentRoot) parentElement;
418 SourceMapper mapper = root.getSourceMapper();
419 if (mapper == null) {
420 return null;
421 } else {
422 // ensure this class file's buffer is open so that source ranges are computed
423 getBuffer();
424
425 IType type = getType();
426 return findElement(type, position, mapper);
427 }
428}
429public IJavaElement getElementAtConsideringSibling(int position) throws JavaModelException {
430 IPackageFragment fragment = (IPackageFragment)getParent();
431 PackageFragmentRoot root = (PackageFragmentRoot) fragment.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
432 SourceMapper mapper = root.getSourceMapper();
433 if (mapper == null) {
434 return null;
435 } else {
436 int index = this.name.indexOf('$');
437 int prefixLength = index < 0 ? this.name.length() : index;
438
439 IType type = null;
440 int start = -1;
441 int end = Integer.MAX_VALUE;
442 IJavaElement[] children = fragment.getChildren();
443 for (int i = 0; i < children.length; i++) {
444 String childName = children[i].getElementName();
445
446 int childIndex = childName.indexOf('$');
447 int childPrefixLength = childIndex < 0 ? childName.indexOf('.') : childIndex;
448 if (prefixLength == childPrefixLength && this.name.regionMatches(0, childName, 0, prefixLength)) {
449 IClassFile classFile = (IClassFile) children[i];
450
451 // ensure this class file's buffer is open so that source ranges are computed
452 classFile.getBuffer();
453
454 SourceRange range = mapper.getSourceRange(classFile.getType());
455 if (range == SourceMapper.UNKNOWN_RANGE) continue;
456 int newStart = range.getOffset();
457 int newEnd = newStart + range.getLength() - 1;
458 if(newStart > start && newEnd < end
459 && newStart <= position && newEnd >= position) {
460 type = classFile.getType();
461 start = newStart;
462 end = newEnd;
463 }
464 }
465 }
466 if(type != null) {
467 return findElement(type, position, mapper);
468 }
469 return null;
470 }
471}
472public String getElementName() {
473 return this.name + SuffixConstants.SUFFIX_STRING_class;
474}
475/**
476 * @see IJavaElement
477 */
478public int getElementType() {
479 return CLASS_FILE;
480}
481/*
482 * @see JavaElement
483 */
484public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner owner) {
485 switch (token.charAt(0)) {
486 case JEM_TYPE:
487 if (!memento.hasMoreTokens()) return this;
488 String typeName = memento.nextToken();
489 JavaElement type = new BinaryType(this, typeName);
490 return type.getHandleFromMemento(memento, owner);
491 }
492 return null;
493}
494/**
495 * @see JavaElement#getHandleMemento()
496 */
497protected char getHandleMementoDelimiter() {
498 return JavaElement.JEM_CLASSFILE;
499}
500/*
501 * @see IJavaElement
502 */
503public IPath getPath() {
504 PackageFragmentRoot root = getPackageFragmentRoot();
505 if (root.isArchive()) {
506 return root.getPath();
507 } else {
508 return getParent().getPath().append(getElementName());
509 }
510}
511/*
512 * @see IJavaElement
513 */
514public IResource resource(PackageFragmentRoot root) {
515 return ((IContainer) ((Openable) this.parent).resource(root)).getFile(new Path(getElementName()));
516}
517/**
518 * @see ISourceReference
519 */
520public String getSource() throws JavaModelException {
521 IBuffer buffer = getBuffer();
522 if (buffer == null) {
523 return null;
524 }
525 return buffer.getContents();
526}
527/**
528 * @see ISourceReference
529 */
530public ISourceRange getSourceRange() throws JavaModelException {
531 IBuffer buffer = getBuffer();
532 if (buffer != null) {
533 String contents = buffer.getContents();
534 if (contents == null) return null;
535 return new SourceRange(0, contents.length());
536 } else {
537 return null;
538 }
539}
540/*
541 * Returns the name of the toplevel type of this class file.
542 */
543public String getTopLevelTypeName() {
544 String topLevelTypeName = getElementName();
545 int firstDollar = topLevelTypeName.indexOf('$');
546 if (firstDollar != -1) {
547 topLevelTypeName = topLevelTypeName.substring(0, firstDollar);
548 } else {
549 topLevelTypeName = topLevelTypeName.substring(0, topLevelTypeName.length()-SUFFIX_CLASS.length);
550 }
551 return topLevelTypeName;
552}
553/**
554 * @see IClassFile
555 */
556public IType getType() {
557//{ObjectTeams: optionally pass the enclosing type name down to the BinaryType:
558 return getType(null);
559}
560IType getType(char[] enclosingTypeName) {
561// orig:
562 if (this.binaryType == null) {
563// :giro
Stephan Herrmanna9a712e2012-04-05 23:23:52 +0200564 if (enclosingTypeName == null) {
565 // maybe we can recover the enclosing type name?
566 int lastDollar = this.name.lastIndexOf('$');
Stephan Herrmannffaf41b2012-04-06 05:00:08 +0200567 isMemberType: if (lastDollar != -1) {
568 String enclosingName = this.name.substring(0, lastDollar);
569 lastDollar = enclosingName.lastIndexOf('$');
570 if (lastDollar != -1) {
571 String previousSegment = enclosingName.substring(lastDollar+1);
572 try {
573 Integer.parseInt(previousSegment);
574 break isMemberType; // s.t. like Outer$1$Local, i.e., not a member type
575 } catch (NumberFormatException e) {
576 // nop
577 }
578 }
Stephan Herrmanna9a712e2012-04-05 23:23:52 +0200579 String binaryParentName = this.parent.getElementName().replace('.', '/');
Stephan Herrmannffaf41b2012-04-06 05:00:08 +0200580 enclosingTypeName = (binaryParentName+'/'+enclosingName).toCharArray();
Stephan Herrmanna9a712e2012-04-05 23:23:52 +0200581 }
582 }
Stephan Herrmann7b7062f2010-04-01 19:56:59 +0000583 if (enclosingTypeName != null)
584 this.binaryType = new BinaryType(enclosingTypeName, this, getTypeName());
585 else
586// SH}
587 this.binaryType = new BinaryType(this, getTypeName());
Stephan Herrmann3260d512010-09-11 11:30:46 +0000588//{ObjectTeams: register unopened type, so OTModelManager can already use it and trigger opening:
Stephan Herrmann7b7062f2010-04-01 19:56:59 +0000589 // make it known to the OTModelManager (without opening):
590 OTModelManager.getSharedInstance().addUnopenedType(this.binaryType);
591// SH}
592
593 }
Stephan Herrmanna9a712e2012-04-05 23:23:52 +0200594//{ObjectTeams: was enclosingTypeName missing when generating binaryType?
595 else if (enclosingTypeName != null) {
596 this.binaryType.updateEnclosingTypeName(enclosingTypeName);
597 }
598// SH}
Stephan Herrmann7b7062f2010-04-01 19:56:59 +0000599 return this.binaryType;
600}
601public String getTypeName() {
602 // Internal class file name doesn't contain ".class" file extension
603 int lastDollar = this.name.lastIndexOf('$');
604 return lastDollar > -1 ? Util.localTypeName(this.name, lastDollar, this.name.length()) : this.name;
605}
606/*
607 * @see IClassFile
608 */
609public ICompilationUnit getWorkingCopy(WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException {
610 CompilationUnit workingCopy = new ClassFileWorkingCopy(this, owner == null ? DefaultWorkingCopyOwner.PRIMARY : owner);
611 JavaModelManager manager = JavaModelManager.getJavaModelManager();
612 JavaModelManager.PerWorkingCopyInfo perWorkingCopyInfo =
613 manager.getPerWorkingCopyInfo(workingCopy, false/*don't create*/, true/*record usage*/, null/*not used since don't create*/);
614 if (perWorkingCopyInfo != null) {
615 return perWorkingCopyInfo.getWorkingCopy(); // return existing handle instead of the one created above
616 }
617 BecomeWorkingCopyOperation op = new BecomeWorkingCopyOperation(workingCopy, null);
618 op.runOperation(monitor);
619 return workingCopy;
620}
621/**
622 * @see IClassFile
623 * @deprecated
624 */
625public IJavaElement getWorkingCopy(IProgressMonitor monitor, org.eclipse.jdt.core.IBufferFactory factory) throws JavaModelException {
626 return getWorkingCopy(BufferFactoryWrapper.create(factory), monitor);
627}
628/**
629 * @see Openable
630 */
631protected boolean hasBuffer() {
632 return true;
633}
634public int hashCode() {
635 return Util.combineHashCodes(this.name.hashCode(), this.parent.hashCode());
636}
637/**
638 * @see IClassFile
639 */
640public boolean isClass() throws JavaModelException {
641 return getType().isClass();
642}
643/**
644 * @see IClassFile
645 */
646public boolean isInterface() throws JavaModelException {
647 return getType().isInterface();
648}
649/**
650 * Returns true - class files are always read only.
651 */
652public boolean isReadOnly() {
653 return true;
654}
655private IStatus validateClassFile() {
656 IPackageFragmentRoot root = getPackageFragmentRoot();
657 try {
658 if (root.getKind() != IPackageFragmentRoot.K_BINARY)
659 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, root);
660 } catch (JavaModelException e) {
661 return e.getJavaModelStatus();
662 }
663 IJavaProject project = getJavaProject();
664 return JavaConventions.validateClassFileName(getElementName(), project.getOption(JavaCore.COMPILER_SOURCE, true), project.getOption(JavaCore.COMPILER_COMPLIANCE, true));
665}
666/**
667 * Opens and returns buffer on the source code associated with this class file.
668 * Maps the source code to the children elements of this class file.
669 * If no source code is associated with this class file,
670 * <code>null</code> is returned.
671 *
672 * @see Openable
673 */
674protected IBuffer openBuffer(IProgressMonitor pm, Object info) throws JavaModelException {
675 // Check the cache for the top-level type first
676 IType outerMostEnclosingType = getOuterMostEnclosingType();
677 IBuffer buffer = getBufferManager().getBuffer(outerMostEnclosingType.getClassFile());
678 if (buffer == null) {
679 SourceMapper mapper = getSourceMapper();
680 IBinaryType typeInfo = info instanceof IBinaryType ? (IBinaryType) info : null;
681 if (mapper != null) {
682 buffer = mapSource(mapper, typeInfo, outerMostEnclosingType.getClassFile());
683 }
684 }
685 return buffer;
686}
687/** Loads the buffer via SourceMapper, and maps it in SourceMapper */
688private IBuffer mapSource(SourceMapper mapper, IBinaryType info, IClassFile bufferOwner) {
689 char[] contents = mapper.findSource(getType(), info);
690 if (contents != null) {
691 // create buffer
692 IBuffer buffer = BufferManager.createBuffer(bufferOwner);
693 if (buffer == null) return null;
694 BufferManager bufManager = getBufferManager();
695 bufManager.addBuffer(buffer);
696
697 // set the buffer source
698 if (buffer.getCharacters() == null){
699 buffer.setContents(contents);
700 }
701
702 // listen to buffer changes
703 buffer.addBufferChangedListener(this);
704
705 // do the source mapping
706 mapper.mapSource(getOuterMostEnclosingType(), contents, info);
707
708 return buffer;
709 } else {
710 // create buffer
711 IBuffer buffer = BufferManager.createNullBuffer(bufferOwner);
712 if (buffer == null) return null;
713 BufferManager bufManager = getBufferManager();
714 bufManager.addBuffer(buffer);
715
716 // listen to buffer changes
717 buffer.addBufferChangedListener(this);
718 return buffer;
719 }
720}
721/* package */ static String simpleName(char[] className) {
722 if (className == null)
723 return null;
724 String simpleName = new String(unqualifiedName(className));
725 int lastDollar = simpleName.lastIndexOf('$');
726 if (lastDollar != -1)
727 return Util.localTypeName(simpleName, lastDollar, simpleName.length());
728 else
729 return simpleName;
730}
731
732/** Returns the type of the top-level declaring class used to find the source code */
733private IType getOuterMostEnclosingType() {
734 IType type = getType();
735 IType enclosingType = type.getDeclaringType();
736 while (enclosingType != null) {
737 type = enclosingType;
738 enclosingType = type.getDeclaringType();
739 }
740 return type;
741}
742
743/**
744 * Returns the Java Model representation of the given name
745 * which is provided in diet class file format, or <code>null</code>
746 * if the given name is <code>null</code>.
747 *
748 * <p><code>ClassFileReader</code> format is similar to "java/lang/Object",
749 * and corresponding Java Model format is "java.lang.Object".
750 */
751
752public static char[] translatedName(char[] name) {
753 if (name == null)
754 return null;
755 int nameLength = name.length;
756 char[] newName= new char[nameLength];
757 for (int i= 0; i < nameLength; i++) {
758 if (name[i] == '/') {
759 newName[i]= '.';
760 } else {
761 newName[i]= name[i];
762 }
763 }
764 return newName;
765}
766/**
767 * Returns the Java Model representation of the given names
768 * which are provided in diet class file format, or <code>null</code>
769 * if the given names are <code>null</code>.
770 *
771 * <p><code>ClassFileReader</code> format is similar to "java/lang/Object",
772 * and corresponding Java Model format is "java.lang.Object".
773 */
774
775/* package */ static char[][] translatedNames(char[][] names) {
776 if (names == null)
777 return null;
778 int length = names.length;
779 char[][] newNames = new char[length][];
780 for(int i = 0; i < length; i++) {
781 newNames[i] = translatedName(names[i]);
782 }
783 return newNames;
784}
785/**
786 * Returns the Java Model format of the unqualified class name for the
787 * given className which is provided in diet class file format,
788 * or <code>null</code> if the given className is <code>null</code>.
789 * (This removes the package name, but not enclosing type names).
790 *
791 * <p><code>ClassFileReader</code> format is similar to "java/lang/Object",
792 * and corresponding Java Model simple name format is "Object".
793 */
794
795/* package */ static char[] unqualifiedName(char[] className) {
796 if (className == null)
797 return null;
798 int count = 0;
799 for (int i = className.length - 1; i > -1; i--) {
800 if (className[i] == '/') {
801 char[] name = new char[count];
802 System.arraycopy(className, i + 1, name, 0, count);
803 return name;
804 }
805 count++;
806 }
807 return className;
808}
809
810/**
811 * @see ICodeAssist#codeComplete(int, ICodeCompletionRequestor)
812 * @deprecated - should use codeComplete(int, ICompletionRequestor) instead
813 */
814public void codeComplete(int offset, final org.eclipse.jdt.core.ICodeCompletionRequestor requestor) throws JavaModelException {
815
816 if (requestor == null){
817 codeComplete(offset, (ICompletionRequestor)null);
818 return;
819 }
820 codeComplete(
821 offset,
822 new ICompletionRequestor(){
823 public void acceptAnonymousType(char[] superTypePackageName,char[] superTypeName, char[][] parameterPackageNames,char[][] parameterTypeNames,char[][] parameterNames,char[] completionName,int modifiers,int completionStart,int completionEnd, int relevance) {
824 // ignore
825 }
826 public void acceptClass(char[] packageName, char[] className, char[] completionName, int modifiers, int completionStart, int completionEnd, int relevance) {
827 requestor.acceptClass(packageName, className, completionName, modifiers, completionStart, completionEnd);
828 }
829 public void acceptError(IProblem error) {
830 // was disabled in 1.0
831 }
832 public void acceptField(char[] declaringTypePackageName, char[] declaringTypeName, char[] fieldName, char[] typePackageName, char[] typeName, char[] completionName, int modifiers, int completionStart, int completionEnd, int relevance) {
833 requestor.acceptField(declaringTypePackageName, declaringTypeName, fieldName, typePackageName, typeName, completionName, modifiers, completionStart, completionEnd);
834 }
835 public void acceptInterface(char[] packageName,char[] interfaceName,char[] completionName,int modifiers,int completionStart,int completionEnd, int relevance) {
836 requestor.acceptInterface(packageName, interfaceName, completionName, modifiers, completionStart, completionEnd);
837 }
838 public void acceptKeyword(char[] keywordName,int completionStart,int completionEnd, int relevance){
839 requestor.acceptKeyword(keywordName, completionStart, completionEnd);
840 }
841 public void acceptLabel(char[] labelName,int completionStart,int completionEnd, int relevance){
842 requestor.acceptLabel(labelName, completionStart, completionEnd);
843 }
844 public void acceptLocalVariable(char[] localVarName,char[] typePackageName,char[] typeName,int modifiers,int completionStart,int completionEnd, int relevance){
845 // ignore
846 }
847 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){
848 // skip parameter names
849 requestor.acceptMethod(declaringTypePackageName, declaringTypeName, selector, parameterPackageNames, parameterTypeNames, returnTypePackageName, returnTypeName, completionName, modifiers, completionStart, completionEnd);
850 }
851 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){
852 // ignore
853 }
854 public void acceptModifier(char[] modifierName,int completionStart,int completionEnd, int relevance){
855 requestor.acceptModifier(modifierName, completionStart, completionEnd);
856 }
857 public void acceptPackage(char[] packageName,char[] completionName,int completionStart,int completionEnd, int relevance){
858 requestor.acceptPackage(packageName, completionName, completionStart, completionEnd);
859 }
860 public void acceptType(char[] packageName,char[] typeName,char[] completionName,int completionStart,int completionEnd, int relevance){
861 requestor.acceptType(packageName, typeName, completionName, completionStart, completionEnd);
862 }
863 public void acceptVariableName(char[] typePackageName,char[] typeName,char[] varName,char[] completionName,int completionStart,int completionEnd, int relevance){
864 // ignore
865 }
866 });
867}
868
869protected IStatus validateExistence(IResource underlyingResource) {
870 // check whether the class file can be opened
871 IStatus status = validateClassFile();
872 if (!status.isOK())
873 return status;
874 if (underlyingResource != null) {
875 if (!underlyingResource.isAccessible())
876 return newDoesNotExistStatus();
877 PackageFragmentRoot root;
878 if ((underlyingResource instanceof IFolder) && (root = getPackageFragmentRoot()).isArchive()) { // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=204652
879 return root.newDoesNotExistStatus();
880 }
881 }
882 return JavaModelStatus.VERIFIED_OK;
883}
Stephan Herrmann66cc2b62010-09-26 15:38:59 +0000884public ISourceRange getNameRange() {
885 return null;
886}
Stephan Herrmann7b7062f2010-04-01 19:56:59 +0000887}