Skip to content

Add ASTHelpers.outermostParenthesized to find the context of a parenthesized expression - #6227

Open
vlsi wants to merge 1 commit into
google:masterfrom
vlsi:outermost-parenthesized
Open

vlsi wants to merge 1 commit into
google:masterfrom
vlsi:outermost-parenthesized

Conversation

@vlsi

@vlsi vlsi commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

A check that decides by the context of an expression reads the parent of its path, and when the expression is in redundant parentheses that parent is a ParenthesizedTree. ASTHelpers had stripParentheses for looking down into an expression and nothing for looking up out of the parentheses around it, so six places carried their own loop: TargetType.targetType, EqualsGetClass (makeAlwaysFalse and removeFromBinary), HashCodeInObjectsHash, RandomCast, and PatternMatchingInstanceof.isVariableAssignedFromCast. The last one is not in the issue's list; it walked the parent path with dropWhile(PARENTHESIZED). The change alters no finding.

outermostParenthesized(TreePath) returns the path to the outermost ParenthesizedTree in the chain that wraps the leaf, or the path itself when the leaf is not wrapped. It returns a path rather than the parent leaf: the returned leaf is a direct child of the parent, so a caller can find an argument position with getArguments().indexOf. The six loops now call it.

AssignmentExpression and BadInstanceof inspect only one level of parentheses and are left alone, because switching them changes their findings; #6218 and #5845 track that. PatternMatchingInstanceof.getUsage expands the usage by exactly one level on purpose.

Verification

ASTHelpersTest covers x, (x), and ((x)) as a call argument (all three give the same MethodInvocationTree and the argument itself as the leaf), a leaf whose grandparent but not parent is parenthesized, and the root path. The TargetType testdata gains a two-level parenthesized enhanced-for iterable. The tests of the changed checks already have parenthesized inputs at each changed site, and they pass.

check_api/pom.xml excludes ASTHelpersTest and TargetTypeTest from the Maven build, so I compiled and ran both by hand against core's test classpath: 70 tests pass. Each of three mutants of the helper fails a new test: a single if instead of the loop fails the call-argument test and TargetTypeTest, climbing to the last ParenthesizedTree among all ancestors fails the grandparent test, and dropping the null check fails the root-path test.

Fixes #6226

🤖 Generated with Claude Code

A check that decides by the context of an expression reads the parent
of its path, and when the expression is in redundant parentheses that
parent is a ParenthesizedTree. ASTHelpers had stripParentheses for
looking down into an expression and nothing for looking up out of the
parentheses around it, so six places carried their own loop:
TargetType.targetType, EqualsGetClass (makeAlwaysFalse and
removeFromBinary), HashCodeInObjectsHash, RandomCast, and
PatternMatchingInstanceof.isVariableAssignedFromCast. The change alters
no finding.

outermostParenthesized(TreePath) returns the path to the outermost
ParenthesizedTree in the chain that wraps the leaf, or the path itself
when the leaf is not wrapped. It returns a path rather than the parent
leaf: the returned leaf is a direct child of the parent, so a caller can
find an argument position with getArguments().indexOf. The six loops
now call it.

AssignmentExpression and BadInstanceof inspect only one level of
parentheses and are left alone, because switching them changes their
findings; google#6218 and google#5845 track that. PatternMatchingInstanceof.getUsage
expands the usage by exactly one level on purpose.

Fixes google#6226

Assisted-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

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

Labels

None yet

1 participant