This is an automated email from the ASF dual-hosted git repository. lkishalmi pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/netbeans.git
The following commit(s) were added to refs/heads/master by this push: new fd9bab3c99 Retain SOURCE annotations inside the intenal model. (#4882) fd9bab3c99 is described below commit fd9bab3c991ede9acb5caddbaf3193943a7814a1 Author: Jan Lahoda <jlah...@netbeans.org> AuthorDate: Mon Apr 17 20:29:15 2023 +0200 Retain SOURCE annotations inside the intenal model. (#4882) --- .../lib/nbjavac/services/NBClassReader.java | 60 +++++++++- .../lib/nbjavac/services/NBClassWriter.java | 133 ++++++++++++++++++++- .../lib/nbjavac/services/NBClassWriterTest.java | 81 +++++++++++-- .../netbeans/lib/nbjavac/services/Utilities.java | 1 + 4 files changed, 263 insertions(+), 12 deletions(-) diff --git a/java/lib.nbjavac/src/org/netbeans/lib/nbjavac/services/NBClassReader.java b/java/lib.nbjavac/src/org/netbeans/lib/nbjavac/services/NBClassReader.java index 9bad23cc29..d8d1722e1c 100644 --- a/java/lib.nbjavac/src/org/netbeans/lib/nbjavac/services/NBClassReader.java +++ b/java/lib.nbjavac/src/org/netbeans/lib/nbjavac/services/NBClassReader.java @@ -33,6 +33,8 @@ import com.sun.tools.javac.util.Names; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.Arrays; import java.util.logging.Level; import java.util.logging.Logger; @@ -45,6 +47,8 @@ import javax.tools.JavaFileObject; */ public class NBClassReader extends ClassReader { + private static final Logger LOG = Logger.getLogger(NBClassReader.class.getName()); + public static void preRegister(Context context) { context.put(classReaderKey, new Context.Factory<ClassReader>() { @Override @@ -73,6 +77,24 @@ public class NBClassReader extends ClassReader { bp = newbp; } }, + new NBAttributeReader(nbNames._org_netbeans_SourceLevelAnnotations, Version.V49, CLASS_OR_MEMBER_ATTRIBUTE) { + protected void read(Symbol sym, int attrLen) { + attachAnnotations(sym); + } + + }, + new NBAttributeReader(nbNames._org_netbeans_SourceLevelParameterAnnotations, Version.V49, CLASS_OR_MEMBER_ATTRIBUTE) { + protected void read(Symbol sym, int attrLen) { + attachParameterAnnotations(sym); + } + + }, + new NBAttributeReader(nbNames._org_netbeans_SourceLevelTypeAnnotations, Version.V52, CLASS_OR_MEMBER_ATTRIBUTE) { + protected void read(Symbol sym, int attrLen) { + attachTypeAnnotations(sym); + } + + }, }; for (NBAttributeReader r: readers) @@ -109,7 +131,7 @@ public class NBClassReader extends ClassReader { } } } catch (IOException ex) { - Logger.getLogger(NBClassReader.class.getName()).log(Level.FINE, null, ex); + LOG.log(Level.FINE, null, ex); } finally { c.classfile = origFile; } @@ -131,6 +153,42 @@ public class NBClassReader extends ClassReader { return Arrays.copyOf(data, off); } + private void attachAnnotations(Symbol sym) { + try { + Method m = ClassReader.class.getDeclaredMethod("attachAnnotations", Symbol.class); + m.setAccessible(true); + m.invoke(this, sym); + } catch (NoSuchMethodException | SecurityException | + IllegalAccessException | IllegalArgumentException | + InvocationTargetException ex) { + LOG.log(Level.SEVERE, null, ex); + } + } + + private void attachParameterAnnotations(Symbol sym) { + try { + Method m = ClassReader.class.getDeclaredMethod("readParameterAnnotations", Symbol.class); + m.setAccessible(true); + m.invoke(this, sym); + } catch (NoSuchMethodException | SecurityException | + IllegalAccessException | IllegalArgumentException | + InvocationTargetException ex) { + LOG.log(Level.SEVERE, null, ex); + } + } + + private void attachTypeAnnotations(Symbol sym) { + try { + Method m = ClassReader.class.getDeclaredMethod("attachTypeAnnotations", Symbol.class); + m.setAccessible(true); + m.invoke(this, sym); + } catch (NoSuchMethodException | SecurityException | + IllegalAccessException | IllegalArgumentException | + InvocationTargetException ex) { + LOG.log(Level.SEVERE, null, ex); + } + } + private abstract class NBAttributeReader extends AttributeReader { private NBAttributeReader(Name name, Version version, Set<AttributeKind> kinds) { diff --git a/java/lib.nbjavac/src/org/netbeans/lib/nbjavac/services/NBClassWriter.java b/java/lib.nbjavac/src/org/netbeans/lib/nbjavac/services/NBClassWriter.java index 9a16f9e6ad..385bce20af 100644 --- a/java/lib.nbjavac/src/org/netbeans/lib/nbjavac/services/NBClassWriter.java +++ b/java/lib.nbjavac/src/org/netbeans/lib/nbjavac/services/NBClassWriter.java @@ -19,19 +19,22 @@ package org.netbeans.lib.nbjavac.services; import com.sun.tools.javac.code.Attribute; +import com.sun.tools.javac.code.Attribute.Compound; import com.sun.tools.javac.code.Attribute.RetentionPolicy; import com.sun.tools.javac.code.Attribute.TypeCompound; +import com.sun.tools.javac.code.Kinds.Kind; import com.sun.tools.javac.code.Symbol; -import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Symbol.MethodSymbol; import com.sun.tools.javac.code.Symbol.VarSymbol; import com.sun.tools.javac.code.Types; import com.sun.tools.javac.jvm.ClassWriter; -import com.sun.tools.javac.jvm.Target; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; -import java.util.Collection; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Level; +import java.util.logging.Logger; /** * @@ -39,6 +42,8 @@ import java.util.Collection; */ public class NBClassWriter extends ClassWriter { + private static final Logger LOG = Logger.getLogger(NBClassWriter.class.getName()); + public static void preRegister(Context context) { context.put(classWriterKey, new Context.Factory<ClassWriter>() { public ClassWriter make(Context c) { @@ -55,5 +60,125 @@ public class NBClassWriter extends ClassWriter { nbNames = NBNames.instance(context); types = Types.instance(context); } - + + @Override + protected int writeExtraAttributes(Symbol sym) { + int attrs = super.writeExtraAttributes(sym); + if (sym.kind == Kind.MTH) { + attrs += writeExtraParameterAttributes((MethodSymbol) sym); + } + attrs += writeExtraJavaAnnotations(sym.getRawAttributes()); + attrs += writeExtraTypeAnnotations(sym.getRawTypeAttributes()); + return attrs; + } + + + protected int writeExtraParameterAttributes(MethodSymbol m) { + boolean hasSourceLevel = false; + if (m.params != null) for (VarSymbol s : m.params) { + for (Attribute.Compound a : s.getRawAttributes()) { + if (types.getRetention(a) == RetentionPolicy.SOURCE) { + hasSourceLevel = true; + break; + } + } + } + int attrCount = 0; + if (hasSourceLevel) { + int attrIndex = writeAttr(nbNames._org_netbeans_SourceLevelParameterAnnotations); + databuf.appendByte(m.params.length()); + for (VarSymbol s : m.params) { + ListBuffer<Attribute.Compound> buf = new ListBuffer<Attribute.Compound>(); + for (Attribute.Compound a : s.getRawAttributes()) + if (types.getRetention(a) == RetentionPolicy.SOURCE) + buf.append(a); + databuf.appendChar(buf.length()); + for (Attribute.Compound a : buf) + writeCompoundAttribute(a); + } + endAttr(attrIndex); + attrCount++; + } + return attrCount; + } + + protected int writeExtraJavaAnnotations(List<Attribute.Compound> attrs) { + ListBuffer<Attribute.Compound> sourceLevel = new ListBuffer<Attribute.Compound>(); + for (Attribute.Compound a : attrs) { + if (types.getRetention(a) == RetentionPolicy.SOURCE) { + sourceLevel.append(a); + } + } + int attrCount = 0; + if (sourceLevel.nonEmpty()) { + int attrIndex = writeAttr(nbNames._org_netbeans_SourceLevelAnnotations); + databuf.appendChar(sourceLevel.length()); + for (Attribute.Compound a : sourceLevel) + writeCompoundAttribute(a); + endAttr(attrIndex); + attrCount++; + } + return attrCount; + } + + protected int writeExtraTypeAnnotations(List<TypeCompound> attrs) { + ListBuffer<Attribute.TypeCompound> sourceLevel = new ListBuffer<Attribute.TypeCompound>(); + for (Attribute.TypeCompound tc : attrs) { + if (tc.hasUnknownPosition()) { + boolean fixed = tc.tryFixPosition(); + + // Could we fix it? + if (!fixed) { + // This happens for nested types like @A Outer. @B Inner. + // For method parameters we get the annotation twice! Once with + // a valid position, once unknown. + // TODO: find a cleaner solution. + continue; + } + } + + if (tc.position.type.isLocal()) + continue; + if (!tc.position.emitToClassfile()) { + continue; + } + if (types.getRetention(tc) == RetentionPolicy.SOURCE) { + sourceLevel.append(tc); + } + } + int attrCount = 0; + if (sourceLevel.nonEmpty()) { + int attrIndex = writeAttr(nbNames._org_netbeans_SourceLevelTypeAnnotations); + databuf.appendChar(sourceLevel.length()); + for (Attribute.TypeCompound p : sourceLevel) + writeTypeAnnotation(p); + endAttr(attrIndex); + attrCount++; + } + return attrCount; + } + + private void writeCompoundAttribute(Compound a) { + try { + Method m = ClassWriter.class.getDeclaredMethod("writeCompoundAttribute", Compound.class); + m.setAccessible(true); + m.invoke(this, a); + } catch (NoSuchMethodException | SecurityException | + IllegalAccessException | IllegalArgumentException | + InvocationTargetException ex) { + LOG.log(Level.SEVERE, null, ex); + } + } + + private void writeTypeAnnotation(TypeCompound p) { + try { + Method m = ClassWriter.class.getDeclaredMethod("writeTypeAnnotation", TypeCompound.class); + m.setAccessible(true); + m.invoke(this, p); + } catch (NoSuchMethodException | SecurityException | + IllegalAccessException | IllegalArgumentException | + InvocationTargetException ex) { + LOG.log(Level.SEVERE, null, ex); + } + } } diff --git a/java/lib.nbjavac/test/unit/src/org/netbeans/lib/nbjavac/services/NBClassWriterTest.java b/java/lib.nbjavac/test/unit/src/org/netbeans/lib/nbjavac/services/NBClassWriterTest.java index b9c573239e..45bc85dc94 100644 --- a/java/lib.nbjavac/test/unit/src/org/netbeans/lib/nbjavac/services/NBClassWriterTest.java +++ b/java/lib.nbjavac/test/unit/src/org/netbeans/lib/nbjavac/services/NBClassWriterTest.java @@ -27,7 +27,12 @@ import java.net.URI; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Set; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Name; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.util.ElementFilter; @@ -39,7 +44,7 @@ import javax.tools.StandardLocation; import javax.tools.ToolProvider; import org.netbeans.junit.NbTestCase; -import static org.netbeans.lib.nbjavac.services.Utilities.DEV_NULL; +import static org.netbeans.lib.nbjavac.services.Utilities.OUT; /** * @@ -47,6 +52,8 @@ import static org.netbeans.lib.nbjavac.services.Utilities.DEV_NULL; */ public class NBClassWriterTest extends NbTestCase { + private final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); + public NBClassWriterTest(String testName) { super(testName); } @@ -57,6 +64,69 @@ public class NBClassWriterTest extends NbTestCase { testEnclosedByPackage("test", "test.Test"); } + public void testSourceRetentionAnnotations() throws Exception { + String code = "package test;\n" + + "import java.lang.annotation.ElementType;\n" + + "import java.lang.annotation.Retention;\n" + + "import java.lang.annotation.RetentionPolicy;\n" + + "import java.lang.annotation.Target;\n" + + "import java.util.List;\n" + + "@SourceRetention\n" + + "public class Test {\n" + + " @SourceRetention\n" + + " int testField;\n" + + " @SourceRetention\n" + + " <@SourceRetentionTypeAnnotation T> void testMethod(@SourceRetention int testParam) {\n" + + " }\n" + + "}\n" + + "@Retention(RetentionPolicy.SOURCE)\n" + + "@interface SourceRetention {}\n"+ + "@Retention(RetentionPolicy.SOURCE)\n" + + "@Target(ElementType.TYPE_USE)\n" + + "@interface SourceRetentionTypeAnnotation {}\n"; + compile(code); + + Context context = new Context(); + NBLog.preRegister(context, OUT); + JavacTaskImpl ct = (JavacTaskImpl) ((JavacTool)tool).getTask(null, null, null, Arrays.asList("-source", "1.7", "-target", "1.7", "-classpath", workingDir.toString()), null, Arrays.asList(new MyFileObject("")), context); + + NBClassReader.preRegister(ct.getContext()); + NBClassWriter.preRegister(ct.getContext()); + + ct.enter(); + + TypeElement test = ct.getElements().getTypeElement("test.Test"); + + assertNotNull(test); + + checkHasAnnotation(test, "test.SourceRetention"); + checkHasAnnotation(ElementFilter.fieldsIn(test.getEnclosedElements()).get(0), "test.SourceRetention"); + ExecutableElement method = ElementFilter.methodsIn(test.getEnclosedElements()).get(0); + checkHasAnnotation(method, "test.SourceRetention"); + checkHasAnnotation(method.getParameters().get(0), "test.SourceRetention"); + checkHasAnnotation(method.getTypeParameters().get(0).getAnnotationMirrors(), "test.SourceRetentionTypeAnnotation"); + } + + private void checkHasAnnotation(Element element, String annotationType) { + checkHasAnnotation(element.getAnnotationMirrors(), annotationType); + } + + private void checkHasAnnotation(List<? extends AnnotationMirror> annotations, String annotationType) { + boolean seenAnnotation = false; + + for (AnnotationMirror am : annotations) { + Name actualAnnotation = ((TypeElement) am.getAnnotationType().asElement()).getQualifiedName(); + if (actualAnnotation.contentEquals(annotationType)) { + seenAnnotation = true; + break; + } + } + + if (!seenAnnotation) { + fail(); + } + } + //<editor-fold defaultstate="collapsed" desc=" Test Infrastructure "> private static class MyFileObject extends SimpleJavaFileObject { private String text; @@ -80,21 +150,18 @@ public class NBClassWriterTest extends NbTestCase { } private void compile(String code) throws Exception { - final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); - assert tool != null; - StandardJavaFileManager std = tool.getStandardFileManager(null, null, null); std.setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(workingDir)); Context context = new Context(); - NBLog.preRegister(context, DEV_NULL); + NBLog.preRegister(context, OUT); final JavacTaskImpl ct = (JavacTaskImpl) ((JavacTool)tool).getTask(null, std, null, Arrays.asList("-source", "1.8", "-target", "1.8"), null, Arrays.asList(new MyFileObject(code)), context); NBClassReader.preRegister(ct.getContext()); NBClassWriter.preRegister(ct.getContext()); - ct.call(); + assertTrue(ct.call()); } private void testEnclosedByPackage(String packageName, String... expectedClassNames) throws IOException { @@ -107,7 +174,7 @@ public class NBClassWriterTest extends NbTestCase { std.setLocation(StandardLocation.CLASS_PATH, Collections.singleton(workingDir)); Context context = new Context(); - NBLog.preRegister(context, DEV_NULL); + NBLog.preRegister(context, OUT); JavacTaskImpl ct = (JavacTaskImpl)((JavacTool)tool).getTask(null, std, null, Arrays.asList("-source", "1.8", "-target", "1.8"), null, Arrays.<JavaFileObject>asList(), context); NBClassReader.preRegister(ct.getContext()); diff --git a/java/lib.nbjavac/test/unit/src/org/netbeans/lib/nbjavac/services/Utilities.java b/java/lib.nbjavac/test/unit/src/org/netbeans/lib/nbjavac/services/Utilities.java index b2ee1fc1c3..b57f165789 100644 --- a/java/lib.nbjavac/test/unit/src/org/netbeans/lib/nbjavac/services/Utilities.java +++ b/java/lib.nbjavac/test/unit/src/org/netbeans/lib/nbjavac/services/Utilities.java @@ -76,6 +76,7 @@ public class Utilities { } public static final PrintWriter DEV_NULL = new PrintWriter(new NullWriter(), false); + public static final PrintWriter OUT = new PrintWriter(System.err, true); private static class NullWriter extends Writer { --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@netbeans.apache.org For additional commands, e-mail: commits-h...@netbeans.apache.org For further information about the NetBeans mailing lists, visit: https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists