1 /*******************************************************************************
2 * Copyright (c) 2000, 2020 IBM Corporation and others.
3 *
4 * This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License 2.0
6 * which accompanies this distribution, and is available at
7 * https://www.eclipse.org/legal/epl-2.0/
8 *
9 * SPDX-License-Identifier: EPL-2.0
10 *
11 * Contributors:
12 * IBM Corporation - initial API and implementation
13 *******************************************************************************/
14 package org.eclipse.jdt.internal.core;
15
16 import java.io.InputStream;
17 import java.net.URL;
18 import java.util.ArrayList;
19 import java.util.HashMap;
20
21 import org.eclipse.core.runtime.Assert;
22 import org.eclipse.core.runtime.IProgressMonitor;
23 import org.eclipse.core.runtime.OperationCanceledException;
24 import org.eclipse.jdt.core.*;
25 import org.eclipse.jdt.core.compiler.CharOperation;
26 import org.eclipse.jdt.core.search.SearchEngine;
27 import org.eclipse.jdt.internal.codeassist.CompletionEngine;
28 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
29 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
30 import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation;
31 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
32 import org.eclipse.jdt.internal.compiler.lookup.Binding;
33 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
34 import org.eclipse.jdt.internal.core.JavaModelManager.PerProjectInfo;
35 import org.eclipse.jdt.internal.core.hierarchy.TypeHierarchy;
36 import org.eclipse.jdt.internal.core.util.MementoTokenizer;
37 import org.eclipse.jdt.internal.core.util.Messages;
38 import org.eclipse.jdt.internal.core.util.Util;
39
40 /**
41 * Parent is an IClassFile.
42 *
43 * @see IType
44 */
45
46 @SuppressWarnings({ "rawtypes", "unchecked" })
47 public class BinaryType extends BinaryMember implements IType, SuffixConstants {
48
49 private static final IField[] NO_FIELDS = new IField[0];
50 private static final IMethod[] NO_METHODS = new IMethod[0];
51 private static final IType[] NO_TYPES = new IType[0];
52 private static final IInitializer[] NO_INITIALIZERS = new IInitializer[0];
53 public static final JavadocContents EMPTY_JAVADOC = new JavadocContents(null, org.eclipse.jdt.internal.compiler.util.Util.EMPTY_STRING);
54
BinaryType(JavaElement parent, String name)55 protected BinaryType(JavaElement parent, String name) {
56 super(parent, name);
57 }
58 /*
59 * Remove my cached children from the Java Model
60 */
61 @Override
closing(Object info)62 protected void closing(Object info) throws JavaModelException {
63 ClassFileInfo cfi = getClassFileInfo();
64 cfi.removeBinaryChildren();
65 }
66
67 /**
68 * @see IType#codeComplete(char[], int, int, char[][], char[][], int[], boolean, ICompletionRequestor)
69 * @deprecated
70 */
71 @Override
codeComplete(char[] snippet,int insertion,int position,char[][] localVariableTypeNames,char[][] localVariableNames,int[] localVariableModifiers,boolean isStatic,ICompletionRequestor requestor)72 public void codeComplete(char[] snippet,int insertion,int position,char[][] localVariableTypeNames,char[][] localVariableNames,int[] localVariableModifiers,boolean isStatic,ICompletionRequestor requestor) throws JavaModelException {
73 codeComplete(snippet, insertion, position, localVariableTypeNames, localVariableNames, localVariableModifiers, isStatic, requestor, DefaultWorkingCopyOwner.PRIMARY);
74 }
75
76 /**
77 * @see IType#codeComplete(char[], int, int, char[][], char[][], int[], boolean, ICompletionRequestor, WorkingCopyOwner)
78 * @deprecated
79 */
80 @Override
codeComplete(char[] snippet,int insertion,int position,char[][] localVariableTypeNames,char[][] localVariableNames,int[] localVariableModifiers,boolean isStatic,ICompletionRequestor requestor, WorkingCopyOwner owner)81 public void codeComplete(char[] snippet,int insertion,int position,char[][] localVariableTypeNames,char[][] localVariableNames,int[] localVariableModifiers,boolean isStatic,ICompletionRequestor requestor, WorkingCopyOwner owner) throws JavaModelException {
82 if (requestor == null) {
83 throw new IllegalArgumentException("Completion requestor cannot be null"); //$NON-NLS-1$
84 }
85 codeComplete(snippet, insertion, position, localVariableTypeNames, localVariableNames, localVariableModifiers, isStatic, new org.eclipse.jdt.internal.codeassist.CompletionRequestorWrapper(requestor), owner);
86 }
87
88 @Override
codeComplete(char[] snippet,int insertion,int position,char[][] localVariableTypeNames,char[][] localVariableNames,int[] localVariableModifiers,boolean isStatic,CompletionRequestor requestor)89 public void codeComplete(char[] snippet,int insertion,int position,char[][] localVariableTypeNames,char[][] localVariableNames,int[] localVariableModifiers,boolean isStatic,CompletionRequestor requestor) throws JavaModelException {
90 codeComplete(snippet, insertion, position, localVariableTypeNames, localVariableNames, localVariableModifiers, isStatic, requestor, DefaultWorkingCopyOwner.PRIMARY);
91 }
92
93 @Override
codeComplete(char[] snippet,int insertion,int position,char[][] localVariableTypeNames,char[][] localVariableNames,int[] localVariableModifiers,boolean isStatic,CompletionRequestor requestor, IProgressMonitor monitor)94 public void codeComplete(char[] snippet,int insertion,int position,char[][] localVariableTypeNames,char[][] localVariableNames,int[] localVariableModifiers,boolean isStatic,CompletionRequestor requestor, IProgressMonitor monitor) throws JavaModelException {
95 codeComplete(snippet, insertion, position, localVariableTypeNames, localVariableNames, localVariableModifiers, isStatic, requestor, DefaultWorkingCopyOwner.PRIMARY, monitor);
96 }
97
98 @Override
codeComplete(char[] snippet,int insertion,int position,char[][] localVariableTypeNames,char[][] localVariableNames,int[] localVariableModifiers,boolean isStatic,CompletionRequestor requestor, WorkingCopyOwner owner)99 public void codeComplete(char[] snippet,int insertion,int position,char[][] localVariableTypeNames,char[][] localVariableNames,int[] localVariableModifiers,boolean isStatic,CompletionRequestor requestor, WorkingCopyOwner owner) throws JavaModelException {
100 codeComplete(snippet, insertion, position, localVariableTypeNames, localVariableNames, localVariableModifiers, isStatic, requestor, owner, null);
101 }
102
103 @Override
codeComplete( char[] snippet, int insertion, int position, char[][] localVariableTypeNames, char[][] localVariableNames, int[] localVariableModifiers, boolean isStatic, CompletionRequestor requestor, WorkingCopyOwner owner, IProgressMonitor monitor)104 public void codeComplete(
105 char[] snippet,
106 int insertion,
107 int position,
108 char[][] localVariableTypeNames,
109 char[][] localVariableNames,
110 int[] localVariableModifiers,
111 boolean isStatic,
112 CompletionRequestor requestor,
113 WorkingCopyOwner owner,
114 IProgressMonitor monitor) throws JavaModelException {
115 if (requestor == null) {
116 throw new IllegalArgumentException("Completion requestor cannot be null"); //$NON-NLS-1$
117 }
118 JavaProject project = (JavaProject) getJavaProject();
119 SearchableEnvironment environment = project.newSearchableNameEnvironment(owner, requestor.isTestCodeExcluded());
120 CompletionEngine engine = new CompletionEngine(environment, requestor, project.getOptions(true), project, owner, monitor);
121
122 String source = getClassFile().getSource();
123 if (source != null && insertion > -1 && insertion < source.length()) {
124 // code complete
125
126 char[] prefix = CharOperation.concat(source.substring(0, insertion).toCharArray(), new char[]{'{'});
127 char[] suffix = CharOperation.concat(new char[]{'}'}, source.substring(insertion).toCharArray());
128 char[] fakeSource = CharOperation.concat(prefix, snippet, suffix);
129
130 BasicCompilationUnit cu =
131 new BasicCompilationUnit(
132 fakeSource,
133 null,
134 getElementName(),
135 project); // use project to retrieve corresponding .java IFile
136
137 engine.complete(cu, prefix.length + position, prefix.length, null/*extended context isn't computed*/);
138 } else {
139 engine.complete(this, snippet, position, localVariableTypeNames, localVariableNames, localVariableModifiers, isStatic);
140 }
141 if (NameLookup.VERBOSE) {
142 System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInSourcePackage: " + environment.nameLookup.timeSpentInSeekTypesInSourcePackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
143 System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInBinaryPackage: " + environment.nameLookup.timeSpentInSeekTypesInBinaryPackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
144 }
145 }
146
147 @Override
createField(String contents, IJavaElement sibling, boolean force, IProgressMonitor monitor)148 public IField createField(String contents, IJavaElement sibling, boolean force, IProgressMonitor monitor) throws JavaModelException {
149 throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this));
150 }
151
152 @Override
createInitializer(String contents, IJavaElement sibling, IProgressMonitor monitor)153 public IInitializer createInitializer(String contents, IJavaElement sibling, IProgressMonitor monitor) throws JavaModelException {
154 throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this));
155 }
156
157 @Override
createMethod(String contents, IJavaElement sibling, boolean force, IProgressMonitor monitor)158 public IMethod createMethod(String contents, IJavaElement sibling, boolean force, IProgressMonitor monitor) throws JavaModelException {
159 throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this));
160 }
161
162 @Override
createType(String contents, IJavaElement sibling, boolean force, IProgressMonitor monitor)163 public IType createType(String contents, IJavaElement sibling, boolean force, IProgressMonitor monitor) throws JavaModelException {
164 throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this));
165 }
166 @Override
equals(Object o)167 public boolean equals(Object o) {
168 if (!(o instanceof BinaryType)) return false;
169 return super.equals(o);
170 }
171
172 @Override
findMethods(IMethod method)173 public IMethod[] findMethods(IMethod method) {
174 try {
175 return findMethods(method, getMethods());
176 } catch (JavaModelException e) {
177 // if type doesn't exist, no matching method can exist
178 return null;
179 }
180 }
181 @Override
getAnnotations()182 public IAnnotation[] getAnnotations() throws JavaModelException {
183 IBinaryType info = (IBinaryType) getElementInfo();
184 IBinaryAnnotation[] binaryAnnotations = info.getAnnotations();
185 return getAnnotations(binaryAnnotations, info.getTagBits());
186 }
187
188 @Override
getChildren()189 public IJavaElement[] getChildren() throws JavaModelException {
190 ClassFileInfo cfi = getClassFileInfo();
191 return cfi.binaryChildren;
192 }
193 @Override
getChildrenForCategory(String category)194 public IJavaElement[] getChildrenForCategory(String category) throws JavaModelException {
195 IJavaElement[] children = getChildren();
196 int length = children.length;
197 if (length == 0) return children;
198 SourceMapper mapper= getSourceMapper();
199 if (mapper != null) {
200 // ensure the class file's buffer is open so that categories are computed
201 getClassFile().getBuffer();
202
203 HashMap categories = mapper.categories;
204 IJavaElement[] result = new IJavaElement[length];
205 int index = 0;
206 if (categories != null) {
207 for (int i = 0; i < length; i++) {
208 IJavaElement child = children[i];
209 String[] cats = (String[]) categories.get(child);
210 if (cats != null) {
211 for (int j = 0, length2 = cats.length; j < length2; j++) {
212 if (cats[j].equals(category)) {
213 result[index++] = child;
214 break;
215 }
216 }
217 }
218 }
219 }
220 if (index < length)
221 System.arraycopy(result, 0, result = new IJavaElement[index], 0, index);
222 return result;
223 }
224 return NO_ELEMENTS;
225 }
getClassFileInfo()226 protected ClassFileInfo getClassFileInfo() throws JavaModelException {
227 return (ClassFileInfo) this.parent.getElementInfo();
228 }
229 @Override
getClassFile()230 public IOrdinaryClassFile getClassFile() {
231 return (IOrdinaryClassFile) super.getClassFile();
232 }
233 @Override
getDeclaringType()234 public IType getDeclaringType() {
235 IOrdinaryClassFile classFile = getClassFile();
236 if (classFile.isOpen()) {
237 try {
238 char[] enclosingTypeName = ((IBinaryType) getElementInfo()).getEnclosingTypeName();
239 if (enclosingTypeName == null) {
240 return null;
241 }
242 enclosingTypeName = ClassFile.unqualifiedName(enclosingTypeName);
243
244 // workaround problem with class files compiled with javac 1.1.*
245 // that return a non-null enclosing type name for local types defined in anonymous (e.g. A$1$B)
246 if (classFile.getElementName().length() > enclosingTypeName.length+1
247 && Character.isDigit(classFile.getElementName().charAt(enclosingTypeName.length+1))) {
248 return null;
249 }
250
251 return getPackageFragment().getOrdinaryClassFile(new String(enclosingTypeName) + SUFFIX_STRING_class).getType();
252 } catch (JavaModelException npe) {
253 return null;
254 }
255 } else {
256 // cannot access .class file without opening it
257 // and getDeclaringType() is supposed to be a handle-only method,
258 // so default to assuming $ is an enclosing type separator
259 String classFileName = classFile.getElementName();
260 int lastDollar = -1;
261 for (int i = 0, length = classFileName.length(); i < length; i++) {
262 char c = classFileName.charAt(i);
263 if (Character.isDigit(c) && lastDollar == i-1) {
264 // anonymous or local type
265 return null;
266 } else if (c == '$') {
267 lastDollar = i;
268 }
269 }
270 if (lastDollar == -1) {
271 return null;
272 } else {
273 String enclosingName = classFileName.substring(0, lastDollar);
274 String enclosingClassFileName = enclosingName + SUFFIX_STRING_class;
275 return
276 new BinaryType(
277 (JavaElement)getPackageFragment().getClassFile(enclosingClassFileName),
278 Util.localTypeName(enclosingName, enclosingName.lastIndexOf('$'), enclosingName.length()));
279 }
280 }
281 }
282 @Override
getElementInfo(IProgressMonitor monitor)283 public Object getElementInfo(IProgressMonitor monitor) throws JavaModelException {
284 JavaModelManager manager = JavaModelManager.getJavaModelManager();
285 Object info = manager.getInfo(this);
286 if (info != null && info != JavaModelCache.NON_EXISTING_JAR_TYPE_INFO) return info;
287 return openWhenClosed(createElementInfo(), false, monitor);
288 }
289 /*
290 * @see IJavaElement
291 */
292 @Override
getElementType()293 public int getElementType() {
294 return TYPE;
295 }
296
297 @Override
getField(String fieldName)298 public IField getField(String fieldName) {
299 return new BinaryField(this, fieldName);
300 }
301 @Override
getFields()302 public IField[] getFields() throws JavaModelException {
303 if (!isRecord()) {
304 ArrayList list = getChildrenOfType(FIELD);
305 if (list.size() == 0) {
306 return NO_FIELDS;
307 }
308 IField[] array= new IField[list.size()];
309 list.toArray(array);
310 return array;
311 }
312 return getFieldsOrComponents(false);
313 }
314 @Override
getRecordComponents()315 public IField[] getRecordComponents() throws JavaModelException {
316 if (!isRecord())
317 return new IField[0];
318 return getFieldsOrComponents(true);
319 }
getFieldsOrComponents(boolean component)320 private IField[] getFieldsOrComponents(boolean component) throws JavaModelException {
321 ArrayList list = getChildrenOfType(FIELD);
322 if (list.size() == 0) {
323 return NO_FIELDS;
324 }
325 ArrayList<IField> fields = new ArrayList<>();
326 for (Object object : list) {
327 IField field = (IField) object;
328 if (field.isRecordComponent() == component)
329 fields.add(field);
330 }
331 IField[] array= new IField[fields.size()];
332 fields.toArray(array);
333 return array;
334 }
335 @Override
getRecordComponent(String compName)336 public IField getRecordComponent(String compName) {
337 try {
338 if (isRecord())
339 return new BinaryField(this, compName);
340 } catch (JavaModelException e) {
341 //
342 }
343 return null;
344 }
345 @Override
getFlags()346 public int getFlags() throws JavaModelException {
347 IBinaryType info = (IBinaryType) getElementInfo();
348 return info.getModifiers() & ~ClassFileConstants.AccSuper;
349 }
350
351 @Override
getFullyQualifiedName()352 public String getFullyQualifiedName() {
353 return this.getFullyQualifiedName('$');
354 }
355
356 @Override
getFullyQualifiedName(char enclosingTypeSeparator)357 public String getFullyQualifiedName(char enclosingTypeSeparator) {
358 try {
359 return getFullyQualifiedName(enclosingTypeSeparator, false/*don't show parameters*/);
360 } catch (JavaModelException e) {
361 // exception thrown only when showing parameters
362 return null;
363 }
364 }
365
366 @Override
getFullyQualifiedParameterizedName()367 public String getFullyQualifiedParameterizedName() throws JavaModelException {
368 return getFullyQualifiedName('.', true/*show parameters*/);
369 }
370
371 /*
372 * @see JavaElement
373 */
374 @Override
getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner workingCopyOwner)375 public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner workingCopyOwner) {
376 switch (token.charAt(0)) {
377 case JEM_COUNT:
378 return getHandleUpdatingCountFromMemento(memento, workingCopyOwner);
379 case JEM_FIELD:
380 if (!memento.hasMoreTokens()) return this;
381 String fieldName = memento.nextToken();
382 JavaElement field = (JavaElement)getField(fieldName);
383 return field.getHandleFromMemento(memento, workingCopyOwner);
384 case JEM_INITIALIZER:
385 if (!memento.hasMoreTokens()) return this;
386 String count = memento.nextToken();
387 JavaElement initializer = (JavaElement)getInitializer(Integer.parseInt(count));
388 return initializer.getHandleFromMemento(memento, workingCopyOwner);
389 case JEM_METHOD:
390 if (!memento.hasMoreTokens()) return this;
391 String selector = memento.nextToken();
392 ArrayList params = new ArrayList();
393 nextParam: while (memento.hasMoreTokens()) {
394 token = memento.nextToken();
395 switch (token.charAt(0)) {
396 case JEM_TYPE:
397 case JEM_TYPE_PARAMETER:
398 case JEM_ANNOTATION:
399 break nextParam;
400 case JEM_METHOD:
401 if (!memento.hasMoreTokens()) return this;
402 String param = memento.nextToken();
403 StringBuffer buffer = new StringBuffer();
404 while (param.length() == 1 && Signature.C_ARRAY == param.charAt(0)) { // backward compatible with 3.0 mementos
405 buffer.append(Signature.C_ARRAY);
406 if (!memento.hasMoreTokens()) return this;
407 param = memento.nextToken();
408 }
409 params.add(buffer.toString() + param);
410 break;
411 default:
412 break nextParam;
413 }
414 }
415 String[] parameters = new String[params.size()];
416 params.toArray(parameters);
417 JavaElement method = (JavaElement)getMethod(selector, parameters);
418 switch (token.charAt(0)) {
419 case JEM_LAMBDA_EXPRESSION:
420 case JEM_TYPE:
421 case JEM_TYPE_PARAMETER:
422 case JEM_LOCALVARIABLE:
423 case JEM_ANNOTATION:
424 return method.getHandleFromMemento(token, memento, workingCopyOwner);
425 default:
426 return method;
427 }
428 case JEM_TYPE:
429 String typeName;
430 if (memento.hasMoreTokens()) {
431 typeName = memento.nextToken();
432 char firstChar = typeName.charAt(0);
433 if (firstChar == JEM_FIELD || firstChar == JEM_INITIALIZER || firstChar == JEM_METHOD || firstChar == JEM_TYPE || firstChar == JEM_COUNT) {
434 token = typeName;
435 typeName = ""; //$NON-NLS-1$
436 } else {
437 token = null;
438 }
439 } else {
440 typeName = ""; //$NON-NLS-1$
441 token = null;
442 }
443 JavaElement type = (JavaElement)getType(typeName);
444 if (token == null) {
445 return type.getHandleFromMemento(memento, workingCopyOwner);
446 } else {
447 return type.getHandleFromMemento(token, memento, workingCopyOwner);
448 }
449 case JEM_TYPE_PARAMETER:
450 if (!memento.hasMoreTokens()) return this;
451 String typeParameterName = memento.nextToken();
452 JavaElement typeParameter = new TypeParameter(this, typeParameterName);
453 return typeParameter.getHandleFromMemento(memento, workingCopyOwner);
454 case JEM_ANNOTATION:
455 if (!memento.hasMoreTokens()) return this;
456 String annotationName = memento.nextToken();
457 JavaElement annotation = new Annotation(this, annotationName);
458 return annotation.getHandleFromMemento(memento, workingCopyOwner);
459 }
460 return null;
461 }
462
463 @Override
getInitializer(int count)464 public IInitializer getInitializer(int count) {
465 return new Initializer(this, count);
466 }
467
468 @Override
getInitializers()469 public IInitializer[] getInitializers() {
470 return NO_INITIALIZERS;
471 }
472 @Override
getKey(boolean forceOpen)473 public String getKey(boolean forceOpen) throws JavaModelException {
474 return getKey(this, forceOpen);
475 }
476
477 @Override
getMethod(String selector, String[] parameterTypeSignatures)478 public IMethod getMethod(String selector, String[] parameterTypeSignatures) {
479 return new BinaryMethod(this, selector, parameterTypeSignatures);
480 }
481
482 @Override
getMethods()483 public IMethod[] getMethods() throws JavaModelException {
484 ArrayList list = getChildrenOfType(METHOD);
485 int size;
486 if ((size = list.size()) == 0) {
487 return NO_METHODS;
488 } else {
489 IMethod[] array= new IMethod[size];
490 list.toArray(array);
491 return array;
492 }
493 }
494
495 @Override
getPackageFragment()496 public IPackageFragment getPackageFragment() {
497 IJavaElement parentElement = this.parent;
498 while (parentElement != null) {
499 if (parentElement.getElementType() == IJavaElement.PACKAGE_FRAGMENT) {
500 return (IPackageFragment)parentElement;
501 }
502 else {
503 parentElement = parentElement.getParent();
504 }
505 }
506 Assert.isTrue(false); // should not happen
507 return null;
508 }
509
510 /**
511 * @see IType#getSuperclassTypeSignature()
512 * @since 3.0
513 */
514 @Override
getSuperclassTypeSignature()515 public String getSuperclassTypeSignature() throws JavaModelException {
516 IBinaryType info = (IBinaryType) getElementInfo();
517 char[] genericSignature = info.getGenericSignature();
518 if (genericSignature != null) {
519 int signatureLength = genericSignature.length;
520 // skip type parameters
521 int index = 0;
522 if (genericSignature[0] == '<') {
523 int count = 1;
524 while (count > 0 && ++index < signatureLength) {
525 switch (genericSignature[index]) {
526 case '<':
527 count++;
528 break;
529 case '>':
530 count--;
531 break;
532 }
533 }
534 index++;
535 }
536 int start = index;
537 index = org.eclipse.jdt.internal.compiler.util.Util.scanClassTypeSignature(genericSignature, start) + 1;
538 char[] superclassSig = CharOperation.subarray(genericSignature, start, index);
539 return new String(ClassFile.translatedName(superclassSig));
540 } else {
541 char[] superclassName = info.getSuperclassName();
542 if (superclassName == null) {
543 return null;
544 }
545 return Signature.createTypeSignature(ClassFile.translatedName(superclassName), true);
546 }
547 }
548
getSourceFileName(IBinaryType info)549 public String getSourceFileName(IBinaryType info) {
550 if (info == null) {
551 try {
552 info = (IBinaryType) getElementInfo();
553 } catch (JavaModelException e) {
554 // default to using the outer most declaring type name
555 IType type = this;
556 IType enclosingType = getDeclaringType();
557 while (enclosingType != null) {
558 type = enclosingType;
559 enclosingType = type.getDeclaringType();
560 }
561 return type.getElementName() + Util.defaultJavaExtension();
562 }
563 }
564 return sourceFileName(info);
565 }
566
567 @Override
getSuperclassName()568 public String getSuperclassName() throws JavaModelException {
569 IBinaryType info = (IBinaryType) getElementInfo();
570 char[] superclassName = info.getSuperclassName();
571 if (superclassName == null) {
572 return null;
573 }
574 return new String(ClassFile.translatedName(superclassName));
575 }
576
577 @Override
getSuperInterfaceNames()578 public String[] getSuperInterfaceNames() throws JavaModelException {
579 IBinaryType info = (IBinaryType) getElementInfo();
580 char[][] names= info.getInterfaceNames();
581 int length;
582 if (names == null || (length = names.length) == 0) {
583 return CharOperation.NO_STRINGS;
584 }
585 names= ClassFile.translatedNames(names);
586 String[] strings= new String[length];
587 for (int i= 0; i < length; i++) {
588 strings[i]= new String(names[i]);
589 }
590 return strings;
591 }
592
593 /**
594 * @see IType#getSuperInterfaceTypeSignatures()
595 * @since 3.0
596 */
597 @Override
getSuperInterfaceTypeSignatures()598 public String[] getSuperInterfaceTypeSignatures() throws JavaModelException {
599 IBinaryType info = (IBinaryType) getElementInfo();
600 char[] genericSignature = info.getGenericSignature();
601 if (genericSignature != null) {
602 ArrayList interfaces = new ArrayList();
603 int signatureLength = genericSignature.length;
604 // skip type parameters
605 int index = 0;
606 if (genericSignature[0] == '<') {
607 int count = 1;
608 while (count > 0 && ++index < signatureLength) {
609 switch (genericSignature[index]) {
610 case '<':
611 count++;
612 break;
613 case '>':
614 count--;
615 break;
616 }
617 }
618 index++;
619 }
620 // skip superclass
621 index = org.eclipse.jdt.internal.compiler.util.Util.scanClassTypeSignature(genericSignature, index) + 1;
622 while (index < signatureLength) {
623 int start = index;
624 index = org.eclipse.jdt.internal.compiler.util.Util.scanClassTypeSignature(genericSignature, start) + 1;
625 char[] interfaceSig = CharOperation.subarray(genericSignature, start, index);
626 interfaces.add(new String(ClassFile.translatedName(interfaceSig)));
627 }
628 int size = interfaces.size();
629 String[] result = new String[size];
630 interfaces.toArray(result);
631 return result;
632 } else {
633 char[][] names= info.getInterfaceNames();
634 int length;
635 if (names == null || (length = names.length) == 0) {
636 return CharOperation.NO_STRINGS;
637 }
638 names= ClassFile.translatedNames(names);
639 String[] strings= new String[length];
640 for (int i= 0; i < length; i++) {
641 strings[i]= Signature.createTypeSignature(names[i], true);
642 }
643 return strings;
644 }
645 }
646
647 @Override
getTypeParameters()648 public ITypeParameter[] getTypeParameters() throws JavaModelException {
649 String[] typeParameterSignatures = getTypeParameterSignatures();
650 int length = typeParameterSignatures.length;
651 if (length == 0) return TypeParameter.NO_TYPE_PARAMETERS;
652 ITypeParameter[] typeParameters = new ITypeParameter[length];
653 for (int i = 0; i < typeParameterSignatures.length; i++) {
654 String typeParameterName = Signature.getTypeVariable(typeParameterSignatures[i]);
655 typeParameters[i] = new TypeParameter(this, typeParameterName);
656 }
657 return typeParameters;
658 }
659
660 /**
661 * @see IType#getTypeParameterSignatures()
662 * @since 3.0
663 */
664 @Override
getTypeParameterSignatures()665 public String[] getTypeParameterSignatures() throws JavaModelException {
666 IBinaryType info = (IBinaryType) getElementInfo();
667 char[] genericSignature = info.getGenericSignature();
668 if (genericSignature == null)
669 return CharOperation.NO_STRINGS;
670
671 char[] dotBaseSignature = CharOperation.replaceOnCopy(genericSignature, '/', '.');
672 char[][] typeParams = Signature.getTypeParameters(dotBaseSignature);
673 return CharOperation.toStrings(typeParams);
674 }
675
676 @Override
getType(String typeName)677 public IType getType(String typeName) {
678 IClassFile classFile= getPackageFragment().getClassFile(getTypeQualifiedName() + "$" + typeName + SUFFIX_STRING_class); //$NON-NLS-1$
679 return new BinaryType((JavaElement)classFile, typeName);
680 }
681 @Override
getTypeParameter(String typeParameterName)682 public ITypeParameter getTypeParameter(String typeParameterName) {
683 return new TypeParameter(this, typeParameterName);
684 }
685
686 @Override
getTypeQualifiedName()687 public String getTypeQualifiedName() {
688 return this.getTypeQualifiedName('$');
689 }
690
691 @Override
getTypeQualifiedName(char enclosingTypeSeparator)692 public String getTypeQualifiedName(char enclosingTypeSeparator) {
693 try {
694 return getTypeQualifiedName(enclosingTypeSeparator, false/*don't show parameters*/);
695 } catch (JavaModelException e) {
696 // exception thrown only when showing parameters
697 return null;
698 }
699 }
700
701 @Override
getTypes()702 public IType[] getTypes() throws JavaModelException {
703 ArrayList list = getChildrenOfType(TYPE);
704 int size;
705 if ((size = list.size()) == 0) {
706 return NO_TYPES;
707 } else {
708 IType[] array= new IType[size];
709 list.toArray(array);
710 return array;
711 }
712 }
713
714 @Override
isAnonymous()715 public boolean isAnonymous() throws JavaModelException {
716 IBinaryType info = (IBinaryType) getElementInfo();
717 return info.isAnonymous();
718 }
719
720 @Override
isClass()721 public boolean isClass() throws JavaModelException {
722 IBinaryType info = (IBinaryType) getElementInfo();
723 return TypeDeclaration.kind(info.getModifiers()) == TypeDeclaration.CLASS_DECL;
724
725 }
726
727 /**
728 * @see IType#isEnum()
729 * @since 3.0
730 */
731 @Override
isEnum()732 public boolean isEnum() throws JavaModelException {
733 IBinaryType info = (IBinaryType) getElementInfo();
734 return TypeDeclaration.kind(info.getModifiers()) == TypeDeclaration.ENUM_DECL;
735 }
736
737 /**
738 * @see IType#isRecord()
739 * @noreference This method is not intended to be referenced by clients as it is a part of Java preview feature.
740 */
741 @Override
isRecord()742 public boolean isRecord() throws JavaModelException {
743 IBinaryType info = (IBinaryType) getElementInfo();
744 return TypeDeclaration.kind(info.getModifiers()) == TypeDeclaration.RECORD_DECL;
745 }
746
747 @Override
isInterface()748 public boolean isInterface() throws JavaModelException {
749 IBinaryType info = (IBinaryType) getElementInfo();
750 switch (TypeDeclaration.kind(info.getModifiers())) {
751 case TypeDeclaration.INTERFACE_DECL:
752 case TypeDeclaration.ANNOTATION_TYPE_DECL: // annotation is interface too
753 return true;
754 }
755 return false;
756 }
757 /**
758 * @see IType#isAnnotation()
759 * @since 3.0
760 */
761 @Override
isAnnotation()762 public boolean isAnnotation() throws JavaModelException {
763 IBinaryType info = (IBinaryType) getElementInfo();
764 return TypeDeclaration.kind(info.getModifiers()) == TypeDeclaration.ANNOTATION_TYPE_DECL;
765 }
766
767 @Override
isLocal()768 public boolean isLocal() throws JavaModelException {
769 IBinaryType info = (IBinaryType) getElementInfo();
770 return info.isLocal();
771 }
772
773 @Override
isMember()774 public boolean isMember() throws JavaModelException {
775 IBinaryType info = (IBinaryType) getElementInfo();
776 return info.isMember();
777 }
778
779 @Override
isResolved()780 public boolean isResolved() {
781 return false;
782 }
783 /*
784 * @see IType
785 */
786 @Override
loadTypeHierachy(InputStream input, IProgressMonitor monitor)787 public ITypeHierarchy loadTypeHierachy(InputStream input, IProgressMonitor monitor) throws JavaModelException {
788 return loadTypeHierachy(input, DefaultWorkingCopyOwner.PRIMARY, monitor);
789 }
790 /*
791 * @see IType
792 */
loadTypeHierachy(InputStream input, WorkingCopyOwner owner, IProgressMonitor monitor)793 public ITypeHierarchy loadTypeHierachy(InputStream input, WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException {
794 return TypeHierarchy.load(this, input, owner);
795 }
796
797 @Override
newSupertypeHierarchy(IProgressMonitor monitor)798 public ITypeHierarchy newSupertypeHierarchy(IProgressMonitor monitor) throws JavaModelException {
799 return this.newSupertypeHierarchy(DefaultWorkingCopyOwner.PRIMARY, monitor);
800 }
801
802 @Override
newSupertypeHierarchy( ICompilationUnit[] workingCopies, IProgressMonitor monitor)803 public ITypeHierarchy newSupertypeHierarchy(
804 ICompilationUnit[] workingCopies,
805 IProgressMonitor monitor)
806 throws JavaModelException {
807
808 CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(this, workingCopies, SearchEngine.createWorkspaceScope(), false);
809 op.runOperation(monitor);
810 return op.getResult();
811 }
812 /**
813 * @param workingCopies the working copies that take precedence over their original compilation units
814 * @param monitor the given progress monitor
815 * @return a type hierarchy for this type containing this type and all of its supertypes
816 * @exception JavaModelException if this element does not exist or if an
817 * exception occurs while accessing its corresponding resource.
818 *
819 * @see IType#newSupertypeHierarchy(IWorkingCopy[], IProgressMonitor)
820 * @deprecated
821 */
822 @Override
newSupertypeHierarchy( IWorkingCopy[] workingCopies, IProgressMonitor monitor)823 public ITypeHierarchy newSupertypeHierarchy(
824 IWorkingCopy[] workingCopies,
825 IProgressMonitor monitor)
826 throws JavaModelException {
827
828 ICompilationUnit[] copies;
829 if (workingCopies == null) {
830 copies = null;
831 } else {
832 int length = workingCopies.length;
833 System.arraycopy(workingCopies, 0, copies = new ICompilationUnit[length], 0, length);
834 }
835 return newSupertypeHierarchy(copies, monitor);
836 }
837
838 @Override
newSupertypeHierarchy( WorkingCopyOwner owner, IProgressMonitor monitor)839 public ITypeHierarchy newSupertypeHierarchy(
840 WorkingCopyOwner owner,
841 IProgressMonitor monitor)
842 throws JavaModelException {
843
844 ICompilationUnit[] workingCopies = JavaModelManager.getJavaModelManager().getWorkingCopies(owner, true/*add primary working copies*/);
845 CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(this, workingCopies, SearchEngine.createWorkspaceScope(), false);
846 op.runOperation(monitor);
847 return op.getResult();
848 }
849
850 @Override
newTypeHierarchy(IJavaProject project, IProgressMonitor monitor)851 public ITypeHierarchy newTypeHierarchy(IJavaProject project, IProgressMonitor monitor) throws JavaModelException {
852 return newTypeHierarchy(project, DefaultWorkingCopyOwner.PRIMARY, monitor);
853 }
854
855 @Override
newTypeHierarchy(IJavaProject project, WorkingCopyOwner owner, IProgressMonitor monitor)856 public ITypeHierarchy newTypeHierarchy(IJavaProject project, WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException {
857 if (project == null) {
858 throw new IllegalArgumentException(Messages.hierarchy_nullProject);
859 }
860 ICompilationUnit[] workingCopies = JavaModelManager.getJavaModelManager().getWorkingCopies(owner, true/*add primary working copies*/);
861 ICompilationUnit[] projectWCs = null;
862 if (workingCopies != null) {
863 int length = workingCopies.length;
864 projectWCs = new ICompilationUnit[length];
865 int index = 0;
866 for (int i = 0; i < length; i++) {
867 ICompilationUnit wc = workingCopies[i];
868 if (project.equals(wc.getJavaProject())) {
869 projectWCs[index++] = wc;
870 }
871 }
872 if (index != length) {
873 System.arraycopy(projectWCs, 0, projectWCs = new ICompilationUnit[index], 0, index);
874 }
875 }
876 CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(
877 this,
878 projectWCs,
879 project,
880 true);
881 op.runOperation(monitor);
882 return op.getResult();
883 }
884 /**
885 * @param monitor the given progress monitor
886 * @exception JavaModelException if this element does not exist or if an
887 * exception occurs while accessing its corresponding resource.
888 * @return a type hierarchy for this type containing
889 *
890 * @see IType#newTypeHierarchy(IProgressMonitor monitor)
891 * @deprecated
892 */
893 @Override
newTypeHierarchy(IProgressMonitor monitor)894 public ITypeHierarchy newTypeHierarchy(IProgressMonitor monitor) throws JavaModelException {
895 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=228845, consider any
896 // changes that may exist on primary working copies.
897 return newTypeHierarchy(DefaultWorkingCopyOwner.PRIMARY, monitor);
898 }
899
900 @Override
newTypeHierarchy( ICompilationUnit[] workingCopies, IProgressMonitor monitor)901 public ITypeHierarchy newTypeHierarchy(
902 ICompilationUnit[] workingCopies,
903 IProgressMonitor monitor)
904 throws JavaModelException {
905
906 CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(this, workingCopies, SearchEngine.createWorkspaceScope(), true);
907 op.runOperation(monitor);
908 return op.getResult();
909 }
910 /**
911 * @see IType#newTypeHierarchy(IWorkingCopy[], IProgressMonitor)
912 * @deprecated
913 */
914 @Override
newTypeHierarchy( IWorkingCopy[] workingCopies, IProgressMonitor monitor)915 public ITypeHierarchy newTypeHierarchy(
916 IWorkingCopy[] workingCopies,
917 IProgressMonitor monitor)
918 throws JavaModelException {
919
920 ICompilationUnit[] copies;
921 if (workingCopies == null) {
922 copies = null;
923 } else {
924 int length = workingCopies.length;
925 System.arraycopy(workingCopies, 0, copies = new ICompilationUnit[length], 0, length);
926 }
927 return newTypeHierarchy(copies, monitor);
928 }
929
930 @Override
newTypeHierarchy( WorkingCopyOwner owner, IProgressMonitor monitor)931 public ITypeHierarchy newTypeHierarchy(
932 WorkingCopyOwner owner,
933 IProgressMonitor monitor)
934 throws JavaModelException {
935
936 ICompilationUnit[] workingCopies = JavaModelManager.getJavaModelManager().getWorkingCopies(owner, true/*add primary working copies*/);
937 CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(this, workingCopies, SearchEngine.createWorkspaceScope(), true);
938 op.runOperation(monitor);
939 return op.getResult();
940 }
941 @Override
resolved(Binding binding)942 public JavaElement resolved(Binding binding) {
943 SourceRefElement resolvedHandle = new ResolvedBinaryType(this.parent, this.name, new String(binding.computeUniqueKey()));
944 resolvedHandle.occurrenceCount = this.occurrenceCount;
945 return resolvedHandle;
946 }
947 /*
948 * Returns the source file name as defined in the given info.
949 * If not present in the info, infers it from this type.
950 */
sourceFileName(IBinaryType info)951 public String sourceFileName(IBinaryType info) {
952 char[] sourceFileName = info.sourceFileName();
953 if (sourceFileName == null) {
954 /*
955 * We assume that this type has been compiled from a file with its name
956 * For example, A.class comes from A.java and p.A.class comes from a file A.java
957 * in the folder p.
958 */
959 if (info.isMember()) {
960 IType enclosingType = getDeclaringType();
961 if (enclosingType == null) return null; // play it safe
962 while (enclosingType.getDeclaringType() != null) {
963 enclosingType = enclosingType.getDeclaringType();
964 }
965 return enclosingType.getElementName() + Util.defaultJavaExtension();
966 } else if (info.isLocal() || info.isAnonymous()){
967 String typeQualifiedName = getTypeQualifiedName();
968 int dollar = typeQualifiedName.indexOf('$');
969 if (dollar == -1) {
970 // malformed inner type: name doesn't contain a dollar
971 return getElementName() + Util.defaultJavaExtension();
972 }
973 return typeQualifiedName.substring(0, dollar) + Util.defaultJavaExtension();
974 } else {
975 return getElementName() + Util.defaultJavaExtension();
976 }
977 } else {
978 int index = CharOperation.lastIndexOf('/', sourceFileName);
979 return new String(sourceFileName, index + 1, sourceFileName.length - index - 1);
980 }
981 }
982 /*
983 * @private Debugging purposes
984 */
985 @Override
toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo)986 protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
987 buffer.append(tabString(tab));
988 if (info == null) {
989 toStringName(buffer);
990 buffer.append(" (not open)"); //$NON-NLS-1$
991 } else if (info == NO_INFO) {
992 toStringName(buffer);
993 } else {
994 try {
995 if (isRecord()) {
996 buffer.append("record "); //$NON-NLS-1$
997 } else if (isAnnotation()) {
998 buffer.append("@interface "); //$NON-NLS-1$
999 } else if (isEnum()) {
1000 buffer.append("enum "); //$NON-NLS-1$
1001 } else if (isInterface()) {
1002 buffer.append("interface "); //$NON-NLS-1$
1003 } else {
1004 buffer.append("class "); //$NON-NLS-1$
1005 }
1006 toStringName(buffer);
1007 } catch (JavaModelException e) {
1008 buffer.append("<JavaModelException in toString of " + getElementName()); //$NON-NLS-1$
1009 }
1010 }
1011 }
1012 @Override
toStringName(StringBuffer buffer)1013 protected void toStringName(StringBuffer buffer) {
1014 if (getElementName().length() > 0)
1015 super.toStringName(buffer);
1016 else
1017 buffer.append("<anonymous>"); //$NON-NLS-1$
1018 }
1019 @Override
getAttachedJavadoc(IProgressMonitor monitor)1020 public String getAttachedJavadoc(IProgressMonitor monitor) throws JavaModelException {
1021 JavadocContents javadocContents = getJavadocContents(monitor);
1022 if (javadocContents == null) return null;
1023 return javadocContents.getTypeDoc();
1024 }
getJavadocContents(IProgressMonitor monitor)1025 public JavadocContents getJavadocContents(IProgressMonitor monitor) throws JavaModelException {
1026 PerProjectInfo projectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(getJavaProject().getProject());
1027 JavadocContents cachedJavadoc = null;
1028 synchronized (projectInfo.javadocCache) {
1029 cachedJavadoc = (JavadocContents) projectInfo.javadocCache.get(this);
1030 }
1031
1032 if (cachedJavadoc != null && cachedJavadoc != EMPTY_JAVADOC) {
1033 return cachedJavadoc;
1034 }
1035 URL baseLocation= getJavadocBaseLocation();
1036 if (baseLocation == null) {
1037 return null;
1038 }
1039 StringBuffer pathBuffer = new StringBuffer(baseLocation.toExternalForm());
1040
1041 if (!(pathBuffer.charAt(pathBuffer.length() - 1) == '/')) {
1042 pathBuffer.append('/');
1043 }
1044 IPackageFragment pack= getPackageFragment();
1045 String typeQualifiedName = null;
1046 if (isMember()) {
1047 IType currentType = this;
1048 StringBuffer typeName = new StringBuffer();
1049 while (currentType != null) {
1050 typeName.insert(0, currentType.getElementName());
1051 currentType = currentType.getDeclaringType();
1052 if (currentType != null) {
1053 typeName.insert(0, '.');
1054 }
1055 }
1056 typeQualifiedName = typeName.toString();
1057 } else {
1058 typeQualifiedName = getElementName();
1059 }
1060
1061 pathBuffer.append(pack.getElementName().replace('.', '/')).append('/').append(typeQualifiedName).append(JavadocConstants.HTML_EXTENSION);
1062 if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
1063 final String contents = getURLContents(baseLocation, String.valueOf(pathBuffer));
1064 JavadocContents javadocContents = new JavadocContents(this, contents);
1065 synchronized (projectInfo.javadocCache) {
1066 projectInfo.javadocCache.put(this, javadocContents);
1067 }
1068 return javadocContents;
1069 }
1070 @Override
isLambda()1071 public boolean isLambda() {
1072 return false;
1073 }
1074 }
1075