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