Skip to content

Fix for reformatting issue with unnamed vars GH9255#9258

Open
neilcsmith-net wants to merge 1 commit intoapache:masterfrom
neilcsmith-net:gh9255
Open

Fix for reformatting issue with unnamed vars GH9255#9258
neilcsmith-net wants to merge 1 commit intoapache:masterfrom
neilcsmith-net:gh9255

Conversation

@neilcsmith-net
Copy link
Member

@neilcsmith-net neilcsmith-net commented Mar 11, 2026

Update JavaLexer to return token type of VAR when followed by underscore as in var _. Fixes formatter issues seen in #9255 Also ensures correct token colouring for this usage.

@neilcsmith-net neilcsmith-net requested a review from ebarboni March 11, 2026 11:14
@neilcsmith-net neilcsmith-net added Java [ci] enable extra Java tests (java.completion, java.source.base, java.hints, refactoring.java, form) ci:dev-build [ci] produce a dev-build zip artifact (7 days expiration, see link on workflow summary page) labels Mar 11, 2026
@neilcsmith-net neilcsmith-net marked this pull request as draft March 11, 2026 11:14
@neilcsmith-net
Copy link
Member Author

OK, difference in test behaviour was due to the incorrect way of setting the source level copied from other tests. Updated all. Test now fails in same way as IDE without this change.

Update JavaLexer to generate correct token type for `var _`.
Add lexer and formatting tests.
@neilcsmith-net neilcsmith-net marked this pull request as ready for review March 11, 2026 12:30
@neilcsmith-net neilcsmith-net changed the title WIP : Fix for reformatting issue with unnamed vars GH9255 Fix for reformatting issue with unnamed vars GH9255 Mar 11, 2026
@neilcsmith-net neilcsmith-net requested a review from mbien March 11, 2026 12:37
Comment on lines 1181 to 1204
if ((c = nextChar()) == 'r') {
c = nextChar();
// Check whether the given char is non-ident and if so then return keyword
if (c != EOF && !Character.isJavaIdentifierPart(c = translateSurrogates(c)) &&
version >= 10) {
// For surrogate 2 chars must be backed up
backup((c >= Character.MIN_SUPPLEMENTARY_CODE_POINT) ? 2 : 1);

int len = input.readLength();

Token next = nextToken();
boolean varKeyword = false;

if (AFTER_VAR_TOKENS.contains(next.id())) {
do {
next = nextToken();
} while (next != null && AFTER_VAR_TOKENS.contains(next.id()));

varKeyword = next != null && next.id() == JavaTokenId.IDENTIFIER;
varKeyword = next != null
&& (next.id() == JavaTokenId.IDENTIFIER
|| next.id() == JavaTokenId.UNDERSCORE);
}

input.backup(input.readLengthEOF()- len);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just an observation and not intended to stop this:

This whole code is problematic. Its existence breaks JShell support for var. The nested language infrastructure breaks when backtracking is used in this manner. I suspect the issue here is that this is not just backtracking, but backtracking over token boundaries.

You can test this by opening "Tools" -> "Open Java Platform Shell", input var s = "String"; and try to let that be evaluated. "Enter" is not accepted and you can observe exception on command line.

With the backtracking code removed (see: matthiasblaesing@0f4f15c (first commit of https://github.com/matthiasblaesing/netbeans/commits/jshell_lexer2/ and inspired by @lahodaj approach in a different PR) execution is at least done (there are still problems there).

Copy link
Member Author

@neilcsmith-net neilcsmith-net Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense (not that I use the JShell support, so hadn't noticed). This ended up being a minimal fix after a long trawl into the reformatter. I didn't really look further at the lexer.

I note that your linked commit shows the same issue in TreeUtilities::isVarType and Reformatter::isVarIdentifier ?

I wonder if it would make sense or be less problematic to always return a var token type, and then check whether it's valid in circumstances where that's necessary?


//check no change then formatted
reformat(doc, golden, golden);
reformat(doc, content, golden);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe reformat shoud reformat twice,because any reformat in this file should converge to same golden

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what you mean? But the tests are isolated and don't (shouldn't) affect each other. The entire contents of doc is set to the second String parameter, reformatted, and tested against the third String parameter.

The first check is there to make sure golden does not change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exactly ensure golden is golden but for every use of reformat in the test.
More for the future of course (because it break 2 tests):

private void reformat(Document doc, String content, String golden) throws Exception {
        reformat(doc, golden, golden, 0, golden.length());
        reformat(doc, content, golden, 0, content.length());
    }

Tested for fun (only 2 golden not golden),
test135210 generate javadoc line
testJavadoc reformat is in 2 step

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes, OK, that would make a lot of sense!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:dev-build [ci] produce a dev-build zip artifact (7 days expiration, see link on workflow summary page) Java [ci] enable extra Java tests (java.completion, java.source.base, java.hints, refactoring.java, form)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants