Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 12 additions & 55 deletions src/main/java/org/checkstyle/autofix/recipe/Header.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,7 @@
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.checkstyle.autofix.parser.CheckConfiguration;
Expand All @@ -42,7 +38,6 @@
public class Header extends Recipe {
private static final String HEADER_PROPERTY = "header";
private static final String HEADER_FILE_PROPERTY = "headerFile";
private static final String IGNORE_LINES_PROPERTY = "ignoreLines";
private static final String CHARSET_PROPERTY = "charset";
private static final String LINE_SEPARATOR = "\n";

Expand All @@ -67,8 +62,7 @@ public String getDescription() {
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
final String licenseHeader = extractLicenseHeader(config);
final List<Integer> ignoreLines = extractIgnoreLines(config);
return new HeaderVisitor(violations, licenseHeader, ignoreLines);
return new HeaderVisitor(violations, licenseHeader);
}

private static String extractLicenseHeader(CheckConfiguration config) {
Expand All @@ -81,7 +75,7 @@ private static String extractLicenseHeader(CheckConfiguration config) {
.getPropertyOrDefault(CHARSET_PROPERTY, Charset.defaultCharset().name()));
final String headerFilePath = config.getProperty(HEADER_FILE_PROPERTY);
try {
header = Files.readString(Path.of(headerFilePath), charsetToUse);
header = toLfLineEnding(Files.readString(Path.of(headerFilePath), charsetToUse));
}
catch (IOException exception) {
throw new IllegalArgumentException("Failed to extract header from config",
Expand All @@ -91,29 +85,17 @@ private static String extractLicenseHeader(CheckConfiguration config) {
return header;
}

private static List<Integer> extractIgnoreLines(CheckConfiguration config) {
final List<Integer> ignoreLinesList;
if (config.hasProperty(IGNORE_LINES_PROPERTY)) {
ignoreLinesList = Arrays.stream(config.getIntArray(IGNORE_LINES_PROPERTY))
.boxed()
.toList();
}
else {
ignoreLinesList = new ArrayList<>();
}
return ignoreLinesList;
private static String toLfLineEnding(String text) {
return text.replaceAll("(?x)\\\\r(?=\\\\n)|\\r(?=\\n)", "");
}

private static class HeaderVisitor extends JavaIsoVisitor<ExecutionContext> {
private final List<CheckstyleViolation> violations;
private final String licenseHeader;
private final List<Integer> ignoreLines;

HeaderVisitor(List<CheckstyleViolation> violations, String licenseHeader,
List<Integer> ignoreLines) {
HeaderVisitor(List<CheckstyleViolation> violations, String licenseHeader) {
this.violations = violations;
this.licenseHeader = licenseHeader;
this.ignoreLines = ignoreLines;
}

@Override
Expand All @@ -126,11 +108,10 @@ public J visit(Tree tree, ExecutionContext ctx) {

if (hasViolation(filePath)) {
final String currentHeader = extractCurrentHeader(sourceFile);
final String fixedHeader = fixHeaderLines(licenseHeader,
currentHeader, ignoreLines);
final String fixedHeader = licenseHeader + LINE_SEPARATOR + currentHeader;

sourceFile = sourceFile.withPrefix(
Space.format(fixedHeader + LINE_SEPARATOR));
Space.format(fixedHeader));
}
result = super.visit(sourceFile, ctx);
}
Expand All @@ -139,35 +120,11 @@ public J visit(Tree tree, ExecutionContext ctx) {

private String extractCurrentHeader(JavaSourceFile sourceFile) {
return sourceFile.getComments().stream()
.map(comment -> comment.printComment(getCursor()))
.collect(Collectors.joining(System.lineSeparator()));
}

private static String fixHeaderLines(String licenseHeader,
String currentHeader, List<Integer> ignoreLines) {
final List<String> currentLines = Arrays
.stream(currentHeader.split(System.lineSeparator()))
.collect(Collectors.toList());
final List<String> licenseLines = Arrays.stream(licenseHeader.split(
System.lineSeparator(), -1)).toList();

final Set<Integer> ignoredLineNumbers = new HashSet<>(ignoreLines);

for (int lineNumber = 1; lineNumber <= licenseLines.size(); lineNumber++) {
final String expectedLine = licenseLines.get(lineNumber - 1);

if (lineNumber <= currentLines.size()) {
if (!ignoredLineNumbers.contains(lineNumber)
&& !expectedLine.equals(currentLines.get(lineNumber - 1))) {
currentLines.set(lineNumber - 1, expectedLine);
}
}
else {
currentLines.add(expectedLine);
}
}

return String.join(LINE_SEPARATOR, currentLines);
.map(comment -> {
return comment.printComment(getCursor())
+ toLfLineEnding(comment.getSuffix());
})
.collect(Collectors.joining(""));
}

private boolean hasViolation(Path filePath) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// Unit test for checkstyle-openrewrite-recipes.
// Dated: 11.07.25
// Dated: XX.XX.XX
// Copyright (C) 2025 Authors. Licensed under Apache 2.0.
// This file is part of the Checkstyle OpenRewrite test suite.
///////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////
Copy link
Collaborator

Choose a reason for hiding this comment

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

I am okay with the approach, but just always prepending sounds like we might miss some opportunities

if the input file has no header -> prepend
If the input file has a header and the number of lines mismatches config header -> prepend
if the input file has a header and the number of lines is the same -> override

Something that can be considered later

Copy link
Member

Choose a reason for hiding this comment

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

@Anmol202005 please create issue so we track it and refer to it. We don't have much data yet to decide what's the best way to handle this. Let's keep it as issue for later

Copy link
Member

Choose a reason for hiding this comment

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

@Anmol202005 please share a link to issue

// Unit test for checkstyle-openrewrite-recipes.
// Dated: 11.07.25
// Copyright (C) 2025 Authors. Licensed under Apache.
///////////////////////////////////////////////////////////////////////////////////////////////

package org.checkstyle.autofix.recipe.header.headercomments;

public class OutputHeaderComments {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// Unit test for checkstyle-openrewrite-recipes.
///////////////////////////////////////////////////////////////////////////////////////////////
// Dated: XX.XX.XX
// Copyright (C) 2025 Authors. Licensed under Apache 2.0.
// This file is part of the Checkstyle OpenRewrite test suite.
///////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////
// This is a test class
///////////////////////////////////////////////////////////////////////////////////////////////

package org.checkstyle.autofix.recipe.header.headerincorrect;

public class OutputHeaderIncorrect {
Expand Down
Loading