From bfd99961c4ba8f9750f4e17861b529dd9b354402 Mon Sep 17 00:00:00 2001 From: Eric Milles Date: Thu, 27 Dec 2018 13:59:47 -0600 Subject: [PATCH] Fix for #782: add support for @PackageScope on annotation type https://issues.apache.org/jira/browse/GROOVY-8940 --- .../core/tests/xform/PackageScopeTests.java | 12 ++ base/org.codehaus.groovy24/.checkstyle | 1 + .../codehaus/groovy/ast/AnnotationNode.java | 190 ++++++++++++++++++ .../groovy/classgen/ExtendedVerifier.java | 2 +- .../groovy/classgen/ExtendedVerifier.java | 6 +- .../groovy/classgen/ExtendedVerifier.java | 6 +- .../groovy/eclipse/wizards/NewTypeWizard.java | 2 +- 7 files changed, 211 insertions(+), 8 deletions(-) create mode 100644 base/org.codehaus.groovy24/src/org/codehaus/groovy/ast/AnnotationNode.java diff --git a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/PackageScopeTests.java b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/PackageScopeTests.java index 30b516337a..7c606dcf8b 100644 --- a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/PackageScopeTests.java +++ b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/PackageScopeTests.java @@ -270,4 +270,16 @@ public void testPackageScope8() { method = findMethod(getCUDeclFor("Foo.groovy"), "method4"); assertTrue("Expected protected but was: " + Modifier.toString(method.modifiers), Modifier.isProtected(method.modifiers)); } + + @Test // https://issues.apache.org/jira/browse/GROOVY-8940 + public void testPackageScope9() { + String[] sources = { + "Tag.groovy", + "@groovy.transform.PackageScope\n" + + "@interface Tag {\n" + + "}\n", + }; + + runNegativeTest(sources, ""); + } } diff --git a/base/org.codehaus.groovy24/.checkstyle b/base/org.codehaus.groovy24/.checkstyle index fa7b9f67d2..4ba524fc8f 100644 --- a/base/org.codehaus.groovy24/.checkstyle +++ b/base/org.codehaus.groovy24/.checkstyle @@ -16,6 +16,7 @@ + diff --git a/base/org.codehaus.groovy24/src/org/codehaus/groovy/ast/AnnotationNode.java b/base/org.codehaus.groovy24/src/org/codehaus/groovy/ast/AnnotationNode.java new file mode 100644 index 0000000000..52ba8377f6 --- /dev/null +++ b/base/org.codehaus.groovy24/src/org/codehaus/groovy/ast/AnnotationNode.java @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.ast; + +import org.codehaus.groovy.GroovyBugError; +import org.codehaus.groovy.ast.expr.Expression; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Represents an annotation which can be attached to interfaces, classes, methods and fields. + * + * @author James Strachan + * @author Alex Popescu + */ +public class AnnotationNode extends ASTNode { + /* GRECLIPSE edit + public static final int TYPE_TARGET = 1; + */ + public static final int CONSTRUCTOR_TARGET = 1 << 1; + public static final int METHOD_TARGET = 1 << 2; + public static final int FIELD_TARGET = 1 << 3; + public static final int PARAMETER_TARGET = 1 << 4; + public static final int LOCAL_VARIABLE_TARGET = 1 << 5; + public static final int ANNOTATION_TARGET = 1 << 6; + public static final int PACKAGE_TARGET = 1 << 7; + // GRECLIPSE add -- GROOVY-7151 and GROOVY-8940 + public static final int TYPE_TARGET = 1 | ANNOTATION_TARGET; + // GRECLIPSE end + private static final int ALL_TARGETS = TYPE_TARGET | CONSTRUCTOR_TARGET | METHOD_TARGET + | FIELD_TARGET | PARAMETER_TARGET | LOCAL_VARIABLE_TARGET | PACKAGE_TARGET; + + private final ClassNode classNode; + private Map members; + private boolean runtimeRetention= false, sourceRetention= false, classRetention = false; + private int allowedTargets = ALL_TARGETS; + + public AnnotationNode(ClassNode classNode) { + this.classNode = classNode; + } + + public ClassNode getClassNode() { + return classNode; + } + + public Map getMembers() { + if (members == null) { + return Collections.emptyMap(); + } + return members; + } + + public Expression getMember(String name) { + if (members == null) { + return null; + } + return members.get(name); + } + + private void assertMembers() { + if (members == null) { + members = new LinkedHashMap(); + } + } + + public void addMember(String name, Expression value) { + assertMembers(); + Expression oldValue = members.get(name); + if (oldValue == null) { + members.put(name, value); + } + else { + throw new GroovyBugError(String.format("Annotation member %s has already been added", name)); + } + } + + public void setMember(String name, Expression value) { + assertMembers(); + members.put(name, value); + } + + public boolean isBuiltIn(){ + return false; + } + + /** + * Flag corresponding to RetentionPolicy. + * @return true if the annotation should be visible at runtime, + * false otherwise + */ + public boolean hasRuntimeRetention() { + return this.runtimeRetention; + } + + /** + * Sets the internal flag of this annotation runtime retention policy. + * If the current annotation has + * RetentionPolicy.RUNTIME or if false + * if the RetentionPolicy.CLASS. + * @param flag if true then current annotation is marked as having + * RetentionPolicy.RUNTIME. If false then + * the annotation has RetentionPolicy.CLASS. + */ + public void setRuntimeRetention(boolean flag) { + this.runtimeRetention = flag; + } + + /** + * Flag corresponding to RetentionPolicy.SOURCE. + * @return true if the annotation is only allowed in sources + * false otherwise + */ + public boolean hasSourceRetention() { + if (!runtimeRetention && !classRetention) return true; + return this.sourceRetention; + } + + /** Sets the internal flag if the current annotation has + * RetentionPolicy.SOURCE. + */ + public void setSourceRetention(boolean flag) { + this.sourceRetention = flag; + } + + /** + * Flag corresponding to RetentionPolicy.CLASS. + * @return true if the annotation is recorded by the compiler, + * but not visible at runtime + * false otherwise + */ + public boolean hasClassRetention() { + return this.classRetention; + } + + /** Sets the internal flag if the current annotation has + * RetentionPolicy.CLASS. + */ + public void setClassRetention(boolean flag) { + this.classRetention = flag; + } + + public void setAllowedTargets(int bitmap) { + this.allowedTargets = bitmap; + } + + public boolean isTargetAllowed(int target) { + return (this.allowedTargets & target) == target; + } + + public static String targetToName(int target) { + switch(target) { + case TYPE_TARGET: + return "TYPE"; + case CONSTRUCTOR_TARGET: + return "CONSTRUCTOR"; + case METHOD_TARGET: + return "METHOD"; + case FIELD_TARGET: + return "FIELD"; + case PARAMETER_TARGET: + return "PARAMETER"; + case LOCAL_VARIABLE_TARGET: + return "LOCAL_VARIABLE"; + case ANNOTATION_TARGET: + return "ANNOTATION"; + case PACKAGE_TARGET: + return "PACKAGE"; + default: + return "unknown target"; + } + } +} diff --git a/base/org.codehaus.groovy24/src/org/codehaus/groovy/classgen/ExtendedVerifier.java b/base/org.codehaus.groovy24/src/org/codehaus/groovy/classgen/ExtendedVerifier.java index 57918362c0..25feb92fd5 100644 --- a/base/org.codehaus.groovy24/src/org/codehaus/groovy/classgen/ExtendedVerifier.java +++ b/base/org.codehaus.groovy24/src/org/codehaus/groovy/classgen/ExtendedVerifier.java @@ -321,7 +321,7 @@ protected boolean isAnnotationCompatible() { } protected void addError(String msg, ASTNode expr) { - // GRECLIPSE: start: use new form of error message that has an end column + // GRECLIPSE add -- use new form of error message that has an end column if (expr instanceof AnnotationNode) { AnnotationNode aNode = (AnnotationNode) expr; this.source.getErrorCollector().addErrorAndContinue( diff --git a/base/org.codehaus.groovy25/src/org/codehaus/groovy/classgen/ExtendedVerifier.java b/base/org.codehaus.groovy25/src/org/codehaus/groovy/classgen/ExtendedVerifier.java index 25b9ef9ae9..97f84477cb 100644 --- a/base/org.codehaus.groovy25/src/org/codehaus/groovy/classgen/ExtendedVerifier.java +++ b/base/org.codehaus.groovy25/src/org/codehaus/groovy/classgen/ExtendedVerifier.java @@ -282,7 +282,7 @@ private static boolean isOverrideMethod(MethodNode method) { } ClassNode superClass = next.getUnresolvedSuperClass(); if (superClass != null) { - next = correctToGenericsSpecRecurse(updatedGenericsSpec, superClass); + next = correctToGenericsSpecRecurse(updatedGenericsSpec, superClass); } else { next = null; } @@ -291,7 +291,7 @@ private static boolean isOverrideMethod(MethodNode method) { } private static MethodNode getDeclaredMethodCorrected(Map genericsSpec, MethodNode mn, ClassNode correctedNext) { - for (MethodNode orig : correctedNext.getDeclaredMethods(mn.getName())) { + for (MethodNode orig : correctedNext.getDeclaredMethods(mn.getName())) { MethodNode method = correctToGenericsSpec(genericsSpec, orig); if (ParameterUtils.parametersEqual(method.getParameters(), mn.getParameters())) { return method; @@ -324,7 +324,7 @@ protected boolean isAnnotationCompatible() { } public void addError(String msg, ASTNode expr) { - // GRECLIPSE: start: use new form of error message that has an end column + // GRECLIPSE add -- use new form of error message that has an end column if (expr instanceof AnnotationNode) { AnnotationNode aNode = (AnnotationNode) expr; this.source.getErrorCollector().addErrorAndContinue( diff --git a/base/org.codehaus.groovy26/src/org/codehaus/groovy/classgen/ExtendedVerifier.java b/base/org.codehaus.groovy26/src/org/codehaus/groovy/classgen/ExtendedVerifier.java index 25b9ef9ae9..97f84477cb 100644 --- a/base/org.codehaus.groovy26/src/org/codehaus/groovy/classgen/ExtendedVerifier.java +++ b/base/org.codehaus.groovy26/src/org/codehaus/groovy/classgen/ExtendedVerifier.java @@ -282,7 +282,7 @@ private static boolean isOverrideMethod(MethodNode method) { } ClassNode superClass = next.getUnresolvedSuperClass(); if (superClass != null) { - next = correctToGenericsSpecRecurse(updatedGenericsSpec, superClass); + next = correctToGenericsSpecRecurse(updatedGenericsSpec, superClass); } else { next = null; } @@ -291,7 +291,7 @@ private static boolean isOverrideMethod(MethodNode method) { } private static MethodNode getDeclaredMethodCorrected(Map genericsSpec, MethodNode mn, ClassNode correctedNext) { - for (MethodNode orig : correctedNext.getDeclaredMethods(mn.getName())) { + for (MethodNode orig : correctedNext.getDeclaredMethods(mn.getName())) { MethodNode method = correctToGenericsSpec(genericsSpec, orig); if (ParameterUtils.parametersEqual(method.getParameters(), mn.getParameters())) { return method; @@ -324,7 +324,7 @@ protected boolean isAnnotationCompatible() { } public void addError(String msg, ASTNode expr) { - // GRECLIPSE: start: use new form of error message that has an end column + // GRECLIPSE add -- use new form of error message that has an end column if (expr instanceof AnnotationNode) { AnnotationNode aNode = (AnnotationNode) expr; this.source.getErrorCollector().addErrorAndContinue( diff --git a/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/wizards/NewTypeWizard.java b/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/wizards/NewTypeWizard.java index cbb59cc733..e58c012425 100644 --- a/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/wizards/NewTypeWizard.java +++ b/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/wizards/NewTypeWizard.java @@ -582,7 +582,7 @@ private void createAnnotationControls(Composite parent) { Map modifiers = new LinkedHashMap<>(); modifiers.put(NewWizardMessages.NewTypeWizardPage_modifiers_public, Flags.AccPublic); - //modifiers.put(NewWizardMessages.NewTypeWizardPage_modifiers_default, Flags.AccDefault); + modifiers.put(NewWizardMessages.NewTypeWizardPage_modifiers_default, Flags.AccDefault); modifiers.put(NewWizardMessages.NewTypeWizardPage_modifiers_private, Flags.AccPrivate); modifiers.put(NewWizardMessages.NewTypeWizardPage_modifiers_protected, Flags.AccProtected);