Skip to content

Commit f4abb32

Browse files
committed
Implemented Violations to upperEll recipe
1 parent 76f932b commit f4abb32

File tree

5 files changed

+253
-14
lines changed

5 files changed

+253
-14
lines changed

config/import-control-test.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@
1111
<allow pkg="java.util"/>
1212
<allow pkg="java.nio"/>
1313
<allow pkg="java.lang"/>
14+
<allow pkg="javax.xml.stream"/>
1415
</import-control>

src/main/java/org/checkstyle/autofix/recipe/UpperEllRecipe.java

Lines changed: 115 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,20 @@
1717

1818
package org.checkstyle.autofix.recipe;
1919

20+
import java.nio.file.Path;
21+
import java.util.ArrayList;
22+
import java.util.List;
23+
import java.util.Objects;
24+
import java.util.concurrent.CancellationException;
25+
import java.util.function.Function;
26+
27+
import org.checkstyle.autofix.parser.CheckstyleViolation;
28+
import org.openrewrite.Cursor;
2029
import org.openrewrite.ExecutionContext;
30+
import org.openrewrite.PrintOutputCapture;
2131
import org.openrewrite.Recipe;
2232
import org.openrewrite.TreeVisitor;
33+
import org.openrewrite.internal.RecipeRunException;
2334
import org.openrewrite.java.JavaIsoVisitor;
2435
import org.openrewrite.java.tree.J;
2536
import org.openrewrite.java.tree.JavaType;
@@ -30,6 +41,16 @@
3041
*/
3142
public class UpperEllRecipe extends Recipe {
3243

44+
private List<CheckstyleViolation> violations;
45+
46+
public UpperEllRecipe() {
47+
this.violations = new ArrayList<>();
48+
}
49+
50+
public UpperEllRecipe(List<CheckstyleViolation> violations) {
51+
this.violations = violations;
52+
}
53+
3354
@Override
3455
public String getDisplayName() {
3556
return "UpperEll recipe";
@@ -43,23 +64,110 @@ public String getDescription() {
4364

4465
@Override
4566
public TreeVisitor<?, ExecutionContext> getVisitor() {
46-
return new UpperEllVisitor();
67+
return new UpperEllVisitor(violations);
4768
}
4869

49-
/**
50-
* Visitor that replaces lowercase 'l' suffixes in long literals with uppercase 'L'.
51-
*/
5270
private static final class UpperEllVisitor extends JavaIsoVisitor<ExecutionContext> {
71+
72+
private final List<CheckstyleViolation> violations;
73+
private String currentFileName;
74+
75+
UpperEllVisitor(List<CheckstyleViolation> violations) {
76+
this.violations = violations;
77+
}
78+
79+
@Override
80+
public J.CompilationUnit visitCompilationUnit(J.CompilationUnit cu, ExecutionContext ctx) {
81+
this.currentFileName = cu.getSourcePath().toString();
82+
return super.visitCompilationUnit(cu, ctx);
83+
}
84+
5385
@Override
5486
public J.Literal visitLiteral(J.Literal literal, ExecutionContext ctx) {
5587
J.Literal result = super.visitLiteral(literal, ctx);
5688
final String valueSource = result.getValueSource();
5789

5890
if (valueSource != null && valueSource.endsWith("l")
59-
&& result.getType() == JavaType.Primitive.Long) {
91+
&& result.getType() == JavaType.Primitive.Long
92+
&& isAtViolationLocation(result)) {
93+
6094
final String numericPart = valueSource.substring(0, valueSource.length() - 1);
61-
final String newValueSource = numericPart + "L";
62-
result = result.withValueSource(newValueSource);
95+
result = result.withValueSource(numericPart + "L");
96+
}
97+
98+
return result;
99+
}
100+
101+
private boolean isAtViolationLocation(J.Literal literal) {
102+
final J.CompilationUnit cursor = Objects.requireNonNull(getCursor()
103+
.firstEnclosing(J.CompilationUnit.class));
104+
105+
final int line = computeLinePosition(cursor, literal, getCursor());
106+
final int column = computeColumnPosition(cursor, literal, getCursor());
107+
108+
return violations.stream().anyMatch(violation -> {
109+
return violation.getLine() == line
110+
&& violation.getColumn() == column
111+
&& Path.of(violation.getFileName()).equals(Path.of(currentFileName));
112+
});
113+
}
114+
115+
private int computePosition(
116+
J tree,
117+
J targetElement,
118+
Cursor cursor,
119+
Function<String, Integer> positionCalculator
120+
) {
121+
final TreeVisitor<?, PrintOutputCapture<TreeVisitor<?, ?>>> printer =
122+
tree.printer(cursor);
123+
124+
final PrintOutputCapture<TreeVisitor<?, ?>> capture =
125+
new PrintOutputCapture<>(printer) {
126+
@Override
127+
public PrintOutputCapture<TreeVisitor<?, ?>> append(String text) {
128+
if (targetElement.isScope(getContext().getCursor().getValue())) {
129+
throw new CancellationException();
130+
}
131+
return super.append(text);
132+
}
133+
};
134+
135+
final int result;
136+
try {
137+
printer.visit(tree, capture, cursor.getParentOrThrow());
138+
throw new IllegalStateException("Target element not found in tree");
139+
}
140+
catch (CancellationException ignored) {
141+
result = positionCalculator.apply(capture.getOut());
142+
}
143+
catch (RecipeRunException exception) {
144+
if (exception.getCause() instanceof CancellationException) {
145+
result = positionCalculator.apply(capture.getOut());
146+
}
147+
else {
148+
throw exception;
149+
}
150+
}
151+
return result;
152+
}
153+
154+
private int computeLinePosition(J tree, J targetElement, Cursor cursor) {
155+
return computePosition(tree, targetElement, cursor,
156+
out -> 1 + (int) out.chars().filter(chr -> chr == '\n').count());
157+
}
158+
159+
private int computeColumnPosition(J tree, J targetElement, Cursor cursor) {
160+
return computePosition(tree, targetElement, cursor, this::calculateColumnOffset);
161+
}
162+
163+
private int calculateColumnOffset(String out) {
164+
final int lineBreakIndex = out.lastIndexOf('\n');
165+
final int result;
166+
if (lineBreakIndex == -1) {
167+
result = out.length();
168+
}
169+
else {
170+
result = out.length() - lineBreakIndex;
63171
}
64172
return result;
65173
}

src/test/java/org/checkstyle/autofix/recipe/AbstractRecipeTest.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import java.nio.file.Files;
2525
import java.nio.file.Paths;
2626

27+
import javax.xml.stream.XMLStreamException;
28+
2729
import org.checkstyle.autofix.ClassRenameRecipe;
2830
import org.openrewrite.Recipe;
2931
import org.openrewrite.test.RewriteTest;
@@ -53,7 +55,7 @@ private Recipe createPreprocessingRecipe() {
5355
*
5456
* @return the main recipe to test
5557
*/
56-
protected abstract Recipe getRecipe();
58+
protected abstract Recipe getRecipe() throws XMLStreamException, IOException;
5759

5860
/**
5961
* Tests a recipe with the given recipe path and test case name.
@@ -67,7 +69,8 @@ private Recipe createPreprocessingRecipe() {
6769
* @param testCaseName the name of the test case (should match directory and file names)
6870
* @throws IOException if files cannot be read
6971
*/
70-
protected void testRecipe(String recipePath, String testCaseName) throws IOException {
72+
protected void testRecipe(String recipePath, String testCaseName)
73+
throws IOException, XMLStreamException {
7174
final String testCaseDir = testCaseName.toLowerCase();
7275
final String inputFileName = "Input" + testCaseName + ".java";
7376
final String outputFileName = "Output" + testCaseName + ".java";

src/test/java/org/checkstyle/autofix/recipe/UpperEllRecipeTest.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,29 +18,40 @@
1818
package org.checkstyle.autofix.recipe;
1919

2020
import java.io.IOException;
21+
import java.nio.file.Path;
22+
import java.util.List;
2123

24+
import javax.xml.stream.XMLStreamException;
25+
26+
import org.checkstyle.autofix.parser.CheckstyleReportsParser;
27+
import org.checkstyle.autofix.parser.CheckstyleViolation;
2228
import org.junit.jupiter.api.Test;
2329
import org.openrewrite.Recipe;
2430

2531
public class UpperEllRecipeTest extends AbstractRecipeTest {
2632

2733
@Override
28-
protected Recipe getRecipe() {
29-
return new UpperEllRecipe();
34+
protected Recipe getRecipe() throws XMLStreamException, IOException {
35+
final String reportPath = "src/test/resources/org/checkstyle/autofix/recipe/upperell"
36+
+ "/report.xml";
37+
38+
final List<CheckstyleViolation> violations =
39+
CheckstyleReportsParser.parse(Path.of(reportPath));
40+
return new UpperEllRecipe(violations);
3041
}
3142

3243
@Test
33-
void hexOctalLiteralTest() throws IOException {
44+
void hexOctalLiteralTest() throws IOException, XMLStreamException {
3445
testRecipe("upperell", "HexOctalLiteral");
3546
}
3647

3748
@Test
38-
void complexLongLiterals() throws IOException {
49+
void complexLongLiterals() throws IOException, XMLStreamException {
3950
testRecipe("upperell", "ComplexLongLiterals");
4051
}
4152

4253
@Test
43-
void stringAndCommentTest() throws IOException {
54+
void stringAndCommentTest() throws IOException, XMLStreamException {
4455
testRecipe("upperell", "StringAndComments");
4556
}
4657
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<checkstyle version="10.12.3">
3+
<file name="org/checkstyle/autofix/recipe/upperell/stringandcomments/InputStringAndComments.java">
4+
<error line="11" column="30" severity="error"
5+
message="Use uppercase 'L' for long literals."
6+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
7+
<error line="18" column="21" severity="error"
8+
message="Use uppercase 'L' for long literals."
9+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
10+
</file>
11+
12+
<file name="org/checkstyle/autofix/recipe/upperell/hexoctalliteral/InputHexOctalLiteral.java">
13+
<error line="4" column="28" severity="error"
14+
message="Use uppercase 'L' for long literals."
15+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
16+
<error line="5" column="32" severity="error"
17+
message="Use uppercase 'L' for long literals."
18+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
19+
<error line="6" column="29" severity="error"
20+
message="Use uppercase 'L' for long literals."
21+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
22+
<error line="7" column="30" severity="error"
23+
message="Use uppercase 'L' for long literals."
24+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
25+
<error line="8" column="31" severity="error"
26+
message="Use uppercase 'L' for long literals."
27+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
28+
<error line="11" column="25" severity="error"
29+
message="Use uppercase 'L' for long literals."
30+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
31+
<error line="12" column="27" severity="error"
32+
message="Use uppercase 'L' for long literals."
33+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
34+
<error line="13" column="28" severity="error"
35+
message="Use uppercase 'L' for long literals."
36+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
37+
</file>
38+
39+
<file name="org/checkstyle/autofix/recipe/upperell/complexlongliterals/InputComplexLongLiterals.java">
40+
<error line="4" column="35" severity="error"
41+
message="Use uppercase 'L' for long literals."
42+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
43+
<error line="5" column="39" severity="error"
44+
message="Use uppercase 'L' for long literals."
45+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
46+
<error line="7" column="27" severity="error"
47+
message="Use uppercase 'L' for long literals."
48+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
49+
<error line="8" column="27" severity="error"
50+
message="Use uppercase 'L' for long literals."
51+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
52+
<error line="11" column="30" severity="error"
53+
message="Use uppercase 'L' for long literals."
54+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
55+
<error line="12" column="32" severity="error"
56+
message="Use uppercase 'L' for long literals."
57+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
58+
<error line="13" column="34" severity="error"
59+
message="Use uppercase 'L' for long literals."
60+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
61+
<error line="14" column="25" severity="error"
62+
message="Use uppercase 'L' for long literals."
63+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
64+
<error line="15" column="25" severity="error"
65+
message="Use uppercase 'L' for long literals."
66+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
67+
<error line="18" column="33" severity="error"
68+
message="Use uppercase 'L' for long literals."
69+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
70+
<error line="22" column="57" severity="error"
71+
message="Use uppercase 'L' for long literals."
72+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
73+
<error line="23" column="33" severity="error"
74+
message="Use uppercase 'L' for long literals."
75+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
76+
<error line="23" column="36" severity="error"
77+
message="Use uppercase 'L' for long literals."
78+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
79+
<error line="23" column="40" severity="error"
80+
message="Use uppercase 'L' for long literals."
81+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
82+
<error line="27" column="40" severity="error"
83+
message="Use uppercase 'L' for long literals."
84+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
85+
<error line="27" column="45" severity="error"
86+
message="Use uppercase 'L' for long literals."
87+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
88+
<error line="27" column="51" severity="error"
89+
message="Use uppercase 'L' for long literals."
90+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
91+
<error line="32" column="17" severity="error"
92+
message="Use uppercase 'L' for long literals."
93+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
94+
<error line="33" column="31" severity="error"
95+
message="Use uppercase 'L' for long literals."
96+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
97+
<error line="34" column="27" severity="error"
98+
message="Use uppercase 'L' for long literals."
99+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
100+
<error line="36" column="45" severity="error"
101+
message="Use uppercase 'L' for long literals."
102+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
103+
<error line="37" column="41" severity="error"
104+
message="Use uppercase 'L' for long literals."
105+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
106+
<error line="38" column="33" severity="error"
107+
message="Use uppercase 'L' for long literals."
108+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
109+
<error line="43" column="19" severity="error"
110+
message="Use uppercase 'L' for long literals."
111+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
112+
<error line="45" column="23" severity="error"
113+
message="Use uppercase 'L' for long literals."
114+
source="com.puppycrawl.tools.checkstyle.checks.coding.UpperEllCheck"/>
115+
</file>
116+
</checkstyle>

0 commit comments

Comments
 (0)