-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
[java] Fix #2996 - CommentSize/CommentContent suppression #4939
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
adangel
merged 14 commits into
pmd:main
from
oowekyala:issue2996-commentsize-suppression
Dec 17, 2024
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
463c4e4
Add utilities to locate node from text position
oowekyala efbbb45
Make token document store reference to AstInfo
oowekyala cd2b448
Add test
oowekyala 9430643
Try to wire this into RuleContext
oowekyala f8b069b
Make sure this works in CommentSize
oowekyala cd02335
Remove AstInfo from tokens
oowekyala fc477cb
Make NodeFindingUtil internal for now
oowekyala 5f9e4ab
Fix pmd violation
oowekyala 714d6c4
Merge branch 'master' into issue2996-commentsize-suppression
oowekyala 89cba9b
Make new API experimental
oowekyala a8ed6cd
Make comment owners contain textually their comment
oowekyala b161f91
Merge branch 'master' into issue2996-commentsize-suppression
oowekyala 2a7a80f
Add custom experimental tag in javadoc
oowekyala 6b58f0c
Merge branch 'main' into issue2996-commentsize-suppression
oowekyala File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
113 changes: 113 additions & 0 deletions
113
pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/internal/NodeFindingUtil.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
/* | ||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html | ||
*/ | ||
|
||
package net.sourceforge.pmd.lang.ast.internal; | ||
|
||
import java.util.Optional; | ||
|
||
import org.checkerframework.checker.nullness.qual.Nullable; | ||
|
||
import net.sourceforge.pmd.lang.ast.Node; | ||
import net.sourceforge.pmd.lang.document.TextRegion; | ||
|
||
/** | ||
* Utilities to find a node at specific text coordinates in a tree. | ||
*/ | ||
public final class NodeFindingUtil { | ||
|
||
private NodeFindingUtil() { | ||
// utility class | ||
} | ||
|
||
|
||
/** | ||
* Locates the innermost node in the subtree rooted in the given node | ||
* that contains the given offset. | ||
*/ | ||
public static Optional<Node> findNodeAt(Node root, int offset) { | ||
return Optional.ofNullable(findNodeImpl(root, offset)); | ||
} | ||
|
||
|
||
/** | ||
* Simple recursive search algo. Assumes that the regions of siblings | ||
* do not overlap and that parents contain regions of children entirely. | ||
* - We only have to explore one node at each level of the tree, and we quickly | ||
* hit the bottom (average depth of a Java AST ~20-25, with 6.x.x grammar). | ||
* - At each level, the next node to explore is chosen via binary search. | ||
*/ | ||
private static @Nullable Node findNodeImpl(Node subject, int offset) { | ||
// deepest node containing the target offset | ||
Node deepestNode = subject; | ||
if (!deepestNode.getTextRegion().contains(offset)) { | ||
return null; | ||
} | ||
while (true) { | ||
Node child = binarySearchInChildren(deepestNode, offset); | ||
if (child == null) { | ||
// no more specific child contains the node | ||
return deepestNode; | ||
} | ||
deepestNode = child; | ||
} | ||
} | ||
|
||
// returns the child of the [parent] that contains the target | ||
// it's assumed to be unique | ||
private static Node binarySearchInChildren(Node parent, int offset) { | ||
|
||
int low = 0; | ||
int high = parent.getNumChildren() - 1; | ||
|
||
while (low <= high) { | ||
int mid = (low + high) / 2; | ||
Node child = parent.getChild(mid); | ||
TextRegion childRegion = child.getTextRegion(); | ||
int cmp = Integer.compare(childRegion.getStartOffset(), offset); | ||
|
||
if (cmp < 0) { | ||
// node start is before target | ||
low = mid + 1; | ||
if (childRegion.getEndOffset() > offset) { | ||
// node end is after target | ||
return child; | ||
} | ||
} else if (cmp > 0) { | ||
high = mid - 1; | ||
} else { | ||
// target is node start position | ||
return child; // key found | ||
} | ||
} | ||
return null; // key not found | ||
} | ||
|
||
/** | ||
* Returns the innermost node that covers the entire given text range | ||
* in the given tree. | ||
* | ||
* @param root Root of the tree | ||
* @param range Range to find | ||
* @param exact If true, will return the *outermost* node whose range | ||
* is *exactly* the given text range, otherwise it may be larger. | ||
*/ | ||
public static Optional<Node> findNodeCovering(Node root, TextRegion range, boolean exact) { | ||
return findNodeAt(root, range.getStartOffset()).map(innermost -> { | ||
for (Node parent : innermost.ancestorsOrSelf()) { | ||
TextRegion parentRange = parent.getTextRegion(); | ||
if (!exact && parentRange.contains(range)) { | ||
return parent; | ||
} else if (exact && parentRange.equals(range)) { | ||
return parent; | ||
} else if (exact && parentRange.contains(range)) { | ||
// if it isn't the same, then we can't find better so better stop looking | ||
return null; | ||
} | ||
} | ||
return null; | ||
}); | ||
} | ||
|
||
|
||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
72 changes: 72 additions & 0 deletions
72
pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/internal/NodeFindingUtilTest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
/* | ||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html | ||
*/ | ||
|
||
package net.sourceforge.pmd.lang.ast.internal; | ||
|
||
import static org.hamcrest.MatcherAssert.assertThat; | ||
import static org.hamcrest.Matchers.equalTo; | ||
import static org.junit.jupiter.api.Assertions.assertFalse; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
import java.util.Optional; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
import net.sourceforge.pmd.lang.DummyLanguageModule; | ||
import net.sourceforge.pmd.lang.LanguageProcessor; | ||
import net.sourceforge.pmd.lang.LanguageProcessorRegistry; | ||
import net.sourceforge.pmd.lang.ast.DummyNode; | ||
import net.sourceforge.pmd.lang.ast.Node; | ||
import net.sourceforge.pmd.lang.ast.Parser; | ||
import net.sourceforge.pmd.lang.ast.RootNode; | ||
import net.sourceforge.pmd.lang.ast.SemanticErrorReporter; | ||
import net.sourceforge.pmd.lang.document.TextDocument; | ||
|
||
class NodeFindingUtilTest { | ||
|
||
@Test | ||
void testFindNode() { | ||
DummyNode.DummyRootNode root = parseLispish("(a(b)x(c))"); | ||
|
||
assertFinds("a", 1, root); | ||
assertFinds("b", 2, root); | ||
assertFinds("b", 3, root); | ||
assertFinds("b", 4, root); | ||
assertFinds("a", 5, root); | ||
assertFinds("c", 6, root); | ||
assertFinds("c", 7, root); | ||
assertFinds("c", 8, root); | ||
assertFinds("a", 9, root); | ||
assertDoesNotFind(10, root); | ||
} | ||
|
||
private static void assertDoesNotFind(int offset, DummyNode.DummyRootNode root) { | ||
assertFalse(NodeFindingUtil.findNodeAt(root, offset).isPresent()); | ||
} | ||
|
||
static void assertFinds(String nodeImage, int offset, Node root) { | ||
Optional<Node> found = NodeFindingUtil.findNodeAt(root, offset); | ||
|
||
assertTrue(found.isPresent(), "Node not found: " + nodeImage + " at offset " + offset); | ||
assertThat(found.get().getImage(), equalTo(nodeImage)); | ||
} | ||
|
||
static DummyNode.DummyRootNode parseLispish(String source) { | ||
|
||
DummyLanguageModule lang = DummyLanguageModule.getInstance(); | ||
try (LanguageProcessor processor = lang.createProcessor(lang.newPropertyBundle())) { | ||
Parser.ParserTask task = new Parser.ParserTask( | ||
TextDocument.readOnlyString(source, lang.getDefaultVersion()), | ||
SemanticErrorReporter.noop(), | ||
LanguageProcessorRegistry.singleton(processor) | ||
); | ||
RootNode root = processor.services().getParser().parse(task); | ||
|
||
return (DummyNode.DummyRootNode) root; | ||
} catch (Exception e) { | ||
throw new RuntimeException(e); | ||
} | ||
|
||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.