Skip to content

Commit

Permalink
Ensure AttrContext.returnResult's checkContext is set to Check.basicH…
Browse files Browse the repository at this point in the history
…andler in javac's Scopes, to avoid it throwing exceptions.
  • Loading branch information
lahodaj committed Dec 3, 2024
1 parent 6b34b88 commit 3959bf1
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@
import com.sun.source.tree.ImportTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.ModifiersTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.StatementTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.Tree.Kind;
import com.sun.source.tree.TypeParameterTree;
import com.sun.source.tree.VariableTree;
import com.sun.source.util.SourcePositions;
import com.sun.source.util.TreePath;
import com.sun.source.util.TreePathScanner;
import java.beans.PropertyVetoException;
import java.io.File;
import java.io.IOException;
Expand Down Expand Up @@ -1553,6 +1555,63 @@ public void run(WorkingCopy parameter) throws Exception {
parameter.rewrite(testTree, nueTestTree);
}
}

public void testGenerateMethodInLambda() throws Exception {
performTest("test/Test.java",
"""
package test;
public class Test {
private void test(Runnable r) {
test(() -> {
new Base<Void, Void>() {};
});
}
}
class Base<T1, T2> {
public T1 test(T1 p) {}
}
""",
"17",
new Task<WorkingCopy>() {
@Override
public void run(WorkingCopy copy) throws java.lang.Exception {
copy.toPhase(Phase.RESOLVED);
new TreePathScanner<Void, Void>() {
@Override
public Void visitNewClass(NewClassTree node, Void p) {
if (node.getClassBody() != null) {
ClassTree clazz = node.getClassBody();
TypeElement anon = (TypeElement) copy.getTrees().getElement(new TreePath(getCurrentPath(), clazz));
TypeElement superClass = (TypeElement) ((DeclaredType) anon.getSuperclass()).asElement();
ExecutableElement method = (ExecutableElement) superClass.getEnclosedElements().stream().filter(el -> el.getSimpleName().contentEquals("test")).findAny().get();
copy.rewrite(clazz, copy.getTreeMaker().addClassMember(clazz, GeneratorUtilities.get(copy).createOverridingMethod(anon, method)));
}
return super.visitNewClass(node, p);
}

}.scan(copy.getCompilationUnit(), null);
}
},
new ContentValidator("""
package test;
public class Test {
private void test(Runnable r) {
test(() -> {
new Base<Void, Void>() {
@Override
public Void test(Void p) {
return super.test(p); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody
}
};
});
}
}
class Base<T1, T2> {
public T1 test(T1 p) {}
}
"""),
false);
}

private static final class ContentValidator implements Validator {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@
import java.util.regex.Pattern;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.source.Comment.Style;
Expand Down Expand Up @@ -874,4 +876,27 @@ public void testPathForInUnnamedClass() throws Exception {

assertEquals("System", it.getName().toString());
}

public void testAttributeTreeCrashes() throws Exception {
this.sourceLevel = "21";

String code = """
package test;
public class Test {
private void test(Runnable r) {
test(() -> {
|
});
}
}
""";

prepareTest("Test", code.replace("|", ""));

int pos = code.indexOf("|");
TreePath tp = info.getTreeUtilities().pathFor(pos);
Scope scope = info.getTrees().getScope(tp);
StatementTree tree = info.getTreeUtilities().parseStatement("{ return super.test(p); }", new SourcePositions[1]);
info.getTreeUtilities().attributeTree(tree, scope);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,21 @@
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.comp.AttrContext;
import com.sun.tools.javac.comp.Check;
import com.sun.tools.javac.comp.Check.CheckContext;
import com.sun.tools.javac.comp.Env;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.tree.TreeInfo;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.util.Context;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.lang.model.element.Element;

/**
Expand All @@ -39,7 +47,9 @@
*/
public class NBJavacTrees extends JavacTrees {

private static final Logger LOG = Logger.getLogger(NBJavacTrees.class.getName());
private final Map<Element, TreePath> element2paths = new HashMap<>();
private final CheckContext chkBasicHandler;

public static void preRegister(Context context) {
context.put(JavacTrees.class, new Context.Factory<JavacTrees>() {
Expand All @@ -50,7 +60,21 @@ public JavacTrees make(Context c) {
}
protected NBJavacTrees(Context context) {
super(context);
Check chk = Check.instance(context);

CheckContext chkBasicHandlerTemp = null;

try {
if (basicHandlerField != null) {
chkBasicHandlerTemp = (CheckContext) basicHandlerField.get(chk);
}
} catch (ReflectiveOperationException ex) {
LOG.log(Level.FINE, null, ex);
}

chkBasicHandler = chkBasicHandlerTemp;
}

@Override
public TreePath getPath(Element e) {
TreePath path = super.getPath(e);
Expand Down Expand Up @@ -81,4 +105,53 @@ public JCTree visitVariable(VariableTree node, JCTree p) {
};
}

@Override
public JavacScope getScope(TreePath path) {
JavacScope result = super.getScope(path);

if (returnResultField != null) {
Env<AttrContext> env = result.getEnv();

try {
Object returnResult = returnResultField.get(env.info);
if (returnResult != null) {
//ensure the returnResult's checkContext is the Check.basicHandler:
returnResultField.set(env.info, dupMethod.invoke(returnResult, chkBasicHandler));
}
} catch (ReflectiveOperationException ex) {
LOG.log(Level.FINE, null, ex);
}
}

return result;
}

private static final Field basicHandlerField;
private static final Field returnResultField;
private static final Method dupMethod;

static {
Field basicHandlerFieldTemp;
Field returnResultFieldTemp;
Method dupMethodTemp;

try {
basicHandlerFieldTemp = Check.class.getDeclaredField("basicHandler");
basicHandlerFieldTemp.setAccessible(true);
returnResultFieldTemp = AttrContext.class.getDeclaredField("returnResult");
returnResultFieldTemp.setAccessible(true);
dupMethodTemp = Class.forName("com.sun.tools.javac.comp.Attr$ResultInfo")
.getDeclaredMethod("dup", CheckContext.class);
dupMethodTemp.setAccessible(true);
} catch (ReflectiveOperationException ex) {
LOG.log(Level.FINE, null, ex);
basicHandlerFieldTemp = null;
returnResultFieldTemp = null;
dupMethodTemp = null;
}

basicHandlerField = basicHandlerFieldTemp;
returnResultField = returnResultFieldTemp;
dupMethod = dupMethodTemp;
}
}

0 comments on commit 3959bf1

Please sign in to comment.