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 b15ddae02e1dc..06caa70d478a6 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 @@ -25,18 +25,14 @@ package com.sun.tools.javac.code; -import java.util.ArrayList; -import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.function.Consumer; -import java.util.stream.Stream; -import javax.tools.DiagnosticListener; import javax.tools.JavaFileObject; import com.sun.tools.javac.tree.EndPosTable; @@ -126,9 +122,10 @@ public boolean isKnown(JavaFileObject sourceFile) { */ public Optional lintAt(JavaFileObject sourceFile, DiagnosticPosition pos) { initializeIfNeeded(); - return Optional.of(sourceFile) - .map(fileInfoMap::get) - .flatMap(fileInfo -> fileInfo.lintAt(pos)); + FileInfo fileInfo = fileInfoMap.get(sourceFile); + if (fileInfo != null) + return fileInfo.lintAt(pos); + return Optional.empty(); } /** @@ -180,15 +177,15 @@ public void finishParsingFile(JCCompilationUnit tree) { private static class FileInfo { final LintRange rootRange; // the root LintRange (covering the entire source file) - final List unmappedDecls = new ArrayList<>(); // unmapped top-level declarations awaiting attribution + final List unmappedDecls = new LinkedList<>(); // unmapped top-level declarations awaiting attribution // After parsing: Add top-level declarations to our "unmappedDecls" list FileInfo(Lint rootLint, JCCompilationUnit tree) { rootRange = new LintRange(rootLint); - tree.defs.stream() - .filter(this::isTopLevelDecl) - .map(decl -> new Span(decl, tree.endPositions)) - .forEach(unmappedDecls::add); + for (JCTree decl : tree.defs) { + if (isTopLevelDecl(decl)) + unmappedDecls.add(new Span(decl, tree.endPositions)); + } } // After attribution: Discard the span from "unmappedDecls" and populate the declaration's subtree under "rootRange" @@ -205,8 +202,11 @@ void afterAttr(JCTree tree, EndPosTable endPositions) { // 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(span -> span.contains(pos)); - return mapped ? Optional.of(rootRange.bestMatch(pos).lint) : Optional.empty(); + for (Span span : unmappedDecls) { + if (span.contains(pos)) + return Optional.empty(); + } + return Optional.of(rootRange.bestMatch(pos).lint); } boolean isTopLevelDecl(JCTree tree) { @@ -252,21 +252,27 @@ private record LintRange( // Create a node representing the entire file, using the root lint configuration LintRange(Lint rootLint) { - this(Span.MAXIMAL, rootLint, new ArrayList<>()); + this(Span.MAXIMAL, rootLint, new LinkedList<>()); } // Create a node representing the given declaration and its corresponding Lint configuration LintRange(JCTree tree, EndPosTable endPositions, Lint lint) { - this(new Span(tree, endPositions), lint, new ArrayList<>()); + this(new Span(tree, endPositions), lint, new LinkedList<>()); } // 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); + LintRange bestMatch = null; + for (LintRange child : children) { + if (!child.span.contains(pos)) // don't recurse unless necessary + continue; + LintRange childBestMatch = child.bestMatch(pos); + if (childBestMatch != null && (bestMatch == null || bestMatch.span.contains(childBestMatch.span))) + bestMatch = childBestMatch; + } + if (bestMatch == null) + bestMatch = span.contains(pos) ? this : null; + return bestMatch; } // Populate a sparse subtree corresponding to the given nested declaration. diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java index 95458f339a151..14a077437b4fe 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java @@ -142,6 +142,16 @@ public final void report(JCDiagnostic diag) { if (category != null) { // this is a lint warning; find the applicable Lint DiagnosticPosition pos = diag.getDiagnosticPosition(); if (pos != null && category.annotationSuppression) { // we should apply the Lint from the warning's position + + // Optimization: We don't need to go through the trouble of calculating the Lint instance at "pos" if + // (a) "category" is disabled at the root level, and (b) the diagnostic doesn't have the DEFAULT_ENABLED + // flag: @SuppressWarnings can only disable lint categories, so "category" is disabled in the entire file. + if (!rootLint().isEnabled(category) && + !diag.isFlagSet(DEFAULT_ENABLED) && + !diag.getCode().equals(RequiresTransitiveAutomatic.key())) // accommodate the "requires" hack below + return; + + // Wait for the Lint instance at "pos" to be calculated, then proceed if ((lint = lintFor(diag)) == null) { addLintWaiter(currentSourceFile(), diag); // ...but we don't know it yet, so defer return;