1 /*******************************************************************************
2  * Copyright (c) 2005, 2012 BEA Systems, Inc. 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  *    sbandow@bea.com - initial API and implementation
13  *    IBM Corporation - Added test for https://bugs.eclipse.org/bugs/show_bug.cgi?id=352949
14  *******************************************************************************/
15 
16 package org.eclipse.jdt.apt.tests;
17 
18 import java.util.Collection;
19 import java.util.Map;
20 
21 import junit.framework.Test;
22 import junit.framework.TestSuite;
23 
24 import org.eclipse.core.resources.IProject;
25 import org.eclipse.core.runtime.IPath;
26 import org.eclipse.jdt.apt.core.env.EnvironmentFactory;
27 import org.eclipse.jdt.apt.tests.annotations.ProcessorTestStatus;
28 import org.eclipse.jdt.apt.tests.annotations.generic.AbstractGenericProcessor;
29 import org.eclipse.jdt.apt.tests.annotations.generic.GenericFactory;
30 import org.eclipse.jdt.apt.tests.annotations.mirrortest.MirrorDeclarationCodeExample;
31 import org.eclipse.jdt.apt.tests.annotations.mirrortest.SourceMirrorCodeExample;
32 import org.eclipse.jdt.core.ICompilationUnit;
33 import org.eclipse.jdt.core.IJavaProject;
34 import org.eclipse.jdt.core.JavaCore;
35 import org.eclipse.jdt.core.JavaModelException;
36 
37 import com.sun.mirror.apt.AnnotationProcessorEnvironment;
38 import com.sun.mirror.declaration.AnnotationMirror;
39 import com.sun.mirror.declaration.AnnotationTypeDeclaration;
40 import com.sun.mirror.declaration.AnnotationTypeElementDeclaration;
41 import com.sun.mirror.declaration.AnnotationValue;
42 import com.sun.mirror.declaration.Declaration;
43 import com.sun.mirror.declaration.TypeDeclaration;
44 import com.sun.mirror.util.SourcePosition;
45 
46 public class MirrorDeclarationTests extends APTTestBase {
47 
MirrorDeclarationTests(final String name)48 	public MirrorDeclarationTests(final String name)
49 	{
50 		super(name);
51 	}
52 
suite()53 	public static Test suite()
54 	{
55 		return new TestSuite(MirrorDeclarationTests.class);
56 	}
57 
58 	@Override
setUp()59 	public void setUp() throws Exception
60 	{
61 		super.setUp();
62 
63 		IProject project = env.getProject( getProjectName() );
64 		IPath srcRoot = getSourcePath();
65 		String code = MirrorDeclarationCodeExample.CODE;
66 		env.addClass(srcRoot, MirrorDeclarationCodeExample.CODE_PACKAGE, MirrorDeclarationCodeExample.CODE_CLASS_NAME, code);
67 		fullBuild( project.getFullPath() );
68 		expectingNoProblems();
69 	}
70 
testMirrorDeclaration()71 	public void testMirrorDeclaration() throws Exception
72 	{
73 		assertEquals(ProcessorTestStatus.NO_ERRORS, ProcessorTestStatus.getErrors());
74 	}
75 
testFieldConstant()76 	public void testFieldConstant() throws Exception
77 	{
78 		IProject project = env.getProject( getProjectName() );
79 		IPath srcRoot = getSourcePath();
80 		String codeTrigger =
81 			"package test;\n" +
82 			"public @interface Trigger{}";
83 
84 		env.addClass(srcRoot, "test", "Trigger", codeTrigger);
85 
86 		String codeEntryPoint = "package test;\n" +
87 								"@Trigger\n" +
88 								"public class EntryPoint {\n" +
89 								"    ClassWithNestedAnnotation nestedAnno;\n}";
90 
91 		env.addClass(srcRoot, "test", "EntryPoint", codeEntryPoint);
92 
93 		String codeClassWithNestedAnnotation =
94 			"package test; \n" +
95 			"public class ClassWithNestedAnnotation {\n" +
96 			"	public final int FOUR = 4; \n " +
97 			"}";
98 
99 		env.addClass(srcRoot, "test", "ClassWithNestedAnnotation", codeClassWithNestedAnnotation);
100 		fullBuild( project.getFullPath() );
101 		expectingNoProblems();
102 	}
103 
104 	// TODO: Disabled due to Bugzilla 124388 -theodora
105 	// https://bugs.eclipse.org/bugs/show_bug.cgi?id=124388
DISABLED_testDefault()106 	public void DISABLED_testDefault() throws Exception
107 	{
108 		IProject project = env.getProject( getProjectName() );
109 		IPath srcRoot = getSourcePath();
110 		String codeTrigger =
111 			"package test;\n" +
112 			"public @interface Trigger{}";
113 
114 		env.addClass(srcRoot, "test", "Trigger", codeTrigger);
115 
116 		String codeEntryPoint = "package test;\n" +
117 								"@Trigger\n" +
118 								"public class EntryPoint {\n" +
119 								"    ClassWithNestedAnnotation nestedAnno;\n}";
120 
121 		env.addClass(srcRoot, "test", "EntryPoint", codeEntryPoint);
122 
123 		String codeClassWithNestedAnnotation =
124 			"package test; \n" +
125 			"public class ClassWithNestedAnnotation {\n" +
126 			"	public @interface NestedAnnotation{\n" +
127 			"		public enum Character{ \n" +
128 			"			Winnie, Tiger, Piglet, Eore; \n" +
129 			"		}\n"+
130 			"		Character value() default Character.Eore; \n" +
131 			"	}\n" +
132 			"}";
133 
134 		env.addClass(srcRoot, "test", "ClassWithNestedAnnotation", codeClassWithNestedAnnotation);
135 		fullBuild( project.getFullPath() );
136 		expectingNoProblems();
137 	}
138 
139 	/**
140 	 * Test AST based mirror implementation and binding based mirror implementation.
141 	 * Specifically,
142 	 *   (i) method declaration with unresolvable return type.
143 	 *  (ii) constructor declaration with unresolvable parameter
144 	 * (iii) field declaration with unresolvable type.
145 	 *
146 	 * This test focus on declarations from file in context.
147 	 *
148 	 * @throws Exception
149 	 */
testUnresolvableDeclarations0()150 	public void testUnresolvableDeclarations0()
151 		throws Exception
152 	{
153 		IProject project = env.getProject( getProjectName() );
154 		IPath srcRoot = getSourcePath();
155 		String declAnno =
156 			"package test;\n" +
157 			"public @interface DeclarationAnno{}";
158 
159 		env.addClass(srcRoot, "test", "DeclarationAnno", declAnno);
160 
161 		String codeFoo =
162 			"package test;\n" +
163 			"@DeclarationAnno\n" +
164 			"public class Foo {\n" +
165 			"    int field0;\n " +
166 			"    UnknownType field1;\n " +
167 			"    public Foo(UnknownType type){} \n" +
168 			"    public void voidMethod(){} \n " +
169 			"    public UnknownType getType(){}\n " +
170 			"    public class Inner{} \n" +
171 			"}";
172 
173 		final IPath fooPath = env.addClass(srcRoot, "test", "Foo", codeFoo);
174 		fullBuild( project.getFullPath() );
175 
176 		expectingOnlySpecificProblemsFor(fooPath, new ExpectedProblem[]{
177 				new ExpectedProblem("", "UnknownType cannot be resolved to a type", fooPath),
178 				new ExpectedProblem("", "UnknownType cannot be resolved to a type", fooPath),
179 				new ExpectedProblem("", "UnknownType cannot be resolved to a type", fooPath)}
180 		);
181 	}
182 
183 	/**
184 	 * Test AST based mirror implementation and binding based mirror implementation.
185 	 * Specifically,
186 	 *   (i) method declaration with unresolvable return type.
187 	 *  (ii) constructor declaration with unresolvable parameter
188 	 * (iii) field declaration with unresolvable type.
189 	 *
190 	 * This test focus on declarations from file outside of processor
191 	 * environment context.
192 	 *
193 	 * @throws Exception
194 	 */
testUnresolvableDeclarations1()195 	public void testUnresolvableDeclarations1()
196 		throws Exception
197 	{
198 		IProject project = env.getProject( getProjectName() );
199 		IPath srcRoot = getSourcePath();
200 		String declAnno =
201 			"package test;\n" +
202 			"public @interface DeclarationAnno{}";
203 
204 		env.addClass(srcRoot, "test", "DeclarationAnno", declAnno);
205 
206 		String codeBar =
207 			"package test;\n" +
208 			"@DeclarationAnno\n" +
209 			"public class Bar {}";
210 		env.addClass(srcRoot, "test", "Bar", codeBar);
211 
212 		String codeFoo =
213 			"package test;\n" +
214 			"@DeclarationAnno\n" +
215 			"public class Foo {\n" +
216 			"    int field0;\n " +
217 			"    UnknownType field1;\n " +
218 			"    public Foo(UnknownType type){} \n" +
219 			"    public void voidMethod(){} \n " +
220 			"    public UnknownType getType(){}\n " +
221 			"    public class Inner{} \n" +
222 			"}";
223 
224 		final IPath fooPath = env.addClass(srcRoot, "test", "Foo", codeFoo);
225 
226 		fullBuild( project.getFullPath() );
227 		expectingOnlySpecificProblemsFor(fooPath, new ExpectedProblem[]{
228 				new ExpectedProblem("", "UnknownType cannot be resolved to a type", fooPath),
229 				new ExpectedProblem("", "UnknownType cannot be resolved to a type", fooPath),
230 				new ExpectedProblem("", "UnknownType cannot be resolved to a type", fooPath)}
231 		);
232 	}
233 
testLocation()234 	public void testLocation() {
235 
236 		TestLocationProc p = new TestLocationProc();
237 		GenericFactory.setProcessor(p);
238 
239 		IProject project = env.getProject( getProjectName() );
240 		IPath srcRoot = getSourcePath();
241 		String x =
242 			"package test;\n" +
243 			"import org.eclipse.jdt.apt.tests.annotations.generic.*;\n" +
244 			"@GenericAnnotation public class X {}";
245 
246 		env.addClass(srcRoot, "test", "X", x);
247 
248 		fullBuild( project.getFullPath() );
249 		expectingNoProblems();
250 
251 		assertTrue("Processor not invoked", p.called);
252 	}
253 
testSourceMirror()254 	public void testSourceMirror() {
255 
256 		TestSourceMirrorProc p = new TestSourceMirrorProc();
257 		GenericFactory.setProcessor(p);
258 
259 		IProject project = env.getProject( getProjectName() );
260 		IPath srcRoot = getSourcePath();
261 		env.addClass(srcRoot, SourceMirrorCodeExample.CODE_PACKAGE, SourceMirrorCodeExample.ANNO_CODE_CLASS_NAME, SourceMirrorCodeExample.ANNO_CODE);
262 		env.addClass(srcRoot, SourceMirrorCodeExample.CODE_PACKAGE, SourceMirrorCodeExample.CODE_CLASS_NAME, SourceMirrorCodeExample.CODE);
263 
264 		fullBuild( project.getFullPath() );
265 		expectingNoProblems();
266 
267 		assertTrue("Processor not invoked", p.called);
268 	}
269 
testPackageInfo()270 	public void testPackageInfo() {
271 		PackageInfoProc p = new PackageInfoProc();
272 		GenericFactory.setProcessor(p);
273 
274 		IProject project = env.getProject( getProjectName() );
275 		IPath srcRoot = getSourcePath();
276 		IPath pkg = env.addPackage(srcRoot, "pkg");
277 		String contents = "@PkgAnnotation\n" +
278 						  "@GenericAnnotation\n" +
279 						  "package pkg;\n" +
280 						  "import org.eclipse.jdt.apt.tests.annotations.generic.*;";
281 		env.addFile(pkg, "package-info.java", contents);
282 		String annContents =
283 				"package pkg;\n" +
284 				"\n" +
285 				"@interface PkgAnnotation {\n" +
286 				"    String value() default \"def\";\n" +
287 				"}\n";
288 		env.addClass(srcRoot, "pkg", "pkgAnnotation", annContents);
289 		fullBuild( project.getFullPath() );
290 		expectingNoProblems();
291 
292 		assertTrue("Processor not invoked", p.called);
293 	}
294 
295 	static class TestLocationProc extends AbstractGenericProcessor {
296 
297 		boolean called;
298 
299 		@Override
_process()300 		public void _process() {
301 			called = true;
302 			assertTrue(decls.size() == 1);
303 
304 			Declaration d = decls.iterator().next();
305 			SourcePosition p = d.getPosition();
306 
307 			assertTrue(p.column() == 32);
308 			assertTrue(p.line() == 3);
309 		}
310 	}
311 
312 	static class TestSourceMirrorProc extends AbstractGenericProcessor {
313 
314 		boolean called;
315 
316 		@Override
_process()317 		public void _process() {
318 			called = true;
319 			TypeDeclaration tdCode = env.getTypeDeclaration(SourceMirrorCodeExample.CODE_PACKAGE + "." + SourceMirrorCodeExample.CODE_CLASS_NAME);
320 			for (AnnotationMirror am : tdCode.getAnnotationMirrors()) {
321 				if ("GenericAnnotation".equals(am.getAnnotationType().getDeclaration().getSimpleName())) {
322 					continue;
323 				}
324 				assertTrue(null != am.getPosition());
325 				AnnotationTypeDeclaration atd = am.getAnnotationType().getDeclaration();
326 				assertTrue(null != atd.getPosition());
327 				for (Map.Entry<AnnotationTypeElementDeclaration, AnnotationValue> entry : am.getElementValues().entrySet()) {
328 					assertNotNull(entry.getKey().getPosition());
329 					assertNotNull(entry.getKey().getDefaultValue().getPosition());
330 				}
331 			}
332 		}
333 	}
334 
335 	static class PackageInfoProc extends AbstractGenericProcessor {
336 
337 		boolean called;
338 
339 		@Override
_process()340 		public void _process() {
341 			called = true;
342 			AnnotationTypeDeclaration annoDecl = (AnnotationTypeDeclaration)env.getTypeDeclaration("pkg.PkgAnnotation");
343 			assertTrue(null != annoDecl);
344 			// get the annotated declarations
345 			Collection<Declaration> annotatedDecls = env.getDeclarationsAnnotatedWith(annoDecl);
346 			// don't return the package declaration - well, apt is doing that..
347 			assertTrue(annotatedDecls == null  || annotatedDecls.size() == 0);
348 
349 			//TODO: test to support package annotation
350 			// PackageDeclaration pdCode = env.getPackage("pkg");
351 			// for (AnnotationMirror am : pdCode.getAnnotationMirrors()) {
352 			//	if ("GenericAnnotation".equals(am.getAnnotationType().getDeclaration().getSimpleName())) {
353 			//		continue;
354 			//	}
355 			//	assertTrue(null != am.getPosition());
356 			//	AnnotationTypeDeclaration atd = am.getAnnotationType().getDeclaration();
357 			//	assertTrue(null != atd.getPosition());
358 			//	for (Map.Entry<AnnotationTypeElementDeclaration, AnnotationValue> entry : am.getElementValues().entrySet()) {
359 			//		assertNotNull(entry.getKey().getPosition());
360 			//		assertNotNull(entry.getKey().getDefaultValue().getPosition());
361 			//	}
362 			// }
363 		}
364 	}
365 
testEnvFactory()366 	public void testEnvFactory() throws JavaModelException {
367 
368 		IProject project = env.getProject(getProjectName());
369 		IPath srcRoot = getSourcePath();
370 		String x = "package test;\n" + "import org.eclipse.jdt.apt.tests.annotations.generic.*;\n"
371 				+ "@GenericAnnotation public class X {}";
372 
373 		IPath path = env.addClass(srcRoot, "test", "X", x);
374 		IPath tail = path.removeFirstSegments(2);
375 		IJavaProject p = JavaCore.create(project);
376 		ICompilationUnit cu = (ICompilationUnit) p.findElement(tail);
377 		assertTrue("Could not find cu", cu != null);
378 
379 		AnnotationProcessorEnvironment env = EnvironmentFactory.getEnvironment(cu, p);
380 		TypeDeclaration t = env.getTypeDeclaration("test.X");
381 
382 		SourcePosition pos = t.getPosition();
383 
384 		assertTrue(pos.column() == 32);
385 		assertTrue(pos.line() == 3);
386 
387 		// Bad type should gracefully return null
388 		TypeDeclaration tBad = env.getTypeDeclaration("test.XYZ");
389 		assertTrue(null == tBad);
390 	}
391 
392 }
393