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

Reply via email to