Skip to content

Commit 04f07e9

Browse files
committed
TreeUtilities: fix record span computation
ErrorDescriptionFactory can now compute spans for record declarations. This allows hints like Unused to correctly highlight hints on records. TreeUtilities: use compact Collections and minor cleanup.
1 parent d0afe36 commit 04f07e9

File tree

2 files changed

+92
-55
lines changed

2 files changed

+92
-55
lines changed

java/java.source.base/src/org/netbeans/api/java/source/TreeUtilities.java

Lines changed: 90 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@
7979
import com.sun.tools.javac.tree.JCTree.JCExpression;
8080
import com.sun.tools.javac.tree.JCTree.JCLambda;
8181
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
82-
import com.sun.tools.javac.tree.JCTree.Tag;
8382
import com.sun.tools.javac.util.JCDiagnostic;
8483
import com.sun.tools.javac.util.Log;
8584
import java.lang.reflect.Method;
@@ -89,6 +88,7 @@
8988
import org.netbeans.api.java.lexer.JavaTokenId;
9089
import org.netbeans.api.java.lexer.JavadocTokenId;
9190
import org.netbeans.api.java.source.JavaSource.Phase;
91+
import org.netbeans.api.lexer.Token;
9292
import org.netbeans.api.lexer.TokenSequence;
9393
import org.netbeans.lib.nbjavac.services.NBAttr;
9494
import org.netbeans.lib.nbjavac.services.NBResolve;
@@ -108,11 +108,42 @@ public final class TreeUtilities {
108108

109109
private static final Logger LOG = Logger.getLogger(TreeUtilities.class.getName());
110110

111-
/**{@link Kind}s that are represented by {@link ClassTree}.
111+
/**
112+
* {@link Kind}s that are represented by {@link ClassTree}.
112113
*
113114
* @since 0.67
114115
*/
115-
public static final Set<Kind> CLASS_TREE_KINDS = EnumSet.of(Kind.ANNOTATION_TYPE, Kind.CLASS, Kind.ENUM, Kind.INTERFACE, Kind.RECORD);
116+
public static final Set<Kind> CLASS_TREE_KINDS = Collections.unmodifiableSet(EnumSet.of(
117+
Kind.ANNOTATION_TYPE,
118+
Kind.CLASS,
119+
Kind.ENUM,
120+
Kind.INTERFACE,
121+
Kind.RECORD
122+
));
123+
124+
private static final Set<JavaTokenId> SPAN_COMMENT_TOKENS = EnumSet.of(
125+
JavaTokenId.DOT,
126+
JavaTokenId.WHITESPACE,
127+
JavaTokenId.BLOCK_COMMENT,
128+
JavaTokenId.LINE_COMMENT,
129+
JavaTokenId.JAVADOC_COMMENT
130+
);
131+
132+
private static final Set<JavaTokenId> SPAN_ClASS_TOKENS = EnumSet.of(
133+
JavaTokenId.CLASS,
134+
JavaTokenId.INTERFACE,
135+
JavaTokenId.ENUM,
136+
JavaTokenId.AT,
137+
JavaTokenId.WHITESPACE,
138+
JavaTokenId.BLOCK_COMMENT,
139+
JavaTokenId.LINE_COMMENT,
140+
JavaTokenId.JAVADOC_COMMENT
141+
);
142+
143+
private static final Set<String> SPAN_CLASS_IDENTIFIERS = Set.of(
144+
"record"
145+
);
146+
116147
private final CompilationInfo info;
117148
private final CommentHandlerService handler;
118149

@@ -379,6 +410,7 @@ public TreePath pathFor(TreePath path, int pos) {
379410
return pathFor(path, pos, info.getTrees().getSourcePositions());
380411
}
381412

413+
@SuppressWarnings("AssignmentToMethodParameter")
382414
public TreePath pathFor(TreePath path, int pos, SourcePositions sourcePositions) {
383415
if (info == null || path == null || sourcePositions == null)
384416
throw new IllegalArgumentException();
@@ -392,13 +424,14 @@ class Result extends Error {
392424

393425
class PathFinder extends ErrorAwareTreePathScanner<Void,Void> {
394426
private int pos;
395-
private SourcePositions sourcePositions;
427+
private final SourcePositions sourcePositions;
396428

397429
private PathFinder(int pos, SourcePositions sourcePositions) {
398430
this.pos = pos;
399431
this.sourcePositions = sourcePositions;
400432
}
401433

434+
@Override
402435
public Void scan(Tree tree, Void p) {
403436
if (tree != null) {
404437
CompilationUnitTree cut = getCurrentPath().getCompilationUnit();
@@ -585,14 +618,15 @@ class Result extends Error {
585618
}
586619

587620
class PathFinder extends DocTreePathScanner<Void,TreePath> {
588-
private int pos;
589-
private DocSourcePositions sourcePositions;
621+
private final int pos;
622+
private final DocSourcePositions sourcePositions;
590623

591624
private PathFinder(int pos, DocSourcePositions sourcePositions) {
592625
this.pos = pos;
593626
this.sourcePositions = sourcePositions;
594627
}
595628

629+
@Override
596630
public Void scan(DocTree tree, TreePath p) {
597631
if (tree != null) {
598632
if (sourcePositions.getStartPosition(p.getCompilationUnit(), getCurrentPath().getDocComment(), tree) < pos && sourcePositions.getEndPosition(p.getCompilationUnit(), getCurrentPath().getDocComment(), tree) >= pos) {
@@ -748,9 +782,9 @@ private static <T extends Tree> T doParse(JavacTaskImpl task, String text, Sourc
748782
CharBuffer buf = CharBuffer.wrap((text+"\u0000").toCharArray(), 0, text.length());
749783
ParserFactory factory = ParserFactory.instance(context);
750784
Parser parser = factory.newParser(buf, false, true, false, false);
751-
if (parser instanceof JavacParser) {
785+
if (parser instanceof JavacParser javacParser) {
752786
if (sourcePositions != null)
753-
sourcePositions[0] = new ParserSourcePositions((JavacParser)parser, offset);
787+
sourcePositions[0] = new ParserSourcePositions(javacParser, offset);
754788
return actualParse.apply(parser);
755789
}
756790
return null;
@@ -785,10 +819,12 @@ private ParserSourcePositions(JavacParser parser, int offset) {
785819
this.offset = offset;
786820
}
787821

822+
@Override
788823
public long getStartPosition(CompilationUnitTree file, Tree tree) {
789824
return parser.getStartPos((JCTree)tree) - offset;
790825
}
791826

827+
@Override
792828
public long getEndPosition(CompilationUnitTree file, Tree tree) {
793829
return parser.getEndPos((JCTree)tree) - offset;
794830
}
@@ -864,12 +900,12 @@ public Scope toScopeWithDisabledAccessibilityChecks(Scope scope) {
864900
}
865901

866902
private static Env<AttrContext> getEnv(Scope scope) {
867-
if (scope instanceof NBScope) {
868-
scope = ((NBScope) scope).delegate;
903+
if (scope instanceof NBScope nbScope) {
904+
scope = nbScope.delegate;
869905
}
870906

871-
if (scope instanceof HackScope) {
872-
return ((HackScope) scope).getEnv();
907+
if (scope instanceof HackScope hackScope) {
908+
return hackScope.getEnv();
873909
}
874910

875911
return ((JavacScope) scope).getEnv();
@@ -1142,7 +1178,7 @@ public int[] findBodySpan(ClassTree clazz) {
11421178
* @since 0.25
11431179
*/
11441180
public int[] findNameSpan(ClassTree clazz) {
1145-
return findNameSpan(clazz.getSimpleName().toString(), clazz, JavaTokenId.CLASS, JavaTokenId.INTERFACE, JavaTokenId.ENUM, JavaTokenId.AT, JavaTokenId.WHITESPACE, JavaTokenId.BLOCK_COMMENT, JavaTokenId.LINE_COMMENT, JavaTokenId.JAVADOC_COMMENT);
1181+
return findNameSpan(clazz.getSimpleName().toString(), clazz, SPAN_ClASS_TOKENS, SPAN_CLASS_IDENTIFIERS);
11461182
}
11471183

11481184
/**Find span of the {@link MethodTree#getName()} identifier in the source.
@@ -1297,7 +1333,7 @@ public int[] findNameSpan(ContinueTree cont) {
12971333
* @since 0.25
12981334
*/
12991335
public int[] findNameSpan(MemberSelectTree mst) {
1300-
return findNameSpan(mst.getIdentifier().toString(), mst, JavaTokenId.DOT, JavaTokenId.WHITESPACE, JavaTokenId.BLOCK_COMMENT, JavaTokenId.LINE_COMMENT, JavaTokenId.JAVADOC_COMMENT);
1336+
return findNameSpan(mst.getIdentifier().toString(), mst, SPAN_COMMENT_TOKENS, Set.of());
13011337
}
13021338

13031339
/**Find span of the {@link MemberReferenceTree#getName()} identifier in the source.
@@ -1310,7 +1346,7 @@ public int[] findNameSpan(MemberSelectTree mst) {
13101346
* @since 0.124
13111347
*/
13121348
public int[] findNameSpan(MemberReferenceTree mst) {
1313-
return findNameSpan(mst.getName().toString(), mst, JavaTokenId.DOT, JavaTokenId.WHITESPACE, JavaTokenId.BLOCK_COMMENT, JavaTokenId.LINE_COMMENT, JavaTokenId.JAVADOC_COMMENT);
1349+
return findNameSpan(mst.getName().toString(), mst, SPAN_COMMENT_TOKENS, Set.of());
13141350
}
13151351

13161352
/**Find span of the name in the DocTree's reference tree (see {@link #getReferenceName(com.sun.source.util.DocTreePath)}
@@ -1366,32 +1402,38 @@ public int[] findNameSpan(DocCommentTree docTree, ReferenceTree ref) {
13661402

13671403
return null;
13681404
}
1369-
1370-
private int[] findNameSpan(String name, Tree t, JavaTokenId... allowedTokens) {
1405+
1406+
private int[] findNameSpan(String name, Tree tree) {
1407+
return findNameSpan(name, tree, Set.of(), Set.of());
1408+
}
1409+
1410+
@SuppressWarnings("NestedAssignment")
1411+
private int[] findNameSpan(String name, Tree tree, Set<JavaTokenId> allowedTokens, Set<String> allowedIdentifiers) {
13711412
if (!SourceVersion.isIdentifier(name)) {
13721413
//names like "<error>", etc.
13731414
return null;
13741415
}
13751416

1376-
JCTree jcTree = (JCTree) t;
1417+
JCTree jcTree = (JCTree) tree;
13771418
int pos = jcTree.pos;
13781419

13791420
if (pos < 0)
13801421
return null;
13811422

1382-
Set<JavaTokenId> allowedTokensSet = EnumSet.noneOf(JavaTokenId.class);
1383-
1384-
allowedTokensSet.addAll(Arrays.asList(allowedTokens));
1385-
13861423
TokenSequence<JavaTokenId> tokenSequence = info.getTokenHierarchy().tokenSequence(JavaTokenId.language());
1387-
13881424
tokenSequence.move(pos);
13891425

13901426
boolean wasNext;
13911427

1392-
while ((wasNext = tokenSequence.moveNext()) && allowedTokensSet.contains(tokenSequence.token().id()))
1393-
;
1394-
1428+
while (wasNext = tokenSequence.moveNext()) {
1429+
Token<JavaTokenId> t = tokenSequence.token();
1430+
if (!allowedTokens.contains(t.id())
1431+
&& ((allowedIdentifiers.isEmpty() || t.id() != JavaTokenId.IDENTIFIER)
1432+
|| !allowedIdentifiers.contains(t.text().toString()))) {
1433+
break;
1434+
}
1435+
}
1436+
13951437
if (wasNext) {
13961438
if (tokenSequence.token().id() == JavaTokenId.IDENTIFIER) {
13971439
boolean nameMatches;
@@ -1620,33 +1662,24 @@ public StatementTree getBreakContinueTarget(TreePath breakOrContinue) throws Ill
16201662
}
16211663
}
16221664

1623-
static Set<Character> EXOTIC_ESCAPE = new HashSet<Character>(
1624-
Arrays.<Character>asList('!', '#', '$', '%', '&', '(', ')', '*', '+', ',', '-',
1625-
':', '=', '?', '@', '^', '_', '`', '{', '|', '}')
1665+
static final Set<Character> EXOTIC_ESCAPE = Set.of(
1666+
'!', '#', '$', '%', '&', '(', ')', '*', '+', ',', '-',
1667+
':', '=', '?', '@', '^', '_', '`', '{', '|', '}'
16261668
);
16271669

1628-
private static final Map<Character, Character> ESCAPE_UNENCODE;
1629-
private static final Map<Character, Character> ESCAPE_ENCODE;
1630-
1631-
static {
1632-
Map<Character, Character> unencode = new HashMap<Character, Character>();
1633-
1634-
unencode.put('n', '\n');
1635-
unencode.put('t', '\t');
1636-
unencode.put('b', '\b');
1637-
unencode.put('r', '\r');
1638-
1639-
ESCAPE_UNENCODE = Collections.unmodifiableMap(unencode);
1640-
1641-
Map<Character, Character> encode = new HashMap<Character, Character>();
1642-
1643-
encode.put('\n', 'n');
1644-
encode.put('\t', 't');
1645-
encode.put('\b', 'b');
1646-
encode.put('\r', 'r');
1670+
private static final Map<Character, Character> ESCAPE_UNENCODE = Map.of(
1671+
'n', '\n',
1672+
't', '\t',
1673+
'b', '\b',
1674+
'r', '\r'
1675+
);
16471676

1648-
ESCAPE_ENCODE = Collections.unmodifiableMap(encode);
1649-
}
1677+
private static final Map<Character, Character> ESCAPE_ENCODE = Map.of(
1678+
'\n', 'n',
1679+
'\t', 't',
1680+
'\b', 'b',
1681+
'\r', 'r'
1682+
);
16501683

16511684
/**Returns new tree based on {@code original}, such that each visited subtree
16521685
* that occurs as a key in {@code original2Translated} is replaced by the corresponding
@@ -1795,6 +1828,7 @@ private UncaughtExceptionsVisitor(final CompilationInfo info) {
17951828
this.info = info;
17961829
}
17971830

1831+
@Override
17981832
public Void visitMethodInvocation(MethodInvocationTree node, Set<TypeMirror> p) {
17991833
super.visitMethodInvocation(node, p);
18001834
Element el = info.getTrees().getElement(getCurrentPath());
@@ -1803,6 +1837,7 @@ public Void visitMethodInvocation(MethodInvocationTree node, Set<TypeMirror> p)
18031837
return null;
18041838
}
18051839

1840+
@Override
18061841
public Void visitNewClass(NewClassTree node, Set<TypeMirror> p) {
18071842
super.visitNewClass(node, p);
18081843
Element el = info.getTrees().getElement(getCurrentPath());
@@ -1811,6 +1846,7 @@ public Void visitNewClass(NewClassTree node, Set<TypeMirror> p) {
18111846
return null;
18121847
}
18131848

1849+
@Override
18141850
public Void visitThrow(ThrowTree node, Set<TypeMirror> p) {
18151851
super.visitThrow(node, p);
18161852
TypeMirror tm = info.getTrees().getTypeMirror(new TreePath(getCurrentPath(), node.getExpression()));
@@ -1823,6 +1859,7 @@ else if (tm.getKind() == TypeKind.UNION)
18231859
return null;
18241860
}
18251861

1862+
@Override
18261863
public Void visitTry(TryTree node, Set<TypeMirror> p) {
18271864
Set<TypeMirror> s = new LinkedHashSet<TypeMirror>();
18281865
Trees trees = info.getTrees();
@@ -1867,6 +1904,7 @@ public Void visitTry(TryTree node, Set<TypeMirror> p) {
18671904
return null;
18681905
}
18691906

1907+
@Override
18701908
public Void visitMethod(MethodTree node, Set<TypeMirror> p) {
18711909
Set<TypeMirror> s = new LinkedHashSet<TypeMirror>();
18721910
scan(node.getBody(), s);
@@ -1895,8 +1933,8 @@ public Void visitLambdaExpression(LambdaExpressionTree node, Set<TypeMirror> p)
18951933

18961934
private static class UnrelatedTypeMirrorSet extends AbstractSet<TypeMirror> {
18971935

1898-
private Types types;
1899-
private LinkedList<TypeMirror> list = new LinkedList<TypeMirror>();
1936+
private final Types types;
1937+
private final LinkedList<TypeMirror> list = new LinkedList<>();
19001938

19011939
public UnrelatedTypeMirrorSet(Types types) {
19021940
this.types = types;

java/spi.java.hints/src/org/netbeans/spi/java/hints/ErrorDescriptionFactory.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@
4949
import org.netbeans.api.annotations.common.NonNull;
5050
import org.netbeans.api.java.source.CompilationInfo;
5151
import org.netbeans.api.java.source.GeneratorUtilities;
52-
import org.netbeans.api.java.source.JavaSource;
53-
import org.netbeans.api.java.source.JavaSource.Phase;
5452
import org.netbeans.api.java.source.TreePathHandle;
5553
import org.netbeans.api.java.source.WorkingCopy;
5654
import org.netbeans.api.lexer.TokenSequence;
@@ -172,7 +170,7 @@ private static int[] computeNameSpan(Tree tree, HintContext context) {
172170
case METHOD -> {
173171
return info.getTreeUtilities().findNameSpan((MethodTree) tree);
174172
}
175-
case ANNOTATION_TYPE, CLASS, ENUM, INTERFACE -> {
173+
case ANNOTATION_TYPE, CLASS, ENUM, RECORD, INTERFACE -> {
176174
return info.getTreeUtilities().findNameSpan((ClassTree) tree);
177175
}
178176
case VARIABLE -> {
@@ -488,6 +486,7 @@ public String getText() {
488486
return NbBundle.getMessage(ErrorDescriptionFactory.class, "LBL_FIX_Suppress_Waning", keyNames.toString() ); // NOI18N
489487
}
490488

489+
@Override
491490
public void performRewrite(TransformationContext ctx) throws IOException {
492491
WorkingCopy copy = ctx.getWorkingCopy();
493492
TreePath path = ctx.getPath();

0 commit comments

Comments
 (0)