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