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 <[email protected]>
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: [email protected]
For additional commands, e-mail: [email protected]
For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists