1 /*******************************************************************************
2  * Copyright (c) 2000, 2017 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.core.tests.model;
15 
16 import java.io.IOException;
17 
18 import org.eclipse.core.resources.IFolder;
19 import org.eclipse.core.runtime.CoreException;
20 import org.eclipse.core.runtime.IPath;
21 import org.eclipse.core.runtime.IProgressMonitor;
22 import org.eclipse.core.runtime.Path;
23 import org.eclipse.jdt.core.*;
24 import org.eclipse.jdt.core.search.IJavaSearchConstants;
25 import org.eclipse.jdt.core.search.IJavaSearchScope;
26 import org.eclipse.jdt.core.search.SearchEngine;
27 import org.eclipse.jdt.internal.core.ClasspathEntry;
28 
29 import junit.framework.Test;
30 
31 public class ClassFileTests extends ModifyingResourceTests {
32 
33 	IPackageFragmentRoot jarRoot;
34 	ICompilationUnit workingCopy;
35 	IOrdinaryClassFile classFile;
36 
ClassFileTests(String name)37 public ClassFileTests(String name) {
38 	super(name);
39 }
40 
41 // Use this static initializer to specify subset for tests
42 // All specified tests which do not belong to the class are skipped...
43 static {
44 //	TESTS_PREFIX = "testGetCategories";
45 //	TESTS_NAMES = new String[] { "testBug372687"};
46 //	TESTS_NUMBERS = new int[] { 13 };
47 //	TESTS_RANGE = new int[] { 16, -1 };
48 }
suite()49 public static Test suite() {
50 	return buildModelTestSuite(ClassFileTests.class);
51 }
52 
53 @Override
setUpSuite()54 public void setUpSuite() throws Exception {
55 	super.setUpSuite();
56 	IJavaProject javaProject = createJavaProject("P", new String[0], new String[] {"JCL15_LIB", "/P/lib"}, "", JavaCore.VERSION_1_5);
57 	String[] pathAndContents = new String[] {
58 		"nongeneric/A.java",
59 		"package nongeneric;\n" +
60 		"public class A {\n" +
61 		"}",
62 		"generic/X.java",
63 		"package generic;\n" +
64 		"public class X<T> {\n" +
65 		"  <U extends Exception> X<T> foo(X<T> x) throws RuntimeException, U {\n" +
66 		"    return null;\n" +
67 		"  }\n" +
68 		"  <K, V extends T> V foo(K key, V value) throws Exception {\n" +
69 		"    return value;\n" +
70 		"  }\n" +
71 		"}",
72 		"generic/Y.java",
73 		"package generic;\n" +
74 		"public class Y<K, L> {\n" +
75 		"}",
76 		"generic/Z.java",
77 		"package generic;\n" +
78 		"public class Z<T extends Object & I<? super T>> {\n" +
79 		"}",
80 		"generic/I.java",
81 		"package generic;\n" +
82 		"public interface I<T> {\n" +
83 		"}",
84 		"generic/W.java",
85 		"package generic;\n" +
86 		"public class W<T extends X<T> , U extends T> {\n" +
87 		"}",
88 		"generic/V.java",
89 		"package generic;\n" +
90 		"public class V extends X<Thread> implements I<String> {\n" +
91 		"}",
92 		"generic/GenericField.java",
93 		"package generic;\n" +
94 		"import java.util.Collection;\n" +
95 		"public class GenericField {\n" +
96 		"	protected Collection<String> myField;\n" +
97 		"}",
98 		"annotated/X.java",
99 		"package annotated;\n" +
100 		"@MyOtherAnnot\n" +
101 		"public class X {\n" +
102 		"  @MyOtherAnnot\n" +
103 		"  Object field;\n" +
104 		"  @MyOtherAnnot\n" +
105 		"  void method() {}\n" +
106 		"  @MyAnnot(_int=1)\n" +
107 		"  void foo01() {}\n" +
108 		"  @MyAnnot(_byte=(byte)2)\n" +
109 		"  void foo02() {}\n" +
110 		"  @MyAnnot(_short=(short)3)\n" +
111 		"  void foo03() {}\n" +
112 		"  @MyAnnot(_char='a')\n" +
113 		"  void foo04() {}\n" +
114 		"  @MyAnnot(_float=1.2f)\n" +
115 		"  void foo05() {}\n" +
116 		"  @MyAnnot(_double=3.4)\n" +
117 		"  void foo06() {}\n" +
118 		"  @MyAnnot(_boolean=true)\n" +
119 		"  void foo07() {}\n" +
120 		"  @MyAnnot(_long=123456789L)\n" +
121 		"  void foo08() {}\n" +
122 		"  @MyAnnot(_string=\"abc\")\n" +
123 		"  void foo09() {}\n" +
124 		"  @MyAnnot(_annot=@MyOtherAnnot)\n" +
125 		"  void foo10() {}\n" +
126 		"  @MyAnnot(_class=String.class)\n" +
127 		"  void foo11() {}\n" +
128 		"  @MyAnnot(_enum=MyEnum.SECOND)\n" +
129 		"  void foo12() {}\n" +
130 		"  @MyAnnot(_array={1, 2, 3})\n" +
131 		"  void foo13() {}\n" +
132 		"  @MyAnnot(_neg_int = -2)\n" +
133 		"  void foo14() {}\n" +
134 		"  @MyAnnot(_neg_float=-2.0f)\n" +
135 		"  void foo15() {}\n" +
136 		"  @MyAnnot(_neg_double=-2.0)\n" +
137 		"  void foo16() {}\n" +
138 		"  @MyAnnot(_neg_long=-2L)\n" +
139 		"  void foo17() {}\n" +
140 		"}\n" +
141 		"@interface MyAnnot {\n" +
142 		"  int _int() default 0;\n" +
143 		"  byte _byte() default 0;\n" +
144 		"  short _short() default 0;\n" +
145 		"  char _char() default ' ';\n" +
146 		"  float _float() default 0.0f;\n" +
147 		"  double _double() default 0.0;\n" +
148 		"  boolean _boolean() default false;\n" +
149 		"  long _long() default 0L;\n" +
150 		"  String _string() default \"   \";\n" +
151 		"  MyOtherAnnot _annot() default @MyOtherAnnot;\n" +
152 		"  Class _class() default Object.class;\n" +
153 		"  MyEnum _enum() default MyEnum.FIRST;\n" +
154 		"  int[] _array() default {};\n" +
155 		"  int _neg_int() default -1;\n" +
156 		"  float _neg_float() default -1.0f;\n" +
157 		"  double _neg_double() default -1.0;\n" +
158 		"  long _neg_long() default -1L;\n" +
159 		"}\n" +
160 		"@interface MyOtherAnnot {\n" +
161 		"}\n" +
162 		"enum MyEnum {\n" +
163 		"  FIRST, SECOND;\n" +
164 		"}",
165 		"annotated/Y.java",
166 		"package annotated;\n" +
167 		"import java.lang.annotation.*;\n" +
168 		"import static java.lang.annotation.ElementType.*;\n" +
169 		"import static java.lang.annotation.RetentionPolicy.*;\n" +
170 		"@Deprecated\n" +
171 		"@Documented\n" +
172 		"@Inherited\n" +
173 		"@Retention(SOURCE)\n" +
174 		"@Target({PACKAGE, TYPE, ANNOTATION_TYPE, METHOD, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, PARAMETER})\n" +
175 		"public @interface Y {\n" +
176 		"}",
177 		"varargs/X.java",
178 		"package varargs;\n" +
179 		"public class X {\n" +
180 		"  void foo(String s, Object ... others) {\n" +
181 		"  }\n" +
182 		"}",
183 		"workingcopy/X.java",
184 		"package workingcopy;\n" +
185 		"public class X {\n" +
186 		"  void foo() {\n" +
187 		"    System.out.println();\n" +
188 		"  }\n" +
189 		"}",
190 		"workingcopy/Y.java",
191 		"package workingcopy;\n" +
192 		"public class Y<W> {\n" +
193 		"  <T> T foo(T t, String... args) {\n" +
194 		"    return t;\n" +
195 		"  }\n" +
196 		"}",
197 		"annotated/MyAnnotation.java",
198 		"package annotated;\n" +
199 		"import java.lang.annotation.Retention;\n" +
200 		"import java.lang.annotation.RetentionPolicy;\n" +
201 		"@Retention(value = RetentionPolicy.RUNTIME)\n" +
202 		"public @interface MyAnnotation {}",
203 		"annotated/MyAnnotation2.java",
204 		"package annotated;\n" +
205 		"import java.lang.annotation.Retention;\n" +
206 		"import java.lang.annotation.RetentionPolicy;\n" +
207 		"@Retention(value = RetentionPolicy.SOURCE)\n" +
208 		"public @interface MyAnnotation2 {}",
209 		"annotated/MyAnnotation3.java",
210 		"package annotated;\n" +
211 		"import java.lang.annotation.Retention;\n" +
212 		"import java.lang.annotation.RetentionPolicy;\n" +
213 		"@Retention(value = RetentionPolicy.CLASS)\n" +
214 		"public @interface MyAnnotation3 {}",
215 		"test342757/X.java",
216 		"package test342757;\n" +
217 		"public class X {\n" +
218 		"	class B {\n" +
219 		"		public B(@Deprecated @Annot String s) {}\n" +
220 		"		public void foo(@Deprecated @Annot int j) {}\n" +
221 		"	}\n" +
222 		"}",
223 		"test342757/Annot.java",
224 		"package test342757;\n" +
225 		"import java.lang.annotation.Retention;\n" +
226 		"import static java.lang.annotation.RetentionPolicy.*;\n" +
227 		"@Retention(CLASS)\n" +
228 		"@interface Annot {}",
229 	};
230 	addLibrary(javaProject, "lib.jar", "libsrc.zip", pathAndContents, JavaCore.VERSION_1_5);
231 	this.jarRoot = javaProject.getPackageFragmentRoot(getFile("/P/lib.jar"));
232 }
233 
234 @Override
tearDownSuite()235 public void tearDownSuite() throws Exception {
236 	super.tearDownSuite();
237 	deleteProject("P");
238 }
239 
240 @Override
tearDown()241 protected void tearDown() throws Exception {
242 	if (this.workingCopy != null)
243 		this.workingCopy.discardWorkingCopy();
244 	if (this.classFile != null) {
245 		removeLibrary(getJavaProject("P"), "lib2.jar", "src2.zip");
246 		this.classFile = null;
247 	}
248 	super.tearDown();
249 }
250 
createClassFile(String contents)251 private IOrdinaryClassFile createClassFile(String contents) throws CoreException, IOException {
252 	IJavaProject project = getJavaProject("P");
253 	addLibrary(project, "lib2.jar", "src2.zip", new String[] {"p/X.java", contents}, "1.5");
254 	this.classFile =  project.getPackageFragmentRoot(getFile("/P/lib2.jar")).getPackageFragment("p").getOrdinaryClassFile("X.class");
255 	return this.classFile;
256 }
257 
258 /*
259  * Ensures that the annotations of a binary type are correct
260  */
testAnnotations01()261 public void testAnnotations01() throws JavaModelException {
262 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("X.class").getType();
263 	assertAnnotationsEqual(
264 		"@annotated.MyOtherAnnot\n",
265 		type.getAnnotations());
266 }
267 
268 /*
269  * Ensures that the annotations of a binary method are correct
270  */
testAnnotations02()271 public void testAnnotations02() throws JavaModelException {
272 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("X.class").getType();
273 	IMethod method = type.getMethod("method", new String[0]);
274 	assertAnnotationsEqual(
275 		"@annotated.MyOtherAnnot\n",
276 		method.getAnnotations());
277 }
278 
279 /*
280  * Ensures that the annotations of a binary field are correct
281  */
testAnnotations03()282 public void testAnnotations03() throws JavaModelException {
283 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("X.class").getType();
284 	IField field = type.getField("field");
285 	assertAnnotationsEqual(
286 		"@annotated.MyOtherAnnot\n",
287 		field.getAnnotations());
288 }
289 
290 /*
291  * Ensures that an annotation with an int value is correct
292  */
testAnnotations04()293 public void testAnnotations04() throws JavaModelException {
294 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("X.class").getType();
295 	IMethod method = type.getMethod("foo01", new String[0]);
296 	assertAnnotationsEqual(
297 		"@annotated.MyAnnot(_int=(int)1)\n",
298 		method.getAnnotations());
299 }
300 
301 /*
302  * Ensures that an annotation with a byte value is correct
303  */
testAnnotations05()304 public void testAnnotations05() throws JavaModelException {
305 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("X.class").getType();
306 	IMethod method = type.getMethod("foo02", new String[0]);
307 	assertAnnotationsEqual(
308 		"@annotated.MyAnnot(_byte=(byte)2)\n",
309 		method.getAnnotations());
310 }
311 
312 /*
313  * Ensures that an annotation with a short value is correct
314  */
testAnnotations06()315 public void testAnnotations06() throws JavaModelException {
316 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("X.class").getType();
317 	IMethod method = type.getMethod("foo03", new String[0]);
318 	assertAnnotationsEqual(
319 		"@annotated.MyAnnot(_short=(short)3)\n",
320 		method.getAnnotations());
321 }
322 
323 /*
324  * Ensures that an annotation with a char value is correct
325  */
testAnnotations07()326 public void testAnnotations07() throws JavaModelException {
327 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("X.class").getType();
328 	IMethod method = type.getMethod("foo04", new String[0]);
329 	assertAnnotationsEqual(
330 		"@annotated.MyAnnot(_char='a')\n",
331 		method.getAnnotations());
332 }
333 
334 /*
335  * Ensures that an annotation with a float value is correct
336  */
testAnnotations08()337 public void testAnnotations08() throws JavaModelException {
338 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("X.class").getType();
339 	IMethod method = type.getMethod("foo05", new String[0]);
340 	assertAnnotationsEqual(
341 		"@annotated.MyAnnot(_float=1.2f)\n",
342 		method.getAnnotations());
343 }
344 
345 /*
346  * Ensures that an annotation with a double value is correct
347  */
testAnnotations09()348 public void testAnnotations09() throws JavaModelException {
349 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("X.class").getType();
350 	IMethod method = type.getMethod("foo06", new String[0]);
351 	assertAnnotationsEqual(
352 		"@annotated.MyAnnot(_double=(double)3.4)\n",
353 		method.getAnnotations());
354 }
355 
356 /*
357  * Ensures that an annotation with a boolean value is correct
358  */
testAnnotations10()359 public void testAnnotations10() throws JavaModelException {
360 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("X.class").getType();
361 	IMethod method = type.getMethod("foo07", new String[0]);
362 	assertAnnotationsEqual(
363 		"@annotated.MyAnnot(_boolean=true)\n",
364 		method.getAnnotations());
365 }
366 
367 /*
368  * Ensures that an annotation with a long value is correct
369  */
testAnnotations11()370 public void testAnnotations11() throws JavaModelException {
371 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("X.class").getType();
372 	IMethod method = type.getMethod("foo08", new String[0]);
373 	assertAnnotationsEqual(
374 		"@annotated.MyAnnot(_long=123456789L)\n",
375 		method.getAnnotations());
376 }
377 
378 /*
379  * Ensures that an annotation with a String value is correct
380  */
testAnnotations12()381 public void testAnnotations12() throws JavaModelException {
382 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("X.class").getType();
383 	IMethod method = type.getMethod("foo09", new String[0]);
384 	assertAnnotationsEqual(
385 		"@annotated.MyAnnot(_string=\"abc\")\n",
386 		method.getAnnotations());
387 }
388 
389 /*
390  * Ensures that an annotation with an annotation value is correct
391  */
testAnnotations13()392 public void testAnnotations13() throws JavaModelException {
393 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("X.class").getType();
394 	IMethod method = type.getMethod("foo10", new String[0]);
395 	assertAnnotationsEqual(
396 		"@annotated.MyAnnot(_annot=@annotated.MyOtherAnnot)\n",
397 		method.getAnnotations());
398 }
399 
400 /*
401  * Ensures that an annotation with a Class value is correct
402  */
testAnnotations14()403 public void testAnnotations14() throws JavaModelException {
404 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("X.class").getType();
405 	IMethod method = type.getMethod("foo11", new String[0]);
406 	assertAnnotationsEqual(
407 		"@annotated.MyAnnot(_class=java.lang.String.class)\n",
408 		method.getAnnotations());
409 }
410 
411 /*
412  * Ensures that an annotation with an enumeration value is correct
413  */
testAnnotations15()414 public void testAnnotations15() throws JavaModelException {
415 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("X.class").getType();
416 	IMethod method = type.getMethod("foo12", new String[0]);
417 	assertAnnotationsEqual(
418 		"@annotated.MyAnnot(_enum=annotated.MyEnum.SECOND)\n",
419 		method.getAnnotations());
420 }
421 
422 /*
423  * Ensures that an annotation with an array value is correct
424  */
testAnnotations16()425 public void testAnnotations16() throws JavaModelException {
426 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("X.class").getType();
427 	IMethod method = type.getMethod("foo13", new String[0]);
428 	assertAnnotationsEqual(
429 		"@annotated.MyAnnot(_array={(int)1, (int)2, (int)3})\n",
430 		method.getAnnotations());
431 }
432 
433 /*
434  * Ensures that the standard annotations of a binary type are correct
435  * (regression test for https://bugs.eclipse.org/bugs/show_bug.cgi?id=248309 )
436  */
testAnnotations17()437 public void testAnnotations17() throws JavaModelException {
438 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("Y.class").getType();
439 	assertAnnotationsEqual(
440 		"@java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.LOCAL_VARIABLE, java.lang.annotation.ElementType.ANNOTATION_TYPE, java.lang.annotation.ElementType.PACKAGE})\n" +
441 		"@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)\n" +
442 		"@java.lang.Deprecated\n" +
443 		"@java.lang.annotation.Documented\n" +
444 		"@java.lang.annotation.Inherited\n",
445 		type.getAnnotations());
446 }
447 
448 /*
449  * Ensures that the annotation of a binary type exists
450  */
testAnnotations18()451 public void testAnnotations18() throws JavaModelException {
452 	IAnnotation annotation = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("X.class").getType().getAnnotation("annotated.MyOtherAnnot");
453 	assertTrue("Annotation should exist", annotation.exists());
454 }
455 
456 /*
457  * https://bugs.eclipse.org/bugs/show_bug.cgi?id=286407
458  */
testAnnotations19()459 public void testAnnotations19() throws JavaModelException {
460 	IPackageFragment packageFragment = this.jarRoot.getPackageFragment("annotated");
461 	IOrdinaryClassFile classFile2 = packageFragment.getOrdinaryClassFile("MyAnnotation.class");
462 	IType type = classFile2.getType();
463 	assertAnnotationsEqual(
464 		"@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)\n",
465 		type.getAnnotations());
466 }
467 /*
468  * https://bugs.eclipse.org/bugs/show_bug.cgi?id=286407
469  */
testAnnotations20()470 public void testAnnotations20() throws JavaModelException {
471 	IPackageFragment packageFragment = this.jarRoot.getPackageFragment("annotated");
472 	IOrdinaryClassFile classFile2 = packageFragment.getOrdinaryClassFile("MyAnnotation2.class");
473 	IType type = classFile2.getType();
474 	assertAnnotationsEqual(
475 		"@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)\n",
476 		type.getAnnotations());
477 }
478 /*
479  * https://bugs.eclipse.org/bugs/show_bug.cgi?id=286407
480  */
testAnnotations21()481 public void testAnnotations21() throws JavaModelException {
482 	IPackageFragment packageFragment = this.jarRoot.getPackageFragment("annotated");
483 	IOrdinaryClassFile classFile2 = packageFragment.getOrdinaryClassFile("MyAnnotation3.class");
484 	IType type = classFile2.getType();
485 	assertAnnotationsEqual(
486 		"@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS)\n",
487 		type.getAnnotations());
488 }
489 
490 /*
491  * https://bugs.eclipse.org/bugs/show_bug.cgi?id=248312
492  * Ensures that an annotation with a negative int value is correct
493  */
testAnnotations22()494 public void testAnnotations22() throws JavaModelException {
495 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("X.class").getType();
496 	IMethod method = type.getMethod("foo14", new String[0]);
497 	assertAnnotationsEqual(
498 		"@annotated.MyAnnot(_neg_int=(int)-2)\n",
499 		method.getAnnotations());
500 }
501 
502 /*
503  * https://bugs.eclipse.org/bugs/show_bug.cgi?id=248312
504  * Ensures that an annotation with a negative float value is correct
505  */
testAnnotations23()506 public void testAnnotations23() throws JavaModelException {
507 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("X.class").getType();
508 	IMethod method = type.getMethod("foo15", new String[0]);
509 	assertAnnotationsEqual(
510 		"@annotated.MyAnnot(_neg_float=-2.0f)\n",
511 		method.getAnnotations());
512 }
513 
514 /*
515  * https://bugs.eclipse.org/bugs/show_bug.cgi?id=248312
516  * Ensures that an annotation with a negative double value is correct
517  */
testAnnotations24()518 public void testAnnotations24() throws JavaModelException {
519 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("X.class").getType();
520 	IMethod method = type.getMethod("foo16", new String[0]);
521 	assertAnnotationsEqual(
522 		"@annotated.MyAnnot(_neg_double=(double)-2.0)\n",
523 		method.getAnnotations());
524 }
525 
526 /*
527  * https://bugs.eclipse.org/bugs/show_bug.cgi?id=248312
528  * Ensures that an annotation with a negative long value is correct
529  */
testAnnotations25()530 public void testAnnotations25() throws JavaModelException {
531 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("X.class").getType();
532 	IMethod method = type.getMethod("foo17", new String[0]);
533 	assertAnnotationsEqual(
534 		"@annotated.MyAnnot(_neg_long=-2L)\n",
535 		method.getAnnotations());
536 }
537 
538 /*
539  * https://bugs.eclipse.org/bugs/show_bug.cgi?id=342757
540  */
testAnnotations26()541 public void testAnnotations26() throws JavaModelException {
542 	IType type = this.jarRoot.getPackageFragment("test342757").getOrdinaryClassFile("X$B.class").getType();
543 	IMethod[] methods = type.getMethods();
544 	String expected =
545 			"@test342757.Annot\n" +
546 			"@java.lang.Deprecated\n" +
547 			"@test342757.Annot\n" +
548 			"@java.lang.Deprecated\n";
549 	StringBuffer buffer = new StringBuffer();
550 	for (int i = 0, max = methods.length; i < max; i++) {
551 		ILocalVariable[] parameters = methods[i].getParameters();
552 		for (int j = 0, max2 = parameters.length; j < max2; j++) {
553 			IAnnotation[] annotations = parameters[j].getAnnotations();
554 			for (int n = 0; n < annotations.length; n++) {
555 				IAnnotation annotation = annotations[n];
556 				appendAnnotation(buffer, annotation);
557 				buffer.append("\n");
558 			}
559 		}
560 	}
561 	String actual = buffer.toString();
562 	if (!expected.equals(actual)) {
563 		System.out.println(displayString(actual, 2) + this.endChar);
564 	}
565 	assertEquals("Unexpected annotations", expected, actual);
566 }
567 
568 /*
569  * Ensures that no exception is thrown for a .class file name with a dot
570  * (regression test for bug 114140 assertion failed when opening a class file not not the classpath)
571  */
testDotName()572 public void testDotName() throws JavaModelException {
573 	IType type = getClassFile("/P/X.Y.class").getType();
574 	assertEquals("X.Y", type.getElementName());
575 }
576 
577 /*
578  * Ensure that the exception types of a binary method are correct.
579  */
testExceptionTypes1()580 public void testExceptionTypes1() throws JavaModelException {
581 	IType type = this.jarRoot.getPackageFragment("generic").getOrdinaryClassFile("X.class").getType();
582 	IMethod method = type.getMethod("foo", new String[] {"TK;", "TV;"});
583 	assertStringsEqual(
584 		"Unexpected return type",
585 		"Ljava.lang.Exception;\n",
586 		method.getExceptionTypes());
587 }
588 
589 /*
590  * Ensure that the exception types of a binary method is correct.
591  */
testExceptionTypes2()592 public void testExceptionTypes2() throws JavaModelException {
593 	IType type = this.jarRoot.getPackageFragment("generic").getOrdinaryClassFile("X.class").getType();
594 	IMethod method = type.getMethod("foo", new String[] {"Lgeneric.X<TT;>;"});
595 	assertStringsEqual(
596 		"Unexpected return type",
597 		"Ljava.lang.RuntimeException;\n" +
598 		"TU;\n",
599 		method.getExceptionTypes());
600 }
601 
602 /*
603  * Ensure that the categories for a class are correct.
604  */
testGetCategories01()605 public void testGetCategories01() throws CoreException, IOException {
606 	createClassFile(
607 		"package p;\n" +
608 		"/**\n" +
609 		" * @category test\n" +
610 		" */\n" +
611 		"public class X {\n" +
612 		"}"
613 	);
614 	String[] categories = this.classFile.getType().getCategories();
615 	assertStringsEqual(
616 		"Unexpected categories",
617 		"test\n",
618 		categories);
619 }
testGetCategories02()620 public void testGetCategories02() throws CoreException, IOException {
621 	createClassFile(
622 		"package p;\n" +
623 		"/**\n" +
624 		" * @category test1 test2 test3 test4 test5 test6 test7 test8 test9 test10\n" +
625 		" */\n" +
626 		"public class X {\n" +
627 		"}"
628 	);
629 	String[] categories = this.classFile.getType().getCategories();
630 	assertStringsEqual(
631 		"Unexpected categories",
632 		"test1\ntest2\ntest3\ntest4\ntest5\ntest6\ntest7\ntest8\ntest9\ntest10\n",
633 		categories);
634 }
635 
636 /*
637  * Ensure that the categories for a field are correct.
638  */
testGetCategories03()639 public void testGetCategories03() throws CoreException, IOException {
640 	createClassFile(
641 		"package p;\n" +
642 		"public class X {\n" +
643 		"  /**\n" +
644 		"   * @category test\n" +
645 		"   */\n" +
646 		"  int field;\n" +
647 		"}"
648 	);
649 	String[] categories = this.classFile.getType().getField("field").getCategories();
650 	assertStringsEqual(
651 		"Unexpected categories",
652 		"test\n",
653 		categories);
654 }
testGetCategories04()655 public void testGetCategories04() throws CoreException, IOException {
656 	createClassFile(
657 		"package p;\n" +
658 		"public class X {\n" +
659 		"  /**\n" +
660 		"   * @category test1 test2\n" +
661 		"   */\n" +
662 		"  int field;\n" +
663 		"}"
664 	);
665 	String[] categories = this.classFile.getType().getField("field").getCategories();
666 	assertStringsEqual(
667 		"Unexpected categories",
668 		"test1\ntest2\n",
669 		categories);
670 }
671 
672 /*
673  * Ensure that the categories for a method are correct.
674  */
testGetCategories05()675 public void testGetCategories05() throws CoreException, IOException {
676 	createClassFile(
677 		"package p;\n" +
678 		"public class X {\n" +
679 		"  /**\n" +
680 		" * @category test\n" +
681 		"   */\n" +
682 		"  void foo() {}\n" +
683 		"}"
684 	);
685 	String[] categories = this.classFile.getType().getMethod("foo", new String[0]).getCategories();
686 	assertStringsEqual(
687 		"Unexpected categories",
688 		"test\n",
689 		categories);
690 }
testGetCategories06()691 public void testGetCategories06() throws CoreException, IOException {
692 	createClassFile(
693 		"package p;\n" +
694 		"public class X {\n" +
695 		"  /**\n" +
696 		" * @category test1 test2 test3 test4 test5\n" +
697 		"   */\n" +
698 		"  void foo() {}\n" +
699 		"}"
700 	);
701 	String[] categories = this.classFile.getType().getMethod("foo", new String[0]).getCategories();
702 	assertStringsEqual(
703 		"Unexpected categories",
704 		"test1\ntest2\ntest3\ntest4\ntest5\n",
705 		categories);
706 }
707 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=125676
testGetCategories07()708 public void testGetCategories07() throws CoreException, IOException {
709 	createClassFile(
710 		"package p;\n" +
711 		"public class X {\n" +
712 		"  /**\n" +
713 		"   * @category " +
714 		"	 *		test\n" +
715 		"   */\n" +
716 		"  void foo() {}\n" +
717 		"}"
718 	);
719 	String[] categories = this.classFile.getType().getMethod("foo", new String[0]).getCategories();
720 	assertStringsEqual(
721 		"Unexpected categories",
722 		"",
723 		categories);
724 }
testGetCategories08()725 public void testGetCategories08() throws CoreException, IOException {
726 	createClassFile(
727 		"package p;\n" +
728 		"public class X {\n" +
729 		"  /**\n" +
730 		"   * @category" +
731 		"	 *		test\n" +
732 		"   */\n" +
733 		"  void foo() {}\n" +
734 		"}"
735 	);
736 	String[] categories = this.classFile.getType().getMethod("foo", new String[0]).getCategories();
737 	assertStringsEqual(
738 		"Unexpected categories",
739 		"",
740 		categories);
741 }
testGetCategories09()742 public void testGetCategories09() throws CoreException, IOException {
743 	createClassFile(
744 		"package p;\n" +
745 		"public class X {\n" +
746 		"  /**\n" +
747 		"   * @category test1" +
748 		"	 *		test2\n" +
749 		"   */\n" +
750 		"  void foo() {}\n" +
751 		"}"
752 	);
753 	String[] categories = this.classFile.getType().getMethod("foo", new String[0]).getCategories();
754 	assertStringsEqual(
755 		"Unexpected categories",
756 		"test1\n",
757 		categories);
758 }
759 
760 /*
761  * Ensure that the categories for a member that has no categories when another member defines some are correct.
762  */
testGetCategories10()763 public void testGetCategories10() throws CoreException, IOException {
764 	createClassFile(
765 		"package p;\n" +
766 		"public class X {\n" +
767 		"  int field1;\n" +
768 		"  /**\n" +
769 		"   * @category test\n" +
770 		"   */\n" +
771 		"  int field2;\n" +
772 		"}"
773 	);
774 	String[] categories = this.classFile.getType().getField("field1").getCategories();
775 	assertStringsEqual(
776 		"Unexpected categories",
777 		"",
778 		categories);
779 }
780 
781 /*
782  * Ensures that the children of a type for a given category are correct.
783  */
testGetChildrenForCategory01()784 public void testGetChildrenForCategory01() throws CoreException, IOException {
785 	createClassFile(
786 		"package p;\n" +
787 		"public class X {\n" +
788 		"  /**\n" +
789 		"   * @category test\n" +
790 		"   */\n" +
791 		"  int field;\n" +
792 		"  /**\n" +
793 		"   * @category test\n" +
794 		"   */\n" +
795 		"  void foo1() {}\n" +
796 		"  /**\n" +
797 		"   * @category test\n" +
798 		"   */\n" +
799 		"  void foo2() {}\n" +
800 		"  /**\n" +
801 		"   * @category other\n" +
802 		"   */\n" +
803 		"  void foo3() {}\n" +
804 		"}"
805 	);
806 	IJavaElement[] children = this.classFile.getType().getChildrenForCategory("test");
807 	assertElementsEqual(
808 		"Unexpected children",
809 		"field [in X [in X.class [in p [in lib2.jar [in P]]]]]\n" +
810 		"foo1() [in X [in X.class [in p [in lib2.jar [in P]]]]]\n" +
811 		"foo2() [in X [in X.class [in p [in lib2.jar [in P]]]]]",
812 		children);
813 }
testGetChildrenForCategory02()814 public void testGetChildrenForCategory02() throws CoreException, IOException {
815 	createClassFile(
816 		"package p;\n" +
817 		"public class X {\n" +
818 		"  /**\n" +
819 		"   * @category fields test all\n" +
820 		"   */\n" +
821 		"  int field;\n" +
822 		"  /**\n" +
823 		"   * @category methods test all\n" +
824 		"   */\n" +
825 		"  void foo1() {}\n" +
826 		"  /**\n" +
827 		"   * @category methods test all\n" +
828 		"   */\n" +
829 		"  void foo2() {}\n" +
830 		"  /**\n" +
831 		"   * @category methods other all\n" +
832 		"   */\n" +
833 		"  void foo3() {}\n" +
834 		"}"
835 	);
836 	IJavaElement[] tests  = this.classFile.getType().getChildrenForCategory("test");
837 	assertElementsEqual(
838 		"Unexpected children",
839 		"field [in X [in X.class [in p [in lib2.jar [in P]]]]]\n" +
840 		"foo1() [in X [in X.class [in p [in lib2.jar [in P]]]]]\n" +
841 		"foo2() [in X [in X.class [in p [in lib2.jar [in P]]]]]",
842 		tests);
843 	IJavaElement[] methods = this.classFile.getType().getChildrenForCategory("methods");
844 	assertElementsEqual(
845 		"Unexpected children",
846 		"foo1() [in X [in X.class [in p [in lib2.jar [in P]]]]]\n" +
847 		"foo2() [in X [in X.class [in p [in lib2.jar [in P]]]]]\n" +
848 		"foo3() [in X [in X.class [in p [in lib2.jar [in P]]]]]",
849 		methods);
850 	IJavaElement[] others = this.classFile.getType().getChildrenForCategory("other");
851 	assertElementsEqual(
852 		"Unexpected children",
853 		"foo3() [in X [in X.class [in p [in lib2.jar [in P]]]]]",
854 		others);
855 	IJavaElement[] all = this.classFile.getType().getChildrenForCategory("all");
856 	assertElementsEqual(
857 		"Unexpected children",
858 		"field [in X [in X.class [in p [in lib2.jar [in P]]]]]\n" +
859 		"foo1() [in X [in X.class [in p [in lib2.jar [in P]]]]]\n" +
860 		"foo2() [in X [in X.class [in p [in lib2.jar [in P]]]]]\n" +
861 		"foo3() [in X [in X.class [in p [in lib2.jar [in P]]]]]",
862 		all);
863 }
864 
865 /*
866  * Ensures that the default value for an annotation method is correct.
867  */
testDefaultValue1()868 public void testDefaultValue1() throws JavaModelException {
869 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("MyAnnot.class").getType();
870 	IMethod method = type.getMethod("_int", new String[0]);
871 	assertMemberValuePairEquals(
872 		"_int=(int)0",
873 		method.getDefaultValue());
874 }
875 
876 /*
877  * Ensures that the default value for an annotation method is correct.
878  */
testDefaultValue2()879 public void testDefaultValue2() throws JavaModelException {
880 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("MyAnnot.class").getType();
881 	IMethod method = type.getMethod("_annot", new String[0]);
882 	assertMemberValuePairEquals(
883 		"_annot=@annotated.MyOtherAnnot",
884 		method.getDefaultValue());
885 }
886 
887 /*
888  * Ensures that the default value for an annotation method is correct.
889  */
testDefaultValue3()890 public void testDefaultValue3() throws JavaModelException {
891 	IType type = this.jarRoot.getPackageFragment("annotated").getOrdinaryClassFile("MyAnnot.class").getType();
892 	IMethod method = type.getMethod("_array", new String[0]);
893 	assertMemberValuePairEquals(
894 		"_array=[unknown]{}",
895 		method.getDefaultValue());
896 }
897 
898 
899 /*
900  * Ensures that the default value for an regular method is correct.
901  */
testDefaultValue4()902 public void testDefaultValue4() throws JavaModelException {
903 	IType type = getPackageFragmentRoot("P", getExternalJCLPathString(JavaCore.VERSION_1_5)).getPackageFragment("java.lang").getOrdinaryClassFile("Object.class").getType();
904 	IMethod method = type.getMethod("toString", new String[0]);
905 	assertMemberValuePairEquals(
906 		"<null>",
907 		method.getDefaultValue());
908 }
909 
910 /*
911  * Ensures that getFullyQualifiedName() behaves correctly for a top level binary type
912  */
testGetFullyQualifiedName1()913 public void testGetFullyQualifiedName1() {
914 	IType type = getClassFile("/P/lib/p/X.class").getType();
915 	assertEquals("p.X", type.getFullyQualifiedName());
916 }
917 
918 /*
919  * Ensures that getFullyQualifiedName() behaves correctly for a top level binary type
920  */
testGetFullyQualifiedName2()921 public void testGetFullyQualifiedName2() {
922 	IType type = getClassFile("/P/lib/X.class").getType();
923 	assertEquals("X", type.getFullyQualifiedName());
924 }
925 
926 /*
927  * Ensures that getFullyQualifiedName() behaves correctly for a member type
928  */
testGetFullyQualifiedName3()929 public void testGetFullyQualifiedName3() {
930 	IType type = getClassFile("/P/lib/p/X$Member.class").getType();
931 	assertEquals("p.X$Member", type.getFullyQualifiedName());
932 }
933 
934 /*
935  * Ensures that getFullyQualifiedName() behaves correctly for a local type
936  */
testGetFullyQualifiedName4()937 public void testGetFullyQualifiedName4() {
938 	IType type = getClassFile("/P/lib/p/X$Local.class").getType();
939 	assertEquals("p.X$Local", type.getFullyQualifiedName());
940 }
941 
942 /*
943  * Ensures that getFullyQualifiedName('.') behaves correctly for a top level binary type
944  */
testGetFullyQualifiedName5()945 public void testGetFullyQualifiedName5() {
946 	IType type = getClassFile("/P/lib/p/X.class").getType();
947 	assertEquals("p.X", type.getFullyQualifiedName('.'));
948 }
949 
950 /*
951  * Ensures that getFullyQualifiedName('.') behaves correctly for a top level binary type
952  */
testGetFullyQualifiedName6()953 public void testGetFullyQualifiedName6() {
954 	IType type = getClassFile("/P/lib/X.class").getType();
955 	assertEquals("X", type.getFullyQualifiedName('.'));
956 }
957 
958 /*
959  * Ensures that getFullyQualifiedName() behaves correctly for a member type
960  */
testGetFullyQualifiedName7()961 public void testGetFullyQualifiedName7() {
962 	IType type = getClassFile("/P/lib/p/X$Member.class").getType();
963 	assertEquals("p.X.Member", type.getFullyQualifiedName('.'));
964 }
965 
966 /*
967  * Ensures that getFullyQualifiedName() behaves correctly for a local type
968  */
testGetFullyQualifiedName8()969 public void testGetFullyQualifiedName8() {
970 	IType type = getClassFile("/P/lib/p/X$Local.class").getType();
971 	assertEquals("p.X.Local", type.getFullyQualifiedName('.'));
972 }
973 
974 /*
975  * Ensures that the resource of a .class file in an external folder is null
976  */
testGetResource()977 public void testGetResource() throws Exception {
978 	try {
979 		createExternalFolder("externalLib/p");
980 		createExternalFile("externalLib/p/X.class", "");
981 		createJavaProject("P1", new String[0], new String[] {getExternalResourcePath("externalLib")}, "");
982 		IOrdinaryClassFile classFile1 = getClassFile("P1", getExternalResourcePath("externalLib"), "p", "X.class");
983 		assertResourceEquals(
984 			"Unexpected resource",
985 			"<null>",
986 			classFile1.getResource());
987 	} finally {
988 		deleteExternalResource("externalLib");
989 		deleteProject("P1");
990 	}
991 }
992 
993 /*
994  * Ensures that IType#getSuperclassTypeSignature() is correct for a binary type.
995  * (regression test for bug 78520 [model] IType#getSuperInterfaceTypeSignatures() doesn't include type arguments)
996  */
testGetSuperclassTypeSignature()997 public void testGetSuperclassTypeSignature() throws JavaModelException {
998 	IType type = this.jarRoot.getPackageFragment("generic").getOrdinaryClassFile("V.class").getType();
999 	assertEquals(
1000 		"Unexpected signature",
1001 		"Lgeneric.X<Ljava.lang.Thread;>;",
1002 		type.getSuperclassTypeSignature());
1003 }
1004 
1005 /*
1006  * Ensures that IType#getSuperInterfaceTypeSignatures() is correct for a binary type.
1007  * (regression test for bug 78520 [model] IType#getSuperInterfaceTypeSignatures() doesn't include type arguments)
1008  */
testGetSuperInterfaceTypeSignatures()1009 public void testGetSuperInterfaceTypeSignatures() throws JavaModelException {
1010 	IType type = this.jarRoot.getPackageFragment("generic").getOrdinaryClassFile("V.class").getType();
1011 	assertStringsEqual(
1012 		"Unexpected signatures",
1013 		"Lgeneric.I<Ljava.lang.String;>;\n",
1014 		type.getSuperInterfaceTypeSignatures());
1015 }
1016 
1017 /*
1018  * Ensures that if a root folder (that has a jar like name) is opened, and then a Jar package fragment root created on this root folder,
1019  * then attempting to open a class file in this folder doesn't throw a ClassCastException
1020  * (regression test for bug 204652 "Open Type": ClassCastException in conjunction with a class folder)
1021  */
testJarLikeRootFolder()1022 public void testJarLikeRootFolder() throws CoreException {
1023 	try {
1024 		IJavaProject p = createJavaProject("P1", new String[0], new String[] {"/P1/classFolder.jar"}, "");
1025 		IFolder folder = createFolder("/P1/classFolder.jar/p");
1026 		createFile("/P1/classFolder.jar/X.class", "p");
1027 
1028 		// populate cache with a valid package fragment root and a valid package fragment
1029 		IPackageFragment validPkg = p.getPackageFragmentRoot(folder.getParent()).getPackageFragment("p");
1030 		validPkg.open(null);
1031 
1032 		// create an invalid package fragment root and an invalid package fragment
1033 		IPackageFragment invalidPkg = p.getPackageFragmentRoot("/P1/classFolder.jar").getPackageFragment("p");
1034 
1035 		// ensure that the class file cannot be opened with a valid exception
1036 		IOrdinaryClassFile openable = invalidPkg.getOrdinaryClassFile("X.class");
1037 		JavaModelException expected = null;
1038 		try {
1039 			openable.open(null);
1040 		} catch (JavaModelException e) {
1041 			expected = e;
1042 		}
1043 		assertExceptionEquals("Unexpected exception", new Path("/P1/classFolder.jar").toOSString() + " does not exist", expected);
1044 	} finally {
1045 		deleteProject("P1");
1046 	}
1047 }
1048 
1049 /*
1050  * Ensures that the parameter names of a binary method with source attached are correct.
1051  */
testParameterNames01()1052 public void testParameterNames01() throws CoreException {
1053 	IMethod method = this.jarRoot.getPackageFragment("generic").getOrdinaryClassFile("X.class").getType().getMethod("foo", new String[] {"TK;", "TV;"});
1054 	String[] parameterNames = method.getParameterNames();
1055 	assertStringsEqual(
1056 		"Unexpected parameter names",
1057 		"key\n" +
1058 		"value\n",
1059 		parameterNames);
1060 }
1061 
1062 /*
1063  * Ensures that the parameter names of a binary method without source attached are correct.
1064  */
testParameterNames02()1065 public void testParameterNames02() throws CoreException {
1066 	IPath sourceAttachmentPath = this.jarRoot.getSourceAttachmentPath();
1067 	try {
1068 		attachSource(this.jarRoot, null, null);
1069 		IMethod method = this.jarRoot.getPackageFragment("generic").getOrdinaryClassFile("X.class").getType().getMethod("foo", new String[] {"TK;", "TV;"});
1070 		String[] parameterNames = method.getParameterNames();
1071 		assertStringsEqual(
1072 			"Unexpected parameter names",
1073 			"key\n" +
1074 			"value\n",
1075 			parameterNames);
1076 	} finally {
1077 		attachSource(this.jarRoot, sourceAttachmentPath.toString(), null);
1078 	}
1079 }
1080 
1081 /**
1082  * Ensure that the type parameter signatures of a binary type are correct.
1083  */
testParameterTypeSignatures1()1084 public void testParameterTypeSignatures1() throws JavaModelException {
1085 	IType type = this.jarRoot.getPackageFragment("generic").getOrdinaryClassFile("X.class").getType();
1086 	assertStringsEqual(
1087 		"Unexpected type parameters",
1088 		"T:Ljava.lang.Object;\n",
1089 		type.getTypeParameterSignatures());
1090 }
1091 
1092 /**
1093  * Ensure that the type parameter signatures of a binary type are correct.
1094  */
testParameterTypeSignatures2()1095 public void testParameterTypeSignatures2() throws JavaModelException {
1096 	IType type = this.jarRoot.getPackageFragment("nongeneric").getOrdinaryClassFile("A.class").getType();
1097 	assertStringsEqual(
1098 		"Unexpected type parameters",
1099 		"",
1100 		type.getTypeParameterSignatures());
1101 }
1102 
1103 /**
1104  * Ensure that the type parameter signatures of a binary type are correct.
1105  */
testParameterTypeSignatures3()1106 public void testParameterTypeSignatures3() throws JavaModelException {
1107 	IType type = this.jarRoot.getPackageFragment("generic").getOrdinaryClassFile("Y.class").getType();
1108 	assertStringsEqual(
1109 		"Unexpected type parameters",
1110 		"K:Ljava.lang.Object;\n" +
1111 		"L:Ljava.lang.Object;\n",
1112 		type.getTypeParameterSignatures());
1113 }
1114 
1115 /**
1116  * Ensure that the type parameter signatures of a binary type are correct.
1117  */
testParameterTypeSignatures4()1118 public void testParameterTypeSignatures4() throws JavaModelException {
1119 	IType type = this.jarRoot.getPackageFragment("generic").getOrdinaryClassFile("Z.class").getType();
1120 	assertStringsEqual(
1121 		"Unexpected type parameters",
1122 		"T:Ljava.lang.Object;:Lgeneric.I<-TT;>;\n",
1123 		type.getTypeParameterSignatures());
1124 }
1125 
1126 /**
1127  * Ensure that the type parameter signatures of a binary type are correct.
1128  */
testParameterTypeSignatures5()1129 public void testParameterTypeSignatures5() throws JavaModelException {
1130 	IType type = this.jarRoot.getPackageFragment("generic").getOrdinaryClassFile("W.class").getType();
1131 	assertStringsEqual(
1132 		"Unexpected type parameters",
1133 		"T:Lgeneric.X<TT;>;\n" +
1134 		"U:TT;\n",
1135 		type.getTypeParameterSignatures());
1136 }
1137 
1138 /**
1139  * Ensure that the type parameter signatures of a binary method are correct.
1140  * @deprecated
1141  */
testParameterTypeSignatures6()1142 public void testParameterTypeSignatures6() throws JavaModelException {
1143 	IType type = this.jarRoot.getPackageFragment("generic").getOrdinaryClassFile("X.class").getType();
1144 	IMethod method = type.getMethod("foo", new String[] {"TK;", "TV;"});
1145 	assertStringsEqual(
1146 		"Unexpected type parameters",
1147 		"K:Ljava.lang.Object;\n" +
1148 		"V:TT;\n",
1149 		method.getTypeParameterSignatures());
1150 }
1151 
1152 /*
1153  * Ensures that the raw parameter names of a binary method with source attached are correct.
1154  */
testRawParameterNames01()1155 public void testRawParameterNames01() throws CoreException {
1156 	IMethod method = this.jarRoot.getPackageFragment("generic").getOrdinaryClassFile("X.class").getType().getMethod("foo", new String[] {"TK;", "TV;"});
1157 	String[] parameterNames = method.getRawParameterNames();
1158 	assertStringsEqual(
1159 		"Unexpected parameter names",
1160 		"arg0\n" +
1161 		"arg1\n",
1162 		parameterNames);
1163 }
1164 
1165 /*
1166  * Ensures that the raw parameter names of a binary method without source attached are correct.
1167  */
testRawParameterNames02()1168 public void testRawParameterNames02() throws CoreException {
1169 	IPath sourceAttachmentPath = this.jarRoot.getSourceAttachmentPath();
1170 	try {
1171 		attachSource(this.jarRoot, null, null);
1172 		IMethod method = this.jarRoot.getPackageFragment("generic").getOrdinaryClassFile("X.class").getType().getMethod("foo", new String[] {"TK;", "TV;"});
1173 		String[] parameterNames = method.getParameterNames();
1174 		assertStringsEqual(
1175 			"Unexpected parameter names",
1176 			"key\n" +
1177 			"value\n",
1178 			parameterNames);
1179 	} finally {
1180 		attachSource(this.jarRoot, sourceAttachmentPath.toString(), null);
1181 	}
1182 }
1183 
1184 /*
1185  * Ensure that the return type of a binary method is correct.
1186  */
testReturnType1()1187 public void testReturnType1() throws JavaModelException {
1188 	IType type = this.jarRoot.getPackageFragment("generic").getOrdinaryClassFile("X.class").getType();
1189 	IMethod method = type.getMethod("foo", new String[] {"TK;", "TV;"});
1190 	assertEquals(
1191 		"Unexpected return type",
1192 		"TV;",
1193 		method.getReturnType());
1194 }
1195 
1196 /*
1197  * Ensure that the return type of a binary method is correct.
1198  */
testReturnType2()1199 public void testReturnType2() throws JavaModelException {
1200 	IType type = this.jarRoot.getPackageFragment("generic").getOrdinaryClassFile("X.class").getType();
1201 	IMethod method = type.getMethod("foo", new String[] {"Lgeneric.X<TT;>;"});
1202 	assertEquals(
1203 		"Unexpected return type",
1204 		"Lgeneric.X<TT;>;",
1205 		method.getReturnType());
1206 }
1207 
1208 /*
1209  * Ensures that asking for the source range of a IOrdinaryClassFile in a non-Java project throws a JavaModelException
1210  * (regression test for bug 132494 JavaModelException opening up class file in non java project)
1211  */
testSourceRange1()1212 public void testSourceRange1() throws CoreException { // was testSourceRangeNonJavaProject()
1213 	try {
1214 		createProject("Simple");
1215 		createFile("/Simple/X.class", "");
1216 		IOrdinaryClassFile classX = getClassFile("/Simple/X.class");
1217 		JavaModelException exception = null;
1218 		try {
1219 			classX.getSourceRange();
1220 		} catch (JavaModelException e) {
1221 			exception = e;
1222 		}
1223 		assertExceptionEquals("Unexpected exception", "Simple does not exist", exception);
1224 	} finally {
1225 		deleteProject("Simple");
1226 	}
1227 }
1228 
1229 /*
1230  * Ensures that asking for the source range of a IOrdinaryClassFile not on the classpath of a Java project doesn't throw a JavaModelException
1231  * (regression test for bug 138507 exception in .class file editor for classes imported via plug-in import)
1232  */
testSourceRange2()1233 public void testSourceRange2() throws CoreException { // was testSourceRangeNotOnClasspath()
1234 	try {
1235 		createJavaProject("P2", new String[] {"src"}, "bin");
1236 		createFile("/P2/bin/X.class", "");
1237 		IOrdinaryClassFile classX = getClassFile("/P2/bin/X.class");
1238 		assertNull("Unxepected source range", classX.getSourceRange());
1239 	} finally {
1240 		deleteProject("P2");
1241 	}
1242 }
1243 
1244 /*
1245  * Ensures that asking for the source range of a IOrdinaryClassFile in proj==src case without the corresponding .java file doesn't throw a JavaModelException
1246  * (regression test for bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=221904 )
1247  */
testSourceRange3()1248 public void testSourceRange3() throws CoreException {
1249 	try {
1250 		createJavaProject("P2", new String[] {""}, "");
1251 		createFile("/P2/X.class", "");
1252 		IOrdinaryClassFile classX = getClassFile("/P2/X.class");
1253 		assertNull("Unxepected source range", classX.getSourceRange());
1254 	} finally {
1255 		deleteProject("P2");
1256 	}
1257 }
1258 
1259 /*
1260  * Ensure that opening a binary type parameter when its parent has not been open yet
1261  * doesn't throw a JavaModelException
1262  * (regression test for bug 101228 JME on code assist)
1263  */
testTypeParameter()1264 public void testTypeParameter() throws CoreException {
1265 	IOrdinaryClassFile clazz = this.jarRoot.getPackageFragment("generic").getOrdinaryClassFile("X.class");
1266 	ITypeParameter typeParameter = clazz.getType().getTypeParameter("T");
1267 	clazz.close();
1268 	assertStringsEqual(
1269 		"Unexpected bounds",
1270 		"java.lang.Object\n",
1271 		typeParameter.getBounds());
1272 }
1273 
1274 /*
1275  * Ensure that a method with varargs has the AccVarargs flag set.
1276  */
testVarargs()1277 public void testVarargs() throws JavaModelException {
1278 	IType type = this.jarRoot.getPackageFragment("varargs").getOrdinaryClassFile("X.class").getType();
1279 	IMethod method = type.getMethod("foo", new String[]{"Ljava.lang.String;", "[Ljava.lang.Object;"});
1280 	assertTrue("Should have the AccVarargs flag set", Flags.isVarargs(method.getFlags()));
1281 }
1282 
1283 /*
1284  * Ensures that a class file can be turned into a working copy and that its children are correct.
1285  */
testWorkingCopy01()1286 public void testWorkingCopy01() throws CoreException {
1287 	IOrdinaryClassFile clazz = this.jarRoot.getPackageFragment("workingcopy").getOrdinaryClassFile("X.class");
1288 	this.workingCopy = clazz.getWorkingCopy(null/*primary owner*/, (IProgressMonitor) null/*no progress*/);
1289 	assertElementDescendants(
1290 		"Unexpected children",
1291 		"[Working copy] X.class\n" +
1292 		"  package workingcopy\n" +
1293 		"  class X\n" +
1294 		"    void foo()",
1295 		this.workingCopy);
1296 }
1297 
1298 /*
1299  * Ensures that a class file without source attached can be turned into a working copy and that its children are correct.
1300  */
testWorkingCopy02()1301 public void testWorkingCopy02() throws CoreException {
1302 	IPath sourceAttachmentPath = this.jarRoot.getSourceAttachmentPath();
1303 	try {
1304 		attachSource(this.jarRoot, null, null);
1305 		IOrdinaryClassFile clazz = this.jarRoot.getPackageFragment("workingcopy").getOrdinaryClassFile("X.class");
1306 		assertNull("Should not have source attached", clazz.getSource());
1307 		this.workingCopy = clazz.getWorkingCopy(null/*primary owner*/, (IProgressMonitor) null/*no progress*/);
1308 		assertElementDescendants(
1309 			"Unexpected children",
1310 			"[Working copy] X.class\n" +
1311 			"  package workingcopy\n" +
1312 			"  class X\n" +
1313 			"    X()\n" +
1314 			"    void foo()",
1315 			this.workingCopy);
1316 	} finally {
1317 		attachSource(this.jarRoot, sourceAttachmentPath.toString(), null);
1318 	}
1319 }
1320 
1321 /*
1322  * Ensures that a class file can be turned into a working copy, modified and that its children are correct.
1323  */
testWorkingCopy03()1324 public void testWorkingCopy03() throws CoreException {
1325 	IOrdinaryClassFile clazz = this.jarRoot.getPackageFragment("workingcopy").getOrdinaryClassFile("X.class");
1326 	this.workingCopy = clazz.getWorkingCopy(null/*primary owner*/, (IProgressMonitor) null/*no progress*/);
1327 	this.workingCopy.getBuffer().setContents(
1328 		"package workingcopy;\n" +
1329 		"public class X {\n" +
1330 		"  void bar() {\n" +
1331 		"  }\n" +
1332 		"}"
1333 	);
1334 	this.workingCopy.reconcile(ICompilationUnit.NO_AST, false/*don't force problems*/, null/*primary owner*/, null/*no progress*/);
1335 	assertElementDescendants(
1336 		"Unexpected children",
1337 		"[Working copy] X.class\n" +
1338 		"  package workingcopy\n" +
1339 		"  class X\n" +
1340 		"    void bar()",
1341 		this.workingCopy);
1342 }
1343 
1344 /*
1345  * Ensures that a class file working copy cannot be commited
1346  */
testWorkingCopy04()1347 public void testWorkingCopy04() throws CoreException {
1348 	IOrdinaryClassFile clazz = this.jarRoot.getPackageFragment("workingcopy").getOrdinaryClassFile("X.class");
1349 	this.workingCopy = clazz.getWorkingCopy(null/*primary owner*/, (IProgressMonitor) null/*no progress*/);
1350 	this.workingCopy.getBuffer().setContents(
1351 		"package workingcopy;\n" +
1352 		"public class X {\n" +
1353 		"  void bar() {\n" +
1354 		"  }\n" +
1355 		"}"
1356 	);
1357 	JavaModelException exception = null;
1358 	try {
1359 		this.workingCopy.commitWorkingCopy(false/*don't force*/, null);
1360 	} catch (JavaModelException e) {
1361 		exception = e;
1362 	}
1363 	assertEquals(
1364 		"Unxepected JavaModelException",
1365 		"Java Model Exception: Java Model Status [Operation not supported for specified element type(s):[Working copy] X.class [in workingcopy [in lib.jar [in P]]]]",
1366 		exception.toString());
1367 }
1368 
1369 /*
1370  * Ensures that a type can be created in class file working copy.
1371  */
testWorkingCopy05()1372 public void testWorkingCopy05() throws CoreException {
1373 	IOrdinaryClassFile clazz = this.jarRoot.getPackageFragment("workingcopy").getOrdinaryClassFile("X.class");
1374 	this.workingCopy = clazz.getWorkingCopy(null/*primary owner*/, (IProgressMonitor) null/*no progress*/);
1375 	this.workingCopy.createType(
1376 		"class Y {\n" +
1377 		"}",
1378 		null,
1379 		false/*don't force*/,
1380 		null);
1381 	assertElementDescendants(
1382 		"Unexpected children",
1383 		"[Working copy] X.class\n" +
1384 		"  package workingcopy\n" +
1385 		"  class X\n" +
1386 		"    void foo()\n" +
1387 		"  class Y",
1388 		this.workingCopy);
1389 }
1390 
1391 /*
1392  * Ensures that the primary compilation unit of class file working copy is correct.
1393  */
testWorkingCopy06()1394 public void testWorkingCopy06() throws CoreException {
1395 	IOrdinaryClassFile clazz = this.jarRoot.getPackageFragment("workingcopy").getOrdinaryClassFile("X.class");
1396 	WorkingCopyOwner owner = new WorkingCopyOwner() {};
1397 	this.workingCopy = clazz.getWorkingCopy(owner, null/*no progress*/);
1398 	ICompilationUnit primary = this.workingCopy.getPrimary();
1399 	assertEquals("Unexpected owner of primary working copy", null, primary.getOwner());
1400 }
1401 
1402 /*
1403  * Ensures that a class file working copy can be restored from the original source.
1404  */
testWorkingCopy07()1405 public void testWorkingCopy07() throws CoreException {
1406 	IOrdinaryClassFile clazz = this.jarRoot.getPackageFragment("workingcopy").getOrdinaryClassFile("X.class");
1407 	WorkingCopyOwner owner = new WorkingCopyOwner() {};
1408 	this.workingCopy = clazz.getWorkingCopy(owner, null/*no progress*/);
1409 	this.workingCopy.getBuffer().setContents(
1410 		"package workingcopy;\n" +
1411 		"public class X {\n" +
1412 		"  void bar() {\n" +
1413 		"  }\n" +
1414 		"}"
1415 	);
1416 	this.workingCopy.reconcile(ICompilationUnit.NO_AST, false/*don't force problems*/, null/*primary owner*/, null/*no progress*/);
1417 	this.workingCopy.restore();
1418 	assertElementDescendants(
1419 		"Unexpected children",
1420 		"[Working copy] X.class\n" +
1421 		"  package workingcopy\n" +
1422 		"  class X\n" +
1423 		"    void foo()",
1424 		this.workingCopy);
1425 }
1426 
1427 /*
1428  * Ensures that a class file working copy can be reconciled against.
1429  */
testWorkingCopy08()1430 public void testWorkingCopy08() throws CoreException {
1431 	IOrdinaryClassFile clazz = this.jarRoot.getPackageFragment("workingcopy").getOrdinaryClassFile("X.class");
1432 	ProblemRequestor problemRequestor = new ProblemRequestor();
1433 	WorkingCopyOwner owner = newWorkingCopyOwner(problemRequestor);
1434 	this.workingCopy = clazz.getWorkingCopy(owner, null/*no progress*/);
1435 	this.workingCopy.getBuffer().setContents(
1436 		"package workingcopy;\n" +
1437 		"public class X {\n" +
1438 		"  public void bar() {\n" +
1439 		"  }\n" +
1440 		"}"
1441 	);
1442 	this.workingCopy.makeConsistent(null);
1443 
1444 	ICompilationUnit cu = getCompilationUnit("/P/Y.java");
1445 	ICompilationUnit copy = null;
1446 	try {
1447 		copy = cu.getWorkingCopy(owner, null/*no progress*/);
1448 		copy.getBuffer().setContents(
1449 			"public class Y {\n" +
1450 			"  void foo(workingcopy.X x) {\n" +
1451 			"    x.bar();\n" +
1452 			"  }\n" +
1453 			"}"
1454 		);
1455 		problemRequestor.problems = new StringBuffer();
1456 		problemRequestor.problemCount = 0;
1457 		copy.reconcile(ICompilationUnit.NO_AST, false/*don't force problems*/, owner, null/*no progress*/);
1458 		assertProblems(
1459 			"Unexpected problems",
1460 			"----------\n" +
1461 			"----------\n",
1462 			problemRequestor);
1463 	} finally {
1464 		if (copy != null)
1465 			copy.discardWorkingCopy();
1466 	}
1467 }
1468 
1469 /*
1470  * Ensures that types in a class file are hidden when reconciling against if the class file working copy is empty.
1471  */
testWorkingCopy09()1472 public void testWorkingCopy09() throws CoreException {
1473 	IOrdinaryClassFile clazz = this.jarRoot.getPackageFragment("workingcopy").getOrdinaryClassFile("X.class");
1474 	ProblemRequestor problemRequestor = new ProblemRequestor();
1475 	WorkingCopyOwner owner = newWorkingCopyOwner(problemRequestor);
1476 	this.workingCopy = clazz.getWorkingCopy(owner, null/*no progress*/);
1477 	this.workingCopy.getBuffer().setContents(	"");
1478 	this.workingCopy.makeConsistent(null);
1479 
1480 	ICompilationUnit cu = getCompilationUnit("/P/Y.java");
1481 	ICompilationUnit copy = null;
1482 	try {
1483 		copy = cu.getWorkingCopy(owner, /*problemRequestor, */null/*no prpgress*/);
1484 		copy.getBuffer().setContents(
1485 			"public class Y {\n" +
1486 			"  workingcopy.X x;\n" +
1487 			"}"
1488 		);
1489 		problemRequestor.problems = new StringBuffer();
1490 		problemRequestor.problemCount = 0;
1491 		copy.reconcile(ICompilationUnit.NO_AST, false/*don't force problems*/, owner, null/*no progress*/);
1492 		assertProblems(
1493 			"Unexpected problems",
1494 			"----------\n" +
1495 			"1. ERROR in /P/Y.java\n" +
1496 			"workingcopy.X cannot be resolved to a type\n" +
1497 			"----------\n",
1498 			problemRequestor);
1499 	} finally {
1500 		if (copy != null)
1501 			copy.discardWorkingCopy();
1502 	}
1503 }
1504 
1505 /*
1506  * Ensures that a 1.5 class file without source attached can be turned into a working copy and that its source is correct.
1507  */
testWorkingCopy10()1508 public void testWorkingCopy10() throws CoreException {
1509 	IPath sourceAttachmentPath = this.jarRoot.getSourceAttachmentPath();
1510 	try {
1511 		attachSource(this.jarRoot, null, null);
1512 		IOrdinaryClassFile clazz = this.jarRoot.getPackageFragment("workingcopy").getOrdinaryClassFile("Y.class");
1513 		assertNull("Should not have source attached", clazz.getSource());
1514 		this.workingCopy = clazz.getWorkingCopy(null/*primary owner*/, (IProgressMonitor) null/*no progress*/);
1515 		assertSourceEquals(
1516 			"Unexpected source",
1517 			"package workingcopy;\n" +
1518 			"public class Y<W> {\n" +
1519 			"  \n" +
1520 			"  public Y() {\n" +
1521 			"  }\n" +
1522 			"  \n" +
1523 			"  <T> T foo(T t, java.lang.String... args) {\n" +
1524 			"    return null;\n" +
1525 			"  }\n" +
1526 			"}",
1527 			this.workingCopy.getSource());
1528 	} finally {
1529 		attachSource(this.jarRoot, sourceAttachmentPath.toString(), null);
1530 	}
1531 }
1532 
1533 /*
1534  * Ensures that types in a class file are not found by a search if the class file working copy is empty.
1535  */
testWorkingCopy11()1536 public void testWorkingCopy11() throws CoreException {
1537 	IPackageFragment pkg = this.jarRoot.getPackageFragment("workingcopy");
1538 	IOrdinaryClassFile clazz = pkg.getOrdinaryClassFile("X.class");
1539 	this.workingCopy = clazz.getWorkingCopy(null/*primary owner*/, (IProgressMonitor) null/*no progress*/);
1540 	this.workingCopy.getBuffer().setContents(	"");
1541 	this.workingCopy.makeConsistent(null);
1542 
1543 	IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] {pkg});
1544 	AbstractJavaSearchTests.JavaSearchResultCollector requestor = new AbstractJavaSearchTests.JavaSearchResultCollector();
1545 	search("*", IJavaSearchConstants.TYPE, IJavaSearchConstants.DECLARATIONS, scope, requestor);
1546 	assertSearchResults(
1547 		"lib.jar workingcopy.Y",
1548 		requestor);
1549 }
1550 /*
1551  * https://bugs.eclipse.org/bugs/show_bug.cgi?id=150244
1552  */
testGetBytes()1553 public void testGetBytes() throws CoreException {
1554 	IPackageFragment pkg = this.jarRoot.getPackageFragment("workingcopy");
1555 	IOrdinaryClassFile clazz = pkg.getOrdinaryClassFile("X.class");
1556 	byte[] bytes = clazz.getBytes();
1557 	assertNotNull("No bytes", bytes);
1558 	int length = bytes.length;
1559 	assertTrue("wrong size", length > 5);
1560 	// sanity check: first four bytes are 0xCAFEBABE
1561 	assertEquals("Wrong value", 0xCA, bytes[0] & 0xFF);
1562 	assertEquals("Wrong value", 0xFE, bytes[1] & 0xFF);
1563 	assertEquals("Wrong value", 0xBA, bytes[2] & 0xFF);
1564 	assertEquals("Wrong value", 0xBE, bytes[3] & 0xFF);
1565 }
1566 /*
1567  * Ensures that the annotations of a binary field are correct
1568  */
testGenericFieldGetTypeSignature()1569 public void testGenericFieldGetTypeSignature() throws JavaModelException {
1570 	IType type = this.jarRoot.getPackageFragment("generic").getOrdinaryClassFile("GenericField.class").getType();
1571 	IField field = type.getField("myField");
1572 	assertEquals(
1573 		"Wrong type signature",
1574 		"Ljava.util.Collection<Ljava.lang.String;>;",
1575 		field.getTypeSignature());
1576 }
1577 
testBug246594()1578 	public void testBug246594() throws JavaModelException {
1579 		IType type = this.jarRoot.getPackageFragment("generic").getOrdinaryClassFile(
1580 				"Z.class").getType();
1581 		ITypeParameter typeParam = type.getTypeParameter("T");
1582 		assertNotNull(typeParam);
1583 		assertStringsEqual("Type parameter bounds signatures",
1584 				"Ljava.lang.Object;\n" +
1585 				"Lgeneric.I<-TT;>;\n",
1586 				typeParam.getBoundsSignatures());
1587 	}
1588 
testBug246594a()1589 	public void testBug246594a() throws JavaModelException {
1590 		IType type = this.jarRoot.getPackageFragment("generic").getOrdinaryClassFile(
1591 				"X.class").getType();
1592 		IMethod method = type.getMethod("foo", new String[] { "TK;", "TV;" });
1593 		ITypeParameter typeParam = method.getTypeParameter("V");
1594 		assertStringsEqual("Type parameter bounds signatures",
1595 							"TT;\n", typeParam.getBoundsSignatures());
1596 	}
1597 	//https://bugs.eclipse.org/bugs/show_bug.cgi?id=316937
testBug316937()1598 	public void testBug316937() throws Exception {
1599 		try {
1600 			IJavaProject project = getJavaProject("P");
1601 			String[] pathAndContents = new String[] {
1602 					"bug316937/Foo.java",
1603 					"package bug316937;\n" + "public class Foo {\n"
1604 							+ "	class Bar {\n"
1605 							+ "		public Bar(int a, int b) {}\n" + "	}\n"
1606 							+ "}\n" };
1607 			addLibrary(project, "lib316937.jar", "src316937.zip",
1608 					pathAndContents, JavaCore.VERSION_1_5);
1609 			IPackageFragmentRoot packageFragRoot = project
1610 					.getPackageFragmentRoot(getFile("/P/lib316937.jar"));
1611 
1612 			IType type = packageFragRoot.getPackageFragment("bug316937")
1613 					.getOrdinaryClassFile("Foo.class").getType();
1614 			IType subType = type.getType("Bar");
1615 			IMethod[] methods = subType.getMethods();
1616 			assertEquals("Constructros", 1, methods.length);
1617 			IMethod method = methods[0];
1618 			String[] paramNames = method.getParameterNames();
1619 			assertStringsEqual("Type parameter names", "a\n" + "b\n",
1620 					paramNames);
1621 
1622 			// Remove the source attachment
1623 			IClasspathEntry[] rawClasspath = project.getRawClasspath();
1624 			for (int index = 0; index < rawClasspath.length; index++) {
1625 				IClasspathEntry entry = rawClasspath[index];
1626 				if (entry.getPath().toString().endsWith("lib316937.jar")) {
1627 					((ClasspathEntry) entry).sourceAttachmentPath = null;
1628 				}
1629 			}
1630 			project.setRawClasspath(rawClasspath, null);
1631 
1632 			packageFragRoot = project
1633 					.getPackageFragmentRoot(getFile("/P/lib316937.jar"));
1634 			type = packageFragRoot.getPackageFragment("bug316937")
1635 					.getOrdinaryClassFile("Foo.class").getType();
1636 			subType = type.getType("Bar");
1637 			methods = subType.getMethods();
1638 			assertEquals("Constructros", 1, methods.length);
1639 			method = methods[0];
1640 			paramNames = method.getParameterNames();
1641 			assertStringsEqual("Type parameter names", "a\n" + "b\n",
1642 					paramNames);
1643 		} finally {
1644 			removeLibrary(getJavaProject("P"), "lib316937.jar", "src316937.zip");
1645 		}
1646 	}
1647 	/*
1648 	 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=372687
1649 	 * Ensures that if more than one thread try to open a class file at the same time, the children are correct.
1650 	 */
testBug372687()1651 	public void testBug372687() throws CoreException {
1652 		String expected = "X.class\n" +
1653 						  "  class X\n" +
1654 						  "    X()\n" +
1655 						  "    void foo()";
1656 		class GetClassThread extends Thread {
1657 			public String childString;
1658 			@Override
1659 			public void run(){
1660 				IOrdinaryClassFile clazz = ClassFileTests.this.jarRoot.getPackageFragment("workingcopy").getOrdinaryClassFile("X.class");
1661 				try {
1662 					this.childString = expandAll(clazz);
1663 				} catch (CoreException e) {
1664 					e.printStackTrace();
1665 				}
1666 			}
1667 		}
1668 		for (int i = 0; i < 10; i++) {
1669 			GetClassThread th1 = new GetClassThread();
1670 			GetClassThread th2 = new GetClassThread();
1671 			GetClassThread th3 = new GetClassThread();
1672 			th1.start();
1673 			th2.start();
1674 			th3.start();
1675 			try {
1676 				th1.join();
1677 				th2.join();
1678 				th3.join();
1679 			} catch (InterruptedException e) {
1680 				// ignore
1681 			}
1682 			assertEquals("Unexpected children", expected, th1.childString);
1683 			assertEquals("Unexpected children", expected, th2.childString);
1684 			assertEquals("Unexpected children", expected, th3.childString);
1685 			IOrdinaryClassFile clazz = ClassFileTests.this.jarRoot.getPackageFragment("workingcopy").getOrdinaryClassFile("X.class");
1686 			clazz.close();
1687 		}
1688 	}
1689 
1690 }
1691