Skip to content

Commit ba28119

Browse files
committed
8348427: DeferredLintHandler API should use JCTree instead of DiagnosticPosition
Reviewed-by: mcimadamore
1 parent c5ac3c4 commit ba28119

File tree

9 files changed

+176
-160
lines changed

9 files changed

+176
-160
lines changed
Lines changed: 99 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -25,24 +25,42 @@
2525

2626
package com.sun.tools.javac.code;
2727

28+
import java.util.ArrayDeque;
29+
import java.util.ArrayList;
2830
import java.util.HashMap;
29-
import java.util.Map;
31+
import java.util.Optional;
32+
import java.util.function.Consumer;
3033

31-
import com.sun.tools.javac.tree.EndPosTable;
3234
import com.sun.tools.javac.tree.JCTree;
35+
import com.sun.tools.javac.tree.JCTree.Tag;
3336
import com.sun.tools.javac.util.Assert;
3437
import com.sun.tools.javac.util.Context;
35-
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
36-
import com.sun.tools.javac.util.ListBuffer;
3738

3839
/**
40+
* Holds pending {@link Lint} warnings until the {@lint Lint} instance associated with the containing
41+
* module, package, class, method, or variable declaration is known so that {@link @SupressWarnings}
42+
* suppressions may be applied.
43+
*
44+
* <p>
45+
* Warnings are regsistered at any time prior to attribution via {@link #report}. The warning will be
46+
* associated with the declaration placed in context by the most recent invocation of {@link #push push()}
47+
* not yet {@link #pop}'d. Warnings are actually emitted later, during attribution, via {@link #flush}.
48+
*
49+
* <p>
50+
* There is also an "immediate" mode, where warnings are emitted synchronously; see {@link #pushImmediate}.
51+
*
52+
* <p>
53+
* Deferred warnings are grouped by the innermost containing module, package, class, method, or variable
54+
* declaration (represented by {@link JCTree} nodes), so that the corresponding {@link Lint} configuration
55+
* can be applied when the warning is eventually generated.
3956
*
4057
* <p><b>This is NOT part of any supported API.
4158
* If you write code that depends on this, you do so at your own risk.
4259
* This code and its internal interfaces are subject to change or
4360
* deletion without notice.</b>
4461
*/
4562
public class DeferredLintHandler {
63+
4664
protected static final Context.Key<DeferredLintHandler> deferredLintHandlerKey = new Context.Key<>();
4765

4866
public static DeferredLintHandler instance(Context context) {
@@ -52,99 +70,107 @@ public static DeferredLintHandler instance(Context context) {
5270
return instance;
5371
}
5472

55-
/** The Lint to use when {@link #immediate(Lint)} is used,
56-
* instead of {@link #setPos(DiagnosticPosition)}. */
57-
private Lint immediateLint;
73+
/**
74+
* Registered {@link LintLogger}s grouped by the innermost containing module, package, class,
75+
* method, or variable declaration.
76+
*/
77+
private final HashMap<JCTree, ArrayList<LintLogger>> deferralMap = new HashMap<>();
78+
79+
/**
80+
* The current "reporter" stack, reflecting calls to {@link #push} and {@link #pop}.
81+
*
82+
* <p>
83+
* The top of the stack determines how calls to {@link #report} are handled.
84+
*/
85+
private final ArrayDeque<Consumer<LintLogger>> reporterStack = new ArrayDeque<>();
5886

5987
@SuppressWarnings("this-escape")
6088
protected DeferredLintHandler(Context context) {
6189
context.put(deferredLintHandlerKey, this);
62-
this.currentPos = IMMEDIATE_POSITION;
63-
immediateLint = Lint.instance(context);
90+
Lint rootLint = Lint.instance(context);
91+
pushImmediate(rootLint); // default to "immediate" mode
6492
}
6593

94+
// LintLogger
95+
6696
/**An interface for deferred lint reporting - loggers passed to
6797
* {@link #report(LintLogger) } will be called when
6898
* {@link #flush(DiagnosticPosition) } is invoked.
6999
*/
70100
public interface LintLogger {
101+
102+
/**
103+
* Generate a warning if appropriate.
104+
*
105+
* @param lint the applicable lint configuration
106+
*/
71107
void report(Lint lint);
72108
}
73109

74-
private DiagnosticPosition currentPos;
75-
private Map<DiagnosticPosition, ListBuffer<LintLogger>> loggersQueue = new HashMap<>();
110+
// Reporter Stack
76111

77-
/**Associate the given logger with the current position as set by {@link #setPos(DiagnosticPosition) }.
78-
* Will be invoked when {@link #flush(DiagnosticPosition) } will be invoked with the same position.
79-
* <br>
80-
* Will invoke the logger synchronously if {@link #immediate() } was called
81-
* instead of {@link #setPos(DiagnosticPosition) }.
112+
/**
113+
* Defer {@link #report}ed warnings until the given declaration is flushed.
114+
*
115+
* @param decl module, package, class, method, or variable declaration
116+
* @see #pop
82117
*/
83-
public void report(LintLogger logger) {
84-
if (currentPos == IMMEDIATE_POSITION) {
85-
logger.report(immediateLint);
86-
} else {
87-
ListBuffer<LintLogger> loggers = loggersQueue.get(currentPos);
88-
if (loggers == null) {
89-
loggersQueue.put(currentPos, loggers = new ListBuffer<>());
90-
}
91-
loggers.append(logger);
92-
}
118+
public void push(JCTree decl) {
119+
Assert.check(decl.getTag() == Tag.MODULEDEF
120+
|| decl.getTag() == Tag.PACKAGEDEF
121+
|| decl.getTag() == Tag.CLASSDEF
122+
|| decl.getTag() == Tag.METHODDEF
123+
|| decl.getTag() == Tag.VARDEF);
124+
reporterStack.push(logger -> deferralMap
125+
.computeIfAbsent(decl, s -> new ArrayList<>())
126+
.add(logger));
93127
}
94128

95-
/**Invoke all {@link LintLogger}s that were associated with the provided {@code pos}.
129+
/**
130+
* Enter "immediate" mode so that {@link #report}ed warnings are emitted synchonously.
131+
*
132+
* @param lint lint configuration to use for reported warnings
96133
*/
97-
public void flush(DiagnosticPosition pos, Lint lint) {
98-
ListBuffer<LintLogger> loggers = loggersQueue.get(pos);
99-
if (loggers != null) {
100-
for (LintLogger lintLogger : loggers) {
101-
lintLogger.report(lint);
102-
}
103-
loggersQueue.remove(pos);
104-
}
134+
public void pushImmediate(Lint lint) {
135+
reporterStack.push(logger -> logger.report(lint));
105136
}
106137

107-
/**Sets the current position to the provided {@code currentPos}. {@link LintLogger}s
108-
* passed to subsequent invocations of {@link #report(LintLogger) } will be associated
109-
* with the given position.
138+
/**
139+
* Revert to the previous configuration in effect prior to the most recent invocation
140+
* of {@link #push} or {@link #pushImmediate}.
141+
*
142+
* @see #pop
110143
*/
111-
public DiagnosticPosition setPos(DiagnosticPosition currentPos) {
112-
DiagnosticPosition prevPosition = this.currentPos;
113-
this.currentPos = currentPos;
114-
return prevPosition;
144+
public void pop() {
145+
Assert.check(reporterStack.size() > 1); // the bottom stack entry should never be popped
146+
reporterStack.pop();
115147
}
116148

117-
/**{@link LintLogger}s passed to subsequent invocations of
118-
* {@link #report(LintLogger) } will be invoked immediately.
149+
/**
150+
* Report a warning.
151+
*
152+
* <p>
153+
* In immediate mode, the warning is emitted synchronously. Otherwise, the warning is emitted later
154+
* when the current declaration is flushed.
119155
*/
120-
public DiagnosticPosition immediate(Lint lint) {
121-
immediateLint = lint;
122-
return setPos(IMMEDIATE_POSITION);
156+
public void report(LintLogger logger) {
157+
Assert.check(!reporterStack.isEmpty());
158+
reporterStack.peek().accept(logger);
123159
}
124160

125-
private static final DiagnosticPosition IMMEDIATE_POSITION = new DiagnosticPosition() {
126-
@Override
127-
public JCTree getTree() {
128-
Assert.error();
129-
return null;
130-
}
131-
132-
@Override
133-
public int getStartPosition() {
134-
Assert.error();
135-
return -1;
136-
}
137-
138-
@Override
139-
public int getPreferredPosition() {
140-
Assert.error();
141-
return -1;
142-
}
143-
144-
@Override
145-
public int getEndPosition(EndPosTable endPosTable) {
146-
Assert.error();
147-
return -1;
148-
}
149-
};
161+
// Warning Flush
162+
163+
/**
164+
* Emit deferred warnings encompassed by the given declaration.
165+
*
166+
* @param decl module, package, class, method, or variable declaration
167+
* @param lint lint configuration corresponding to {@code decl}
168+
*/
169+
public void flush(JCTree decl, Lint lint) {
170+
Optional.of(decl)
171+
.map(deferralMap::remove)
172+
.stream()
173+
.flatMap(ArrayList::stream)
174+
.forEach(logger -> logger.report(lint));
175+
}
150176
}

0 commit comments

Comments
 (0)