From 92a1975ad19e5a0f7779a31c4ef6985c261283c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9rard=20Paligot?= Date: Wed, 11 May 2016 16:26:31 +0200 Subject: [PATCH] feat(annot): Reference to an annotation field as an invocation. (#660) --- .../declaration/CtAnnotationTypeImpl.java | 60 +++++++++++++++++++ .../support/visitor/SignaturePrinter.java | 4 +- .../spoon/test/annotation/AnnotationTest.java | 2 +- src/test/java/spoon/test/main/MainTest.java | 2 +- .../AnnotationFieldReferenceTest.java | 30 ++++++++++ .../test/reference/testclasses/Mole.java | 7 +++ .../test/reference/testclasses/Parameter.java | 5 ++ 7 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 src/test/java/spoon/test/reference/AnnotationFieldReferenceTest.java create mode 100644 src/test/java/spoon/test/reference/testclasses/Mole.java create mode 100644 src/test/java/spoon/test/reference/testclasses/Parameter.java diff --git a/src/main/java/spoon/support/reflect/declaration/CtAnnotationTypeImpl.java b/src/main/java/spoon/support/reflect/declaration/CtAnnotationTypeImpl.java index 2de43d9ee7e..74dd6f52df7 100644 --- a/src/main/java/spoon/support/reflect/declaration/CtAnnotationTypeImpl.java +++ b/src/main/java/spoon/support/reflect/declaration/CtAnnotationTypeImpl.java @@ -16,7 +16,10 @@ */ package spoon.support.reflect.declaration; +import spoon.reflect.code.CtComment; +import spoon.reflect.declaration.CtAnnotation; import spoon.reflect.declaration.CtAnnotationType; +import spoon.reflect.declaration.CtField; import spoon.reflect.declaration.CtFormalTypeDeclarer; import spoon.reflect.declaration.CtMethod; import spoon.reflect.declaration.CtType; @@ -30,6 +33,7 @@ import java.util.Collections; import java.util.List; import java.util.Set; +import java.util.TreeSet; /** * The implementation for {@link spoon.reflect.declaration.CtAnnotationType}. @@ -44,6 +48,62 @@ public void accept(CtVisitor v) { v.visitCtAnnotationType(this); } + private CtMethod createGhostMethod(CtField field) { + final CtMethod method = factory.Core().createMethod(); + method.setImplicit(true); + method.setSimpleName(field.getSimpleName()); + method.setModifiers(field.getModifiers()); + method.setType(factory.Core().clone(field.getType())); + for (CtAnnotation ctAnnotation : field.getAnnotations()) { + method.addAnnotation(factory.Core().clone(ctAnnotation)); + } + for (CtComment ctComment : field.getComments()) { + method.addComment(factory.Core().clone(ctComment)); + } + method.setDocComment(field.getDocComment()); + method.setPosition(field.getPosition()); + method.setShadow(field.isShadow()); + return method; + } + + private void addGhostMethod(CtField field) { + super.addMethod(createGhostMethod(field)); + } + + @Override + public > C addField(CtField field) { + addGhostMethod(field); + return super.addField(field); + } + + @Override + public > C addField(int index, CtField field) { + addGhostMethod(field); + return super.addField(index, field); + } + + @Override + public > C addFieldAtTop(CtField field) { + addGhostMethod(field); + return super.addFieldAtTop(field); + } + + @Override + public > C setFields(List> fields) { + Set> methods = new TreeSet>(); + for (CtField field : fields) { + methods.add(createGhostMethod(field)); + } + super.setMethods(methods); + return super.setFields(fields); + } + + @Override + public boolean removeField(CtField field) { + super.removeMethod(createGhostMethod(field)); + return super.removeField(field); + } + @Override public Set> getSuperInterfaces() { return Collections.emptySet(); diff --git a/src/main/java/spoon/support/visitor/SignaturePrinter.java b/src/main/java/spoon/support/visitor/SignaturePrinter.java index 00e392f48f9..22bee9a5097 100644 --- a/src/main/java/spoon/support/visitor/SignaturePrinter.java +++ b/src/main/java/spoon/support/visitor/SignaturePrinter.java @@ -126,7 +126,9 @@ public void visitCtMethod(CtMethod m) { } write("> "); } - write(m.getType().getQualifiedName()); + if (m.getType() != null) { + write(m.getType().getQualifiedName()); + } write(" "); write(m.getSimpleName()); write("("); diff --git a/src/test/java/spoon/test/annotation/AnnotationTest.java b/src/test/java/spoon/test/annotation/AnnotationTest.java index d888bdfe9ae..2fd54993677 100644 --- a/src/test/java/spoon/test/annotation/AnnotationTest.java +++ b/src/test/java/spoon/test/annotation/AnnotationTest.java @@ -318,7 +318,7 @@ public void testAnnotatedElementTypes() throws Exception { CtAnnotationType annotationType = pkg.getType("Bound"); assertEquals(Bound.class, annotationType.getActualClass()); assertNull(annotationType.getSuperclass()); - assertEquals(0,annotationType.getAllMethods().size()); + assertEquals(annotationType.getFields().size(),annotationType.getAllMethods().size()); assertEquals(0,annotationType.getSuperInterfaces().size()); annotations = annotationType.getAnnotations(); diff --git a/src/test/java/spoon/test/main/MainTest.java b/src/test/java/spoon/test/main/MainTest.java index be6306dfe85..69c5ac53c2d 100644 --- a/src/test/java/spoon/test/main/MainTest.java +++ b/src/test/java/spoon/test/main/MainTest.java @@ -112,7 +112,7 @@ public void visitCtTypeReference(CtTypeReference reference) { @Override public void visitCtExecutableReference(CtExecutableReference reference) { assertNotNull(reference); - if (isLanguageExecutable(reference) || isDeclaredInAnAnnotation(reference)) { + if (isLanguageExecutable(reference)) { super.visitCtExecutableReference(reference); return; } diff --git a/src/test/java/spoon/test/reference/AnnotationFieldReferenceTest.java b/src/test/java/spoon/test/reference/AnnotationFieldReferenceTest.java new file mode 100644 index 00000000000..bbe279fc22e --- /dev/null +++ b/src/test/java/spoon/test/reference/AnnotationFieldReferenceTest.java @@ -0,0 +1,30 @@ +package spoon.test.reference; + +import org.junit.Test; +import spoon.reflect.code.CtInvocation; +import spoon.reflect.declaration.CtExecutable; +import spoon.reflect.declaration.CtField; +import spoon.reflect.declaration.CtMethod; +import spoon.reflect.factory.Factory; +import spoon.reflect.visitor.filter.TypeFilter; +import spoon.test.reference.testclasses.Mole; +import spoon.test.reference.testclasses.Parameter; +import spoon.testing.utils.ModelUtils; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class AnnotationFieldReferenceTest { + @Test + public void testAnnotationFieldReference() throws Exception { + final Factory factory = ModelUtils.build(Parameter.class, Mole.class); + final CtMethod make = factory.Class().get(Mole.class).getMethod("make", factory.Type().createReference(Parameter.class)); + final CtInvocation annotationInv = make.getElements(new TypeFilter>(CtInvocation.class)).get(0); + final CtExecutable executableDeclaration = annotationInv.getExecutable().getExecutableDeclaration(); + assertNotNull(executableDeclaration); + final CtField value = factory.Annotation().get(Parameter.class).getField("value"); + assertNotNull(value); + assertEquals(value.getSimpleName(), executableDeclaration.getSimpleName()); + assertEquals(value.getType(), executableDeclaration.getType()); + } +} diff --git a/src/test/java/spoon/test/reference/testclasses/Mole.java b/src/test/java/spoon/test/reference/testclasses/Mole.java new file mode 100644 index 00000000000..10519b1926c --- /dev/null +++ b/src/test/java/spoon/test/reference/testclasses/Mole.java @@ -0,0 +1,7 @@ +package spoon.test.reference.testclasses; + +public class Mole { + private void make(Parameter p) { + p.value(); + } +} diff --git a/src/test/java/spoon/test/reference/testclasses/Parameter.java b/src/test/java/spoon/test/reference/testclasses/Parameter.java new file mode 100644 index 00000000000..7435fb06526 --- /dev/null +++ b/src/test/java/spoon/test/reference/testclasses/Parameter.java @@ -0,0 +1,5 @@ +package spoon.test.reference.testclasses; + +public @interface Parameter { + String value(); +} \ No newline at end of file