diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index 8bb985ddf27..7189dc5fe33 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -36,9 +36,7 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.function.BiFunction; import java.util.function.IntFunction; -import java.util.function.Predicate; import javax.lang.model.element.Modifier; import javax.lang.model.element.NestingKind; @@ -2257,316 +2255,12 @@ public void run() { currentClassFile = classFile; List newList = deproxyTypeCompoundList(proxies); sym.setTypeAttributes(newList.prependList(sym.getRawTypeAttributes())); - addTypeAnnotationsToSymbol(sym, newList); } finally { currentClassFile = previousClassFile; } } } - /** - * Rewrites types in the given symbol to include type annotations. - * - *

The list of type annotations includes annotations for all types in the signature of the - * symbol. Associating the annotations with the correct type requires interpreting the JVMS - * 4.7.20-A target_type to locate the correct type to rewrite, and then interpreting the JVMS - * 4.7.20.2 type_path to associate the annotation with the correct contained type. - */ - private static void addTypeAnnotationsToSymbol( - Symbol s, List attributes) { - new TypeAnnotationSymbolVisitor(attributes).visit(s, null); - } - - private static class TypeAnnotationSymbolVisitor - extends Types.DefaultSymbolVisitor { - - private final List attributes; - - private TypeAnnotationSymbolVisitor(List attributes) { - this.attributes = attributes; - } - - @Override - public Void visitClassSymbol(Symbol.ClassSymbol s, Void unused) { - ClassType t = (ClassType) s.type; - int i = 0; - ListBuffer interfaces = new ListBuffer<>(); - for (Type itf : t.interfaces_field) { - interfaces.add(addTypeAnnotations(itf, classExtends(i++))); - } - t.interfaces_field = interfaces.toList(); - t.supertype_field = addTypeAnnotations(t.supertype_field, classExtends(65535)); - if (t.typarams_field != null) { - t.typarams_field = - rewriteTypeParameters( - t.typarams_field, TargetType.CLASS_TYPE_PARAMETER_BOUND); - } - return null; - } - - @Override - public Void visitMethodSymbol(Symbol.MethodSymbol s, Void unused) { - Type t = s.type; - if (t.hasTag(TypeTag.FORALL)) { - Type.ForAll fa = (Type.ForAll) t; - fa.tvars = rewriteTypeParameters(fa.tvars, TargetType.METHOD_TYPE_PARAMETER_BOUND); - t = fa.qtype; - } - MethodType mt = (MethodType) t; - ListBuffer argtypes = new ListBuffer<>(); - int i = 0; - for (Symbol.VarSymbol param : s.params) { - param.type = addTypeAnnotations(param.type, methodFormalParameter(i++)); - argtypes.add(param.type); - } - mt.argtypes = argtypes.toList(); - ListBuffer thrown = new ListBuffer<>(); - i = 0; - for (Type thrownType : mt.thrown) { - thrown.add(addTypeAnnotations(thrownType, thrownType(i++))); - } - mt.thrown = thrown.toList(); - /* possible information loss if the type of the method is void then we can't add type - * annotations to it - */ - if (!mt.restype.hasTag(TypeTag.VOID)) { - mt.restype = addTypeAnnotations(mt.restype, TargetType.METHOD_RETURN); - } - if (mt.recvtype != null) { - mt.recvtype = addTypeAnnotations(mt.recvtype, TargetType.METHOD_RECEIVER); - } - return null; - } - - @Override - public Void visitVarSymbol(Symbol.VarSymbol s, Void unused) { - s.type = addTypeAnnotations(s.type, TargetType.FIELD); - return null; - } - - @Override - public Void visitSymbol(Symbol s, Void unused) { - return null; - } - - private List rewriteTypeParameters(List tvars, TargetType boundType) { - ListBuffer tvarbuf = new ListBuffer<>(); - int typeVariableIndex = 0; - for (Type tvar : tvars) { - Type bound = tvar.getUpperBound(); - if (bound.isCompound()) { - ClassType ct = (ClassType) bound; - int boundIndex = 0; - if (ct.supertype_field != null) { - ct.supertype_field = - addTypeAnnotations( - ct.supertype_field, - typeParameterBound( - boundType, typeVariableIndex, boundIndex++)); - } - ListBuffer itfbuf = new ListBuffer<>(); - for (Type itf : ct.interfaces_field) { - itfbuf.add( - addTypeAnnotations( - itf, - typeParameterBound( - boundType, typeVariableIndex, boundIndex++))); - } - ct.interfaces_field = itfbuf.toList(); - } else { - bound = - addTypeAnnotations( - bound, - typeParameterBound( - boundType, - typeVariableIndex, - bound.isInterface() ? 1 : 0)); - } - ((TypeVar) tvar).setUpperBound(bound); - tvarbuf.add(tvar); - typeVariableIndex++; - } - return tvarbuf.toList(); - } - - private Type addTypeAnnotations(Type type, TargetType targetType) { - return addTypeAnnotations(type, pos -> pos.type == targetType); - } - - private Type addTypeAnnotations(Type type, Predicate filter) { - Assert.checkNonNull(type); - - // Find type annotations that match the given target type - ListBuffer filtered = new ListBuffer<>(); - for (Attribute.TypeCompound attribute : this.attributes) { - if (filter.test(attribute.position)) { - filtered.add(attribute); - } - } - if (filtered.isEmpty()) { - return type; - } - - // Group the matching annotations by their type path. Each group of annotations will be - // added to a type at that location. - Map, ListBuffer> - attributesByPath = new HashMap<>(); - for (Attribute.TypeCompound attribute : filtered.toList()) { - attributesByPath - .computeIfAbsent(attribute.position.location, k -> new ListBuffer<>()) - .add(attribute); - } - - // Search the structure of the type to find the contained types at each type path - Map> attributesByType = new HashMap<>(); - new TypeAnnotationLocator(attributesByPath, attributesByType).visit(type, List.nil()); - - // Rewrite the type and add the annotations - type = new TypeAnnotationTypeMapping(attributesByType).visit(type, null); - Assert.check(attributesByType.isEmpty(), "Failed to apply annotations to types"); - - return type; - } - - private static Predicate typeParameterBound( - TargetType targetType, int parameterIndex, int boundIndex) { - return pos -> - pos.type == targetType - && pos.parameter_index == parameterIndex - && pos.bound_index == boundIndex; - } - - private static Predicate methodFormalParameter(int index) { - return pos -> - pos.type == TargetType.METHOD_FORMAL_PARAMETER && pos.parameter_index == index; - } - - private static Predicate thrownType(int index) { - return pos -> pos.type == TargetType.THROWS && pos.type_index == index; - } - - private static Predicate classExtends(int index) { - return pos -> pos.type == TargetType.CLASS_EXTENDS && pos.type_index == index; - } - } - - /** - * Visit all contained types, assembling a type path to represent the current location, and - * record the types at each type path that need to be annotated. - */ - private static class TypeAnnotationLocator - extends Types.DefaultTypeVisitor> { - private final Map, - ListBuffer> attributesByPath; - private final Map> attributesByType; - - private TypeAnnotationLocator( - Map, ListBuffer> - attributesByPath, - Map> attributesByType) { - this.attributesByPath = attributesByPath; - this.attributesByType = attributesByType; - } - - @Override - public Void visitClassType(ClassType t, List path) { - // As described in JVMS 4.7.20.2, type annotations on nested types are located with - // 'left-to-right' steps starting on 'the outermost part of the type for which a type - // annotation is admissible'. So the current path represents the outermost containing - // type of the type being visited, and we add type path steps for every contained nested - // type. - List enclosing = List.nil(); - for (Type curr = t; - curr != null && curr != Type.noType; - curr = curr.getEnclosingType()) { - enclosing = enclosing.prepend((ClassType) curr); - } - for (ClassType te : enclosing) { - if (te.typarams_field != null) { - int i = 0; - for (Type typaram : te.typarams_field) { - visit(typaram, path.append(new TypeAnnotationPosition.TypePathEntry( - TypeAnnotationPosition.TypePathEntryKind.TYPE_ARGUMENT, i++))); - } - } - visitType(te, path); - path = path.append(TypeAnnotationPosition.TypePathEntry.INNER_TYPE); - } - return null; - } - - @Override - public Void visitWildcardType( - WildcardType t, List path) { - visit(t.type, path.append(TypeAnnotationPosition.TypePathEntry.WILDCARD)); - return super.visitWildcardType(t, path); - } - - @Override - public Void visitArrayType(ArrayType t, List path) { - visit(t.elemtype, path.append(TypeAnnotationPosition.TypePathEntry.ARRAY)); - return super.visitArrayType(t, path); - } - - @Override - public Void visitType(Type t, List path) { - ListBuffer attributes = attributesByPath.remove(path); - if (attributes != null) { - attributesByType.put(t, attributes.toList()); - } - return null; - } - } - - /** A type mapping that rewrites the type to include type annotations. */ - private static class TypeAnnotationTypeMapping extends Type.StructuralTypeMapping { - - private final Map> attributesByType; - - private TypeAnnotationTypeMapping( - Map> attributesByType) { - this.attributesByType = attributesByType; - } - - private Type reannotate(T t, BiFunction f) { - // We're relying on object identify of Type instances to record where the annotations - // need to be added, so we have to retrieve the annotations for each type before - // rewriting it, and then add them after its contained types have been rewritten. - List attributes = attributesByType.remove(t); - Type mapped = f.apply(t, null); - if (attributes == null) { - return mapped; - } - // Runtime-visible and -invisible annotations are completed separately, so if the same - // type has annotations from both it will get annotated twice. - TypeMetadata.Annotations existing = mapped.getMetadata(TypeMetadata.Annotations.class); - if (existing != null) { - existing.annotationBuffer().addAll(attributes); - return mapped; - } - return mapped.annotatedType(attributes); - } - - @Override - public Type visitClassType(ClassType t, Void unused) { - return reannotate(t, super::visitClassType); - } - - @Override - public Type visitWildcardType(WildcardType t, Void unused) { - return reannotate(t, super::visitWildcardType); - } - - @Override - public Type visitArrayType(ArrayType t, Void unused) { - return reannotate(t, super::visitArrayType); - } - - @Override - public Type visitType(Type t, Void unused) { - return reannotate(t, (x, u) -> x); - } - } /************************************************************************ * Reading Symbols diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnosOnConstructorsTest.java b/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnosOnConstructorsTest.java deleted file mode 100644 index 996d12b35a4..00000000000 --- a/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnosOnConstructorsTest.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 8320001 - * @summary javac crashes while adding type annotations to the return type of a constructor - * @library /tools/lib /tools/javac/lib - * @modules - * jdk.compiler/com.sun.tools.javac.api - * jdk.compiler/com.sun.tools.javac.main - * @build toolbox.ToolBox toolbox.JavacTask - * @run main TypeAnnosOnConstructorsTest - */ - -import java.io.IOException; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -import java.util.List; -import java.util.Set; -import javax.annotation.processing.AbstractProcessor; -import javax.annotation.processing.RoundEnvironment; -import javax.annotation.processing.SupportedAnnotationTypes; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.TypeElement; - -import toolbox.JavacTask; -import toolbox.Task; -import toolbox.Task.Mode; -import toolbox.Task.OutputKind; -import toolbox.TestRunner; -import toolbox.ToolBox; - -public class TypeAnnosOnConstructorsTest extends TestRunner { - protected ToolBox tb; - - TypeAnnosOnConstructorsTest() { - super(System.err); - tb = new ToolBox(); - } - - public static void main(String... args) throws Exception { - new TypeAnnosOnConstructorsTest().runTests(); - } - - protected void runTests() throws Exception { - runTests(m -> new Object[]{Paths.get(m.getName())}); - } - - Path[] findJavaFiles(Path... paths) throws IOException { - return tb.findJavaFiles(paths); - } - - @Test - public void testAnnoOnConstructors(Path base) throws Exception { - Path src = base.resolve("src"); - Path y = src.resolve("Y.java"); - Path classes = base.resolve("classes"); - - Files.createDirectories(classes); - - tb.writeJavaFiles(src, - """ - import java.lang.annotation.Target; - import java.lang.annotation.ElementType; - import java.lang.annotation.Retention; - import java.lang.annotation.RetentionPolicy; - - class Y { - @TA public Y() {} - } - - @Target(ElementType.TYPE_USE) - @Retention(RetentionPolicy.RUNTIME) - @interface TA {} - """); - - // we need to compile Y first - new JavacTask(tb) - .files(y) - .outdir(classes) - .run(); - - Path classDir = getClassDir(); - new JavacTask(tb) - .classpath(classes, classDir) - .options("-processor", SimpleProcessor.class.getName()) - .classes("Y") - .outdir(classes) - .run(Task.Expect.SUCCESS); - } - - public Path getClassDir() { - String classes = ToolBox.testClasses; - if (classes == null) { - return Paths.get("build"); - } else { - return Paths.get(classes); - } - } - - @SupportedAnnotationTypes("*") - public static final class SimpleProcessor extends AbstractProcessor { - @Override - public SourceVersion getSupportedSourceVersion() { - return SourceVersion.latestSupported(); - } - - @Override - public boolean process(Set annotations, RoundEnvironment roundEnv) { - return false; - } - } -} diff --git a/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java b/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java index af63575052c..b58b434baff 100644 --- a/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java +++ b/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java @@ -33,7 +33,6 @@ * jdk.compiler/com.sun.tools.javac.util * @build JavacTestingAbstractProcessor DPrinter BasicAnnoTests * @compile/process -XDaccessInternalAPI -processor BasicAnnoTests -proc:only BasicAnnoTests.java - * @compile/process -XDaccessInternalAPI -processor BasicAnnoTests -proc:only BasicAnnoTests */ import java.io.PrintWriter;