diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java
index bc9b3cf63da..5ac57b6508d 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java
@@ -34,7 +34,6 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
-import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.tools.DiagnosticListener;
@@ -138,9 +137,9 @@ public class LintMapper {
* @param sourceFile source file
* @param tree top-level declaration (class, package, or module)
*/
- public void calculateLints(JavaFileObject sourceFile, JCTree tree) {
+ public void calculateLints(JavaFileObject sourceFile, JCTree tree, EndPosTable endPositions) {
Assert.check(rootLint != null);
- fileInfoMap.get(sourceFile).afterAttr(tree);
+ fileInfoMap.get(sourceFile).afterAttr(tree, endPositions);
}
/**
@@ -174,49 +173,40 @@ public class LintMapper {
* Holds {@link Lint} information for a fully parsed source file.
*
*
- * Initially (immediately after parsing), "unmappedDecls" will contain a {@link JCTree} corresponding
- * to each top-level declaration in the source file. As those top-level declarations are attributed,
- * the {@link JCTree} is removed and a new {@link MappedDecl} subtree is added to the "mappedDecls" tree.
+ * Initially (immediately after parsing), "unmappedDecls" contains a {@link Span} corresponding to each
+ * top-level declaration in the source file. As each top-level declaration is attributed, the corresponding
+ * {@link Span} is removed and the corresponding {@link LintRange} subtree is populated under "rootRange".
*/
private static class FileInfo {
- EndPosTable endPositions; // end position table for this source file (only during attribution)
- final MappedDecl mappedDecls; // root node with subtree for each mapped top-level declaration
- final List unmappedDecls; // unmapped (i.e., awaiting attribution) top-level declarations
+ final LintRange rootRange; // the root LintRange (covering the entire source file)
+ final List unmappedDecls = new ArrayList<>(); // unmapped top-level declarations awaiting attribution
// After parsing: Add top-level declarations to our "unmappedDecls" list
FileInfo(Lint rootLint, JCCompilationUnit tree) {
- this.endPositions = tree.endPositions;
- this.mappedDecls = new MappedDecl(rootLint);
- this.unmappedDecls = tree.defs.stream()
+ rootRange = new LintRange(rootLint);
+ tree.defs.stream()
.filter(this::isTopLevelDecl)
- .collect(Collectors.toCollection(ArrayList::new));
+ .map(decl -> new Span(decl, tree.endPositions))
+ .forEach(unmappedDecls::add);
}
- // After attribution: Discard the tree from "unmappedDecls" and add a corresponding MappedDecl to "mappedDecls"
- void afterAttr(JCTree tree) {
- MappedDeclBuilder builder = null;
- for (Iterator i = unmappedDecls.iterator(); i.hasNext(); ) {
- if (contains(i.next(), tree.pos())) {
- builder = new MappedDeclBuilder(mappedDecls, endPositions);
+ // After attribution: Discard the span from "unmappedDecls" and populate the declaration's subtree under "rootRange"
+ void afterAttr(JCTree tree, EndPosTable endPositions) {
+ for (Iterator i = unmappedDecls.iterator(); i.hasNext(); ) {
+ if (i.next().contains(tree.pos())) {
+ rootRange.populateSubtree(tree, endPositions);
i.remove();
- break;
+ return;
}
}
- Assert.check(builder != null, "top-level declaration not found");
- builder.scan(tree);
- if (unmappedDecls.isEmpty())
- endPositions = null; // gc friendly
+ throw new AssertionError("top-level declaration not found");
}
- // Find the (narrowest) Lint that applies to the given position, unless the position has not been mapped yet
+ // Find the most specific Lint configuration applying to the given position, unless the position has not been mapped yet
Optional lintAt(DiagnosticPosition pos) {
- boolean mapped = unmappedDecls.stream().noneMatch(tree -> contains(tree, pos));
- return mapped ? Optional.of(mappedDecls.bestMatch(pos).lint) : Optional.empty();
- }
-
- boolean contains(JCTree tree, DiagnosticPosition pos) {
- return FileInfo.contains(TreeInfo.getStartPos(tree), TreeInfo.getEndPos(tree, endPositions), pos);
+ boolean mapped = unmappedDecls.stream().noneMatch(span -> span.contains(pos));
+ return mapped ? Optional.of(rootRange.bestMatch(pos).lint) : Optional.empty();
}
boolean isTopLevelDecl(JCTree tree) {
@@ -224,141 +214,121 @@ public class LintMapper {
|| tree.getTag() == Tag.PACKAGEDEF
|| tree.getTag() == Tag.CLASSDEF;
}
-
- static boolean contains(int startPos, int endPos, DiagnosticPosition pos) {
- int offset = pos.getLintPosition();
- return offset == startPos || (offset > startPos && offset < endPos);
- }
}
-// MappedDecl
+// Span
/**
- * A module, package, class, method, or variable declaration within which all {@link Lint} configurations are known.
- * There is also a root instance that represents the entire file.
+ * A lexical range.
*/
- private static class MappedDecl {
+ private record Span(int startPos, int endPos) {
- final int startPos; // declaration's lexical starting position
- final int endPos; // declaration's lexical ending position
- final Lint lint; // the Lint configuration that applies at this declaration
- final Symbol symbol; // declaration symbol (for debug purposes only; null for root)
- final MappedDecl parent; // the parent node of this node
- final List children; // the nested declarations one level below this node
+ static final Span MAXIMAL = new Span(Integer.MIN_VALUE, Integer.MAX_VALUE);
- // Create a node representing the entire file, using the root lint configuration
- MappedDecl(Lint rootLint) {
- this(Integer.MIN_VALUE, Integer.MAX_VALUE, rootLint, null, null);
- }
-
- // Create a node representing the given declaration and its corresponding Lint configuration
- MappedDecl(JCTree tree, EndPosTable endPositions, Lint lint, Symbol symbol, MappedDecl parent) {
- this(TreeInfo.getStartPos(tree), TreeInfo.getEndPos(tree, endPositions), lint, symbol, parent);
- parent.children.add(this);
- }
-
- MappedDecl(int startPos, int endPos, Lint lint, Symbol symbol, MappedDecl parent) {
- this.startPos = startPos;
- this.endPos = endPos;
- this.lint = lint;
- this.symbol = symbol;
- this.parent = parent;
- this.children = new ArrayList<>();
- }
-
- // Find the narrowest node in this tree (including me) that contains the given position, if any
- MappedDecl bestMatch(DiagnosticPosition pos) {
- return children.stream()
- .map(child -> child.bestMatch(pos))
- .filter(Objects::nonNull)
- .reduce((a, b) -> a.contains(b) ? b : a)
- .orElseGet(() -> contains(pos) ? this : null);
+ Span(JCTree tree, EndPosTable endPositions) {
+ this(TreeInfo.getStartPos(tree), TreeInfo.getEndPos(tree, endPositions));
}
boolean contains(DiagnosticPosition pos) {
- return FileInfo.contains(startPos, endPos, pos);
+ int offset = pos.getLintPosition();
+ return offset == startPos || (offset > startPos && offset < endPos);
}
- boolean contains(MappedDecl that) {
+ boolean contains(Span that) {
return this.startPos <= that.startPos && this.endPos >= that.endPos;
}
+ }
+
+// LintRange
+
+ /**
+ * A tree of nested lexical ranges and the {@link Lint} configurations that apply therein.
+ */
+ private record LintRange(
+ Span span, // declaration's lexical range
+ Lint lint, // the Lint configuration that applies at this declaration
+ Symbol symbol, // declaration symbol (for debug purposes only; null for root)
+ LintRange parent, // the parent node of this node
+ List children // the nested declarations one level below this node
+ ) {
+
+ // Create a node representing the entire file, using the root lint configuration
+ LintRange(Lint rootLint) {
+ this(Span.MAXIMAL, rootLint, null, null, new ArrayList<>());
+ }
+
+ // Create a node representing the given declaration and its corresponding Lint configuration
+ LintRange(JCTree tree, EndPosTable endPositions, Lint lint, Symbol symbol, LintRange parent) {
+ this(new Span(tree, endPositions), lint, symbol, parent, new ArrayList<>());
+ parent.children.add(this);
+ }
+
+ // Find the most specific node in this tree (including me) that contains the given position, if any
+ LintRange bestMatch(DiagnosticPosition pos) {
+ return children.stream()
+ .map(child -> child.bestMatch(pos))
+ .filter(Objects::nonNull)
+ .reduce((a, b) -> a.span.contains(b.span) ? b : a)
+ .orElseGet(() -> span.contains(pos) ? this : null);
+ }
+
+ // Populate a sparse subtree corresponding to the given nested declaration.
+ // Only when the Lint configuration differs from the parent is a node added.
+ void populateSubtree(JCTree tree, EndPosTable endPositions) {
+ new TreeScanner() {
+
+ private LintRange parent = LintRange.this;
+
+ @Override
+ public void visitModuleDef(JCModuleDecl tree) {
+ scanDecl(tree, tree.sym, super::visitModuleDef);
+ }
+ @Override
+ public void visitPackageDef(JCPackageDecl tree) {
+ scanDecl(tree, tree.packge, super::visitPackageDef);
+ }
+ @Override
+ public void visitClassDef(JCClassDecl tree) {
+ scanDecl(tree, tree.sym, super::visitClassDef);
+ }
+ @Override
+ public void visitMethodDef(JCMethodDecl tree) {
+ scanDecl(tree, tree.sym, super::visitMethodDef);
+ }
+ @Override
+ public void visitVarDef(JCVariableDecl tree) {
+ scanDecl(tree, tree.sym, super::visitVarDef);
+ }
+
+ private void scanDecl(T tree, Symbol symbol, Consumer super T> recursor) {
+
+ // The "symbol" can be null if there were earlier errors; skip this declaration if so
+ if (symbol == null) {
+ recursor.accept(tree);
+ return;
+ }
+
+ // Update the Lint using the declaration; if there's no change, then we don't need a new node here
+ Lint newLint = parent.lint.augment(symbol);
+ if (newLint == parent.lint) { // note: lint.augment() returns the same instance if there's no change
+ recursor.accept(tree);
+ return;
+ }
+
+ // Add a new node here
+ LintRange node = parent = new LintRange(tree, endPositions, newLint, symbol, parent);
+ try {
+ recursor.accept(tree);
+ } finally {
+ parent = node.parent;
+ }
+ }
+ }.scan(tree);
+ }
@Override
public String toString() {
- String label = symbol != null ? "sym=" + symbol : "ROOT";
- return String.format("MappedDecl[%d-%d,%s,lint=%s]", startPos, endPos, label, lint);
- }
- }
-
-// MappedDeclBuilder
-
- /**
- * Builds a tree of {@link MappedDecl}s starting from a top-level declaration.
- * The tree is sparse: only declarations that differ from their parent are included.
- */
- private static class MappedDeclBuilder extends TreeScanner {
-
- private final EndPosTable endPositions;
-
- private MappedDecl parent;
- private Lint lint;
-
- MappedDeclBuilder(MappedDecl rootNode, EndPosTable endPositions) {
- this.endPositions = endPositions;
- this.parent = rootNode;
- this.lint = rootNode.lint; // i.e, rootLint
- }
-
- @Override
- public void visitModuleDef(JCModuleDecl tree) {
- scanDecl(tree, tree.sym, super::visitModuleDef);
- }
-
- @Override
- public void visitPackageDef(JCPackageDecl tree) {
- scanDecl(tree, tree.packge, super::visitPackageDef);
- }
-
- @Override
- public void visitClassDef(JCClassDecl tree) {
- scanDecl(tree, tree.sym, super::visitClassDef);
- }
-
- @Override
- public void visitMethodDef(JCMethodDecl tree) {
- scanDecl(tree, tree.sym, super::visitMethodDef);
- }
-
- @Override
- public void visitVarDef(JCVariableDecl tree) {
- scanDecl(tree, tree.sym, super::visitVarDef);
- }
-
- private void scanDecl(T tree, Symbol symbol, Consumer super T> recursor) {
-
- // The "symbol" can be null if there were earlier errors; skip this declaration if so
- if (symbol == null) {
- recursor.accept(tree);
- return;
- }
-
- // Update the current Lint in effect
- Lint previousLint = lint;
- lint = lint.augment(symbol); // note: lint.augment() returns the same instance if there's no change
-
- // Add a MappedDecl node here, but only if this declaration's Lint configuration is different from its parent
- if (lint != previousLint) {
- MappedDecl node = new MappedDecl(tree, endPositions, lint, symbol, parent);
- parent = node;
- try {
- recursor.accept(tree);
- } finally {
- parent = node.parent;
- lint = previousLint;
- }
- } else {
- recursor.accept(tree);
- }
+ return String.format("LintRange[span=%s,sym=%s,lint=%s,children=%s]", span, symbol, lint, children);
}
}
}
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
index ac5b4f41830..45ece909ad7 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
@@ -5296,7 +5296,7 @@ public class Attr extends JCTree.Visitor {
annotate.flush();
// Now that this tree is attributed, we can calculate the Lint configuration everywhere within it
- lintMapper.calculateLints(env.toplevel.sourcefile, env.tree);
+ lintMapper.calculateLints(env.toplevel.sourcefile, env.tree, env.toplevel.endPositions);
}
public void attribPackage(DiagnosticPosition pos, PackageSymbol p) {