Skip to content

Commit 26816cf

Browse files
committed
Implemented Violations to upperEll recipe
1 parent c909a05 commit 26816cf

File tree

9 files changed

+260
-30
lines changed

9 files changed

+260
-30
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/UpperEll.java

Lines changed: 112 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,19 @@
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.concurrent.CancellationException;
24+
import java.util.function.Function;
25+
26+
import org.checkstyle.autofix.parser.CheckstyleViolation;
27+
import org.openrewrite.Cursor;
2028
import org.openrewrite.ExecutionContext;
29+
import org.openrewrite.PrintOutputCapture;
2130
import org.openrewrite.Recipe;
2231
import org.openrewrite.TreeVisitor;
32+
import org.openrewrite.internal.RecipeRunException;
2333
import org.openrewrite.java.JavaIsoVisitor;
2434
import org.openrewrite.java.tree.J;
2535
import org.openrewrite.java.tree.JavaType;
@@ -30,6 +40,16 @@
3040
*/
3141
public class UpperEll extends Recipe {
3242

43+
private List<CheckstyleViolation> violations;
44+
45+
public UpperEll() {
46+
this.violations = new ArrayList<>();
47+
}
48+
49+
public UpperEll(List<CheckstyleViolation> violations) {
50+
this.violations = violations;
51+
}
52+
3353
@Override
3454
public String getDisplayName() {
3555
return "UpperEll recipe";
@@ -43,23 +63,108 @@ public String getDescription() {
4363

4464
@Override
4565
public TreeVisitor<?, ExecutionContext> getVisitor() {
46-
return new UpperEllVisitor();
66+
return new UpperEllVisitor(violations);
4767
}
4868

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

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

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.InputClassRenamer;
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/UpperEllTest.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 UpperEllTest extends AbstractRecipeTest {
2632

2733
@Override
28-
protected Recipe getRecipe() {
29-
return new UpperEll();
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 UpperEll(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
}

src/test/resources/org/checkstyle/autofix/recipe/upperell/complexlongliterals/InputComplexLongLiterals.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ public class InputComplexLongLiterals {
1111
private Long simpleLong = 1234l;
1212
private Long negativeLong = -5678l;
1313
private Long underscoreLong = 1_000_000l;
14-
Long maxLongObject = 9223372036854775807l;
15-
Long minLongObject = -9223372036854775808l;
14+
Long maxLongObject = 9223372036854775807l; //suppressed violation
15+
Long minLongObject = -9223372036854775808l; //suppressed violation
1616

1717
public long calculate(long input1, long input2) {
1818
return input1 + input2 + 1000l;

src/test/resources/org/checkstyle/autofix/recipe/upperell/complexlongliterals/OutputComplexLongLiterals.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ public class OutputComplexLongLiterals {
1111
private Long simpleLong = 1234L;
1212
private Long negativeLong = -5678L;
1313
private Long underscoreLong = 1_000_000L;
14-
Long maxLongObject = 9223372036854775807L;
15-
Long minLongObject = -9223372036854775808L;
14+
Long maxLongObject = 9223372036854775807l; //suppressed violation
15+
Long minLongObject = -9223372036854775808l; //suppressed violation
1616

1717
public long calculate(long input1, long input2) {
1818
return input1 + input2 + 1000L;

src/test/resources/org/checkstyle/autofix/recipe/upperell/hexoctalliteral/InputHexOctalLiteral.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
public class InputHexOctalLiteral {
44
private long hexLower = 0x1ABCl;
5-
private long hexUpper = 0X2DEFl;
6-
private long octal = 0777l;
7-
private long binary = 0b1010l;
8-
private long decimal = 12345l;
5+
private long hexUpper = 0X2DEFl;
6+
private long octal = 0777l;
7+
private long binary = 0b1010l;
8+
private long decimal = 12345l;
99

1010
public void calculateValues() {
11-
long hexResult = 0xDEADBEEFl;
12-
long octalResult = 01234l;
11+
long hexResult = 0xDEADBEEFl + 0xDEADBEFl; //suppressed violation for 0xDEADBEFl
12+
long octalResult = 01234l + 0xDEADBEEFl; //suppressed violation for 0xDEADBEFl
1313
long binaryResult = 0b11110000l;
1414
}
1515
}

src/test/resources/org/checkstyle/autofix/recipe/upperell/hexoctalliteral/OutputHexOctalLiteral.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
public class OutputHexOctalLiteral {
44
private long hexLower = 0x1ABCL;
5-
private long hexUpper = 0X2DEFL;
6-
private long octal = 0777L;
7-
private long binary = 0b1010L;
8-
private long decimal = 12345L;
5+
private long hexUpper = 0X2DEFL;
6+
private long octal = 0777L;
7+
private long binary = 0b1010L;
8+
private long decimal = 12345L;
99

1010
public void calculateValues() {
11-
long hexResult = 0xDEADBEEFL;
12-
long octalResult = 01234L;
11+
long hexResult = 0xDEADBEEFL + 0xDEADBEFl; //suppressed violation for 0xDEADBEFl
12+
long octalResult = 01234L + 0xDEADBEEFl; //suppressed violation for 0xDEADBEFl
1313
long binaryResult = 0b11110000L;
1414
}
1515
}

0 commit comments

Comments
 (0)