/
githubmirror
/
jdk22
Обзор
Документация
Войти
/
githubmirror
/
jdk22
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
make/jdk/src/classes/build/tools/depend/Depend.java
925 строк
35 KB
Magnus Ihse Bursie
8320915: Update copyright year in build files
29 ноя 2023, 00:40
29 ноя 2023, 00:40
ce4e6e2
Код
Авторство
О чём код?
/* * Copyright (c) 2017, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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. */ package build.tools.depend; import com.sun.source.tree.ClassTree; import com.sun.source.tree.CompilationUnitTree; import com.sun.source.tree.IdentifierTree; import com.sun.source.tree.ImportTree; import com.sun.source.tree.LiteralTree; import com.sun.source.tree.MemberReferenceTree; import com.sun.source.tree.MemberSelectTree; import com.sun.source.tree.MethodTree; import com.sun.source.tree.ModifiersTree; import com.sun.source.tree.PrimitiveTypeTree; import com.sun.source.tree.Tree; import com.sun.source.tree.VariableTree; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.annotation.Documented; import java.nio.charset.Charset; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.HexFormat; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.AnnotationValueVisitor; import javax.lang.model.element.Element; import javax.lang.model.element.ElementVisitor; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.ModuleElement; import javax.lang.model.element.ModuleElement.DirectiveVisitor; import javax.lang.model.element.ModuleElement.ExportsDirective; import javax.lang.model.element.ModuleElement.OpensDirective; import javax.lang.model.element.ModuleElement.ProvidesDirective; import javax.lang.model.element.ModuleElement.RequiresDirective; import javax.lang.model.element.ModuleElement.UsesDirective; import javax.lang.model.element.PackageElement; import javax.lang.model.element.QualifiedNameable; import javax.lang.model.element.RecordComponentElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeParameterElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.ArrayType; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.ErrorType; import javax.lang.model.type.ExecutableType; import javax.lang.model.type.IntersectionType; import javax.lang.model.type.NoType; import javax.lang.model.type.NullType; import javax.lang.model.type.PrimitiveType; import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeVariable; import javax.lang.model.type.TypeVisitor; import javax.lang.model.type.UnionType; import javax.lang.model.type.WildcardType; import javax.lang.model.util.ElementFilter; import javax.tools.JavaFileObject; import com.sun.source.util.JavacTask; import com.sun.source.util.Plugin; import com.sun.source.util.TaskEvent; import com.sun.source.util.TaskEvent.Kind; import com.sun.source.util.TaskListener; import com.sun.source.util.TreePath; import com.sun.source.util.TreeScanner; import com.sun.source.util.Trees; import com.sun.tools.javac.api.BasicJavacTask; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Context.Key; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Options; import com.sun.tools.javac.util.StringUtils; import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.IdentityHashMap; import java.util.LinkedHashMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.StreamSupport; import javax.lang.model.element.ElementKind; import javax.lang.model.element.Name; import javax.tools.ForwardingJavaFileManager; import javax.tools.JavaFileManager; import javax.tools.StandardLocation; import javax.tools.ToolProvider; public class Depend implements Plugin { @Override public String getName() { return "depend"; } @Override public void init(JavacTask jt, String... args) { addExports(); Path internalAPIDigestFile; Map<String, String> internalAPI = new HashMap<>(); AtomicBoolean noApiChange = new AtomicBoolean(); Context context = ((BasicJavacTask) jt).getContext(); JavaCompiler compiler = JavaCompiler.instance(context); try { Options options = Options.instance(context); String modifiedInputs = options.get("modifiedInputs"); if (modifiedInputs == null) { throw new IllegalStateException("Expected modifiedInputs to be set using -XDmodifiedInputs=<list-of-files>"); } String logLevel = options.get("LOG_LEVEL"); boolean debug = "trace".equals(logLevel) || "debug".equals(logLevel); String internalAPIPath = options.get("internalAPIPath"); if (internalAPIPath == null) { throw new IllegalStateException("Expected internalAPIPath to be set using -XDinternalAPIPath=<internal-API-path>"); } Set<Path> modified = Files.readAllLines(Paths.get(modifiedInputs)).stream() .map(Paths::get) .collect(Collectors.toSet()); internalAPIDigestFile = Paths.get(internalAPIPath); if (Files.isReadable(internalAPIDigestFile)) { try { Files.readAllLines(internalAPIDigestFile, StandardCharsets.UTF_8) .forEach(line -> { String[] keyAndValue = line.split("="); internalAPI.put(keyAndValue[0], keyAndValue[1]); }); } catch (IOException ex) { throw new IllegalStateException(ex); } } Class<?> initialFileParserIntf = Class.forName("com.sun.tools.javac.main.JavaCompiler$InitialFileParserIntf"); Class<?> initialFileParser = Class.forName("com.sun.tools.javac.main.JavaCompiler$InitialFileParser"); Field initialParserKeyField = initialFileParser.getDeclaredField("initialParserKey"); @SuppressWarnings("unchecked") Key<Object> key = (Key<Object>) initialParserKeyField.get(null); Object initialParserInstance = Proxy.newProxyInstance(Depend.class.getClassLoader(), new Class<?>[] {initialFileParserIntf}, new FilteredInitialFileParser(compiler, modified, internalAPI, noApiChange, debug)); context.<Object>put(key, initialParserInstance); } catch (Exception ex) { throw new IllegalStateException(ex); } jt.addTaskListener(new TaskListener() { private final Map<ModuleElement, Set<PackageElement>> apiPackages = new HashMap<>(); private final MessageDigest apiHash; { try { apiHash = MessageDigest.getInstance("SHA-256"); } catch (NoSuchAlgorithmException ex) { throw new IllegalStateException(ex); } } @Override public void started(TaskEvent te) { } @Override public void finished(TaskEvent te) { if (te.getKind() == Kind.ANALYZE) { if (te.getSourceFile().isNameCompatible("module-info", JavaFileObject.Kind.SOURCE)) { ModuleElement mod = (ModuleElement) Trees.instance(jt).getElement(new TreePath(te.getCompilationUnit())); new APIVisitor(apiHash).visit(mod); } else if (te.getSourceFile().isNameCompatible("package-info", JavaFileObject.Kind.SOURCE)) { //ignore - cannot contain important changes (?) } else { TypeElement clazz = te.getTypeElement(); ModuleElement mod = jt.getElements().getModuleOf(clazz); Set<PackageElement> thisModulePackages = apiPackages.computeIfAbsent(mod, m -> { return ElementFilter.exportsIn(mod.getDirectives()) .stream() .map(ed -> ed.getPackage()) .collect(Collectors.toSet()); }); if (thisModulePackages.contains(jt.getElements().getPackageOf(clazz))) { new APIVisitor(apiHash).visit(clazz); } } } if (te.getKind() == Kind.COMPILATION && !noApiChange.get() && compiler.errorCount() == 0) { try (OutputStream out = Files.newOutputStream(internalAPIDigestFile)) { String hashes = internalAPI.entrySet() .stream() .map(e -> e.getKey() + "=" + e.getValue()) .collect(Collectors.joining("\n")); out.write(hashes.getBytes(StandardCharsets.UTF_8)); } catch (IOException ex) { throw new IllegalStateException(ex); } String previousSignature = null; File digestFile = new File(args[0]); try (InputStream in = new FileInputStream(digestFile)) { previousSignature = new String(in.readAllBytes(), "UTF-8"); } catch (IOException ex) { //ignore } String currentSignature = Depend.this.toString(apiHash.digest()); if (!Objects.equals(previousSignature, currentSignature)) { digestFile.getParentFile().mkdirs(); try (OutputStream out = new FileOutputStream(digestFile)) { out.write(currentSignature.getBytes("UTF-8")); } catch (IOException ex) { throw new IllegalStateException(ex); } } } } }); } private void addExports() { var systemCompiler = ToolProvider.getSystemJavaCompiler(); try (JavaFileManager jfm = systemCompiler.getStandardFileManager(null, null, null)) { JavaFileManager fm = new ForwardingJavaFileManager<JavaFileManager>(jfm) { @Override public ClassLoader getClassLoader(JavaFileManager.Location location) { if (location == StandardLocation.CLASS_PATH) { return Depend.class.getClassLoader(); } return super.getClassLoader(location); } }; ((JavacTask) systemCompiler.getTask(null, fm, null, List.of("-proc:only", "-XDaccessInternalAPI=true"), List.of("java.lang.Object"), null)) .analyze(); } catch (IOException ex) { throw new IllegalStateException(ex); } } private com.sun.tools.javac.util.List<JCCompilationUnit> doFilteredParse( JavaCompiler compiler, Iterable<JavaFileObject> fileObjects, Set<Path> modified, Map<String, String> internalAPI, AtomicBoolean noApiChange, boolean debug) { Map<JavaFileObject, JCCompilationUnit> files2CUT = new IdentityHashMap<>(); boolean fullRecompile = modified.stream() .map(Path::toString) .anyMatch(f -> !StringUtils.toLowerCase(f).endsWith(".java")); ListBuffer<JCCompilationUnit> result = new ListBuffer<>(); for (JavaFileObject jfo : fileObjects) { if (modified.contains(Path.of(jfo.getName()))) { JCCompilationUnit parsed = compiler.parse(jfo); files2CUT.put(jfo, parsed); String currentSignature = treeDigest(parsed); if (!currentSignature.equals(internalAPI.get(jfo.getName()))) { fullRecompile |= true; internalAPI.put(jfo.getName(), currentSignature); } result.add(parsed); } } if (fullRecompile) { for (JavaFileObject jfo : fileObjects) { if (!modified.contains(Path.of(jfo.getName()))) { JCCompilationUnit parsed = files2CUT.get(jfo); if (parsed == null) { parsed = compiler.parse(jfo); internalAPI.put(jfo.getName(), treeDigest(parsed)); } result.add(parsed); } } } else { noApiChange.set(true); } if (debug) { long allJavaInputs = StreamSupport.stream(fileObjects.spliterator(), false).count(); String module = StreamSupport.stream(fileObjects.spliterator(), false) .map(fo -> fo.toUri().toString()) .filter(path -> path.contains("/share/classes/")) .map(path -> path.substring(0, path.indexOf("/share/classes/"))) .map(path -> path.substring(path.lastIndexOf("/") + 1)) .findAny() .orElseGet(() -> "unknown"); String nonJavaModifiedFiles = modified.stream() .map(Path::toString) .filter(f -> !StringUtils.toLowerCase(f) .endsWith(".java")) .collect(Collectors.joining(", ")); System.err.println("compiling module: " + module + ", all Java inputs: " + allJavaInputs + ", modified files (Java or non-Java): " + modified.size() + ", full recompile: " + fullRecompile + ", non-Java modified files: " + nonJavaModifiedFiles); } return result.toList(); } private String treeDigest(JCCompilationUnit cu) { try { TreeVisitor v = new TreeVisitor(MessageDigest.getInstance("MD5")); v.scan(cu, null); return Depend.this.toString(v.apiHash.digest()); } catch (NoSuchAlgorithmException ex) { throw new IllegalStateException(ex); } } private String toString(byte[] digest) { return HexFormat.of().withUpperCase().formatHex(digest); } private static final class APIVisitor implements ElementVisitor<Void, Void>, TypeVisitor<Void, Void>, AnnotationValueVisitor<Void, Void>, DirectiveVisitor<Void, Void> { private final MessageDigest apiHash; private final Charset utf8; public APIVisitor(MessageDigest apiHash) { this.apiHash = apiHash; utf8 = Charset.forName("UTF-8"); } public Void visit(Iterable<? extends Element> list, Void p) { list.forEach(e -> visit(e, p)); return null; } private void update(CharSequence data) { apiHash.update(data.toString().getBytes(utf8)); } private void visit(Iterable<? extends TypeMirror> types) { for (TypeMirror type : types) { visit(type); } } private void updateAnnotation(AnnotationMirror am) { update("@"); visit(am.getAnnotationType()); am.getElementValues() .keySet() .stream() .sorted((ee1, ee2) -> ee1.getSimpleName().toString().compareTo(ee2.getSimpleName().toString())) .forEach(ee -> { visit(ee); visit(am.getElementValues().get(ee)); }); } private void updateAnnotations(Iterable<? extends AnnotationMirror> annotations) { for (AnnotationMirror am : annotations) { if (am.getAnnotationType().asElement().getAnnotation(Documented.class) == null) continue; updateAnnotation(am); } } @Override public Void visit(Element e, Void p) { if (e.getKind() != ElementKind.MODULE && !e.getModifiers().contains(Modifier.PUBLIC) && !e.getModifiers().contains(Modifier.PROTECTED)) { return null; } update(e.getKind().name()); update(e.getModifiers().stream() .map(mod -> mod.name()) .collect(Collectors.joining(",", "[", "]"))); update(e.getSimpleName()); updateAnnotations(e.getAnnotationMirrors()); return e.accept(this, p); } @Override public Void visit(Element e) { return visit(e, null); } @Override public Void visitModule(ModuleElement e, Void p) { update(String.valueOf(e.isOpen())); update(e.getQualifiedName()); e.getDirectives() .stream() .forEach(d -> d.accept(this, null)); return null; } @Override public Void visitPackage(PackageElement e, Void p) { throw new UnsupportedOperationException("Should not get here."); } @Override public Void visitType(TypeElement e, Void p) { visit(e.getTypeParameters(), p); visit(e.getSuperclass()); visit(e.getInterfaces()); visit(e.getEnclosedElements(), p); return null; } @Override public Void visitRecordComponent(@SuppressWarnings("preview")RecordComponentElement e, Void p) { update(e.getSimpleName()); visit(e.asType()); return null; } @Override public Void visitVariable(VariableElement e, Void p) { visit(e.asType()); update(String.valueOf(e.getConstantValue())); return null; } @Override public Void visitExecutable(ExecutableElement e, Void p) { update("<"); visit(e.getTypeParameters(), p); update(">"); visit(e.getReturnType()); update("("); visit(e.getParameters(), p); update(")"); visit(e.getThrownTypes()); update(String.valueOf(e.getDefaultValue())); update(String.valueOf(e.isVarArgs())); return null; } @Override public Void visitTypeParameter(TypeParameterElement e, Void p) { visit(e.getBounds()); return null; } @Override public Void visitUnknown(Element e, Void p) { throw new UnsupportedOperationException("Not supported."); } @Override public Void visit(TypeMirror t, Void p) { if (t == null) { update("null"); return null; } update(t.getKind().name()); updateAnnotations(t.getAnnotationMirrors()); t.accept(this, p); return null; } @Override public Void visitPrimitive(PrimitiveType t, Void p) { return null; //done } @Override public Void visitNull(NullType t, Void p) { return null; //done } @Override public Void visitArray(ArrayType t, Void p) { visit(t.getComponentType()); update("[]"); return null; } @Override public Void visitDeclared(DeclaredType t, Void p) { update(((QualifiedNameable) t.asElement()).getQualifiedName()); update("<"); visit(t.getTypeArguments()); update(">"); return null; } @Override public Void visitError(ErrorType t, Void p) { return visitDeclared(t, p); } private final Set<Element> seenVariables = new HashSet<>(); @Override public Void visitTypeVariable(TypeVariable t, Void p) { Element decl = t.asElement(); if (!seenVariables.add(decl)) { return null; } visit(decl, null); visit(t.getLowerBound(), null); visit(t.getUpperBound(), null); seenVariables.remove(decl); return null; } @Override public Void visitWildcard(WildcardType t, Void p) { visit(t.getSuperBound()); visit(t.getExtendsBound()); return null; } @Override public Void visitExecutable(ExecutableType t, Void p) { throw new UnsupportedOperationException("Not supported."); } @Override public Void visitNoType(NoType t, Void p) { return null;//done } @Override public Void visitUnknown(TypeMirror t, Void p) { throw new UnsupportedOperationException("Not supported."); } @Override public Void visitUnion(UnionType t, Void p) { update("("); visit(t.getAlternatives()); update(")"); return null; } @Override public Void visitIntersection(IntersectionType t, Void p) { update("("); visit(t.getBounds()); update(")"); return null; } @Override public Void visit(AnnotationValue av, Void p) { return av.accept(this, p); } @Override public Void visitBoolean(boolean b, Void p) { update(String.valueOf(b)); return null; } @Override public Void visitByte(byte b, Void p) { update(String.valueOf(b)); return null; } @Override public Void visitChar(char c, Void p) { update(String.valueOf(c)); return null; } @Override public Void visitDouble(double d, Void p) { update(String.valueOf(d)); return null; } @Override public Void visitFloat(float f, Void p) { update(String.valueOf(f)); return null; } @Override public Void visitInt(int i, Void p) { update(String.valueOf(i)); return null; } @Override public Void visitLong(long i, Void p) { update(String.valueOf(i)); return null; } @Override public Void visitShort(short s, Void p) { update(String.valueOf(s)); return null; } @Override public Void visitString(String s, Void p) { update(s); return null; } @Override public Void visitType(TypeMirror t, Void p) { return visit(t); } @Override public Void visitEnumConstant(VariableElement c, Void p) { return visit(c); } @Override public Void visitAnnotation(AnnotationMirror a, Void p) { updateAnnotation(a); return null; } @Override public Void visitArray(List<? extends AnnotationValue> vals, Void p) { update("("); for (AnnotationValue av : vals) { visit(av); } update(")"); return null; } @Override public Void visitUnknown(AnnotationValue av, Void p) { throw new UnsupportedOperationException("Not supported."); } @Override public Void visitRequires(RequiresDirective d, Void p) { update("RequiresDirective"); update(String.valueOf(d.isStatic())); update(String.valueOf(d.isTransitive())); update(d.getDependency().getQualifiedName()); return null; } @Override public Void visitExports(ExportsDirective d, Void p) { update("ExportsDirective"); update(d.getPackage().getQualifiedName()); if (d.getTargetModules() != null) { for (ModuleElement me : d.getTargetModules()) { update(me.getQualifiedName()); } } else { update("<none>"); } return null; } @Override public Void visitOpens(OpensDirective d, Void p) { update("OpensDirective"); update(d.getPackage().getQualifiedName()); if (d.getTargetModules() != null) { for (ModuleElement me : d.getTargetModules()) { update(me.getQualifiedName()); } } else { update("<none>"); } return null; } @Override public Void visitUses(UsesDirective d, Void p) { update("UsesDirective"); update(d.getService().getQualifiedName()); return null; } @Override public Void visitProvides(ProvidesDirective d, Void p) { update("ProvidesDirective"); update(d.getService().getQualifiedName()); update("("); for (TypeElement impl : d.getImplementations()) { update(impl.getQualifiedName()); } update(")"); return null; } } private static final class TreeVisitor extends TreeScanner<Void, Void> { private final Set<Name> seenIdentifiers = new HashSet<>(); private final MessageDigest apiHash; private final Charset utf8; public TreeVisitor(MessageDigest apiHash) { this.apiHash = apiHash; utf8 = Charset.forName("UTF-8"); } private void update(CharSequence data) { apiHash.update(data.toString().getBytes(utf8)); } @Override public Void scan(Tree tree, Void p) { update("("); if (tree != null) { update(tree.getKind().name()); }; super.scan(tree, p); update(")"); return null; } @Override public Void visitCompilationUnit(CompilationUnitTree node, Void p) { seenIdentifiers.clear(); scan(node.getPackage(), p); scan(node.getTypeDecls(), p); scan(((JCCompilationUnit) node).getModuleDecl(), p); List<ImportTree> importantImports = new ArrayList<>(); for (ImportTree imp : node.getImports()) { Tree t = imp.getQualifiedIdentifier(); if (t.getKind() == Tree.Kind.MEMBER_SELECT) { Name member = ((MemberSelectTree) t).getIdentifier(); if (member.contentEquals("*") || seenIdentifiers.contains(member)) { importantImports.add(imp); } } else { //should not happen, possibly erroneous source? importantImports.add(imp); } } importantImports.sort((imp1, imp2) -> { if (imp1.isStatic() ^ imp2.isStatic()) { return imp1.isStatic() ? -1 : 1; } else { return imp1.getQualifiedIdentifier().toString().compareTo(imp2.getQualifiedIdentifier().toString()); } }); scan(importantImports, p); return null; } @Override public Void visitIdentifier(IdentifierTree node, Void p) { update(node.getName()); seenIdentifiers.add(node.getName()); return super.visitIdentifier(node, p); } @Override public Void visitMemberSelect(MemberSelectTree node, Void p) { update(node.getIdentifier()); return super.visitMemberSelect(node, p); } @Override public Void visitMemberReference(MemberReferenceTree node, Void p) { update(node.getName()); return super.visitMemberReference(node, p); } @Override public Void scan(Iterable<? extends Tree> nodes, Void p) { update("("); super.scan(nodes, p); update(")"); return null; } @Override public Void visitClass(ClassTree node, Void p) { update(node.getSimpleName()); scan(node.getModifiers(), p); scan(node.getTypeParameters(), p); scan(node.getExtendsClause(), p); scan(node.getImplementsClause(), p); scan(node.getMembers() .stream() .filter(this::importantMember) .collect(Collectors.toList()), p); return null; } private boolean importantMember(Tree m) { return switch (m.getKind()) { case ANNOTATION_TYPE, CLASS, ENUM, INTERFACE, RECORD -> !isPrivate(((ClassTree) m).getModifiers()); case METHOD -> !isPrivate(((MethodTree) m).getModifiers()); case VARIABLE -> !isPrivate(((VariableTree) m).getModifiers()) || isRecordComponent((VariableTree) m); case BLOCK -> false; default -> false; }; } private boolean isPrivate(ModifiersTree mt) { return mt.getFlags().contains(Modifier.PRIVATE); } private boolean isRecordComponent(VariableTree vt) { return (((JCVariableDecl) vt).mods.flags & Flags.RECORD) != 0; } @Override public Void visitVariable(VariableTree node, Void p) { update(node.getName()); return super.visitVariable(node, p); } @Override public Void visitMethod(MethodTree node, Void p) { update(node.getName()); scan(node.getModifiers(), p); scan(node.getReturnType(), p); scan(node.getTypeParameters(), p); scan(node.getParameters(), p); scan(node.getReceiverParameter(), p); scan(node.getThrows(), p); scan(node.getDefaultValue(), p); return null; } @Override public Void visitLiteral(LiteralTree node, Void p) { update(String.valueOf(node.getValue())); return super.visitLiteral(node, p); } @Override public Void visitModifiers(ModifiersTree node, Void p) { update(node.getFlags().toString()); return super.visitModifiers(node, p); } @Override public Void visitPrimitiveType(PrimitiveTypeTree node, Void p) { update(node.getPrimitiveTypeKind().name()); return super.visitPrimitiveType(node, p); } } private class FilteredInitialFileParser implements InvocationHandler { private final JavaCompiler compiler; private final Set<Path> modified; private final Map<String, String> internalAPI; private final AtomicBoolean noApiChange; private final boolean debug; public FilteredInitialFileParser(JavaCompiler compiler, Set<Path> modified, Map<String, String> internalAPI, AtomicBoolean noApiChange, boolean debug) { this.compiler = compiler; this.modified = modified; this.internalAPI = internalAPI; this.noApiChange = noApiChange; this.debug = debug; } @Override @SuppressWarnings("unchecked") public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return switch (method.getName()) { case "parse" -> doFilteredParse(compiler, (Iterable<JavaFileObject>) args[0], modified, internalAPI, noApiChange, debug); default -> throw new UnsupportedOperationException(); }; } } }