From 30ce46901ff03f2205b347ea4b957e978472f9c3 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 13 Aug 2024 11:17:38 +0100 Subject: [PATCH] Skip SpringLeadingWhitespaceCheck in text blocks Closes gh-421 --- .../check/SpringLeadingWhitespaceCheck.java | 53 ++++++++++++++++++- .../LeadingWhitespaceTabsAndTextBlock.txt | 1 + .../LeadingWhitespaceTabsAndTextBlock.java | 33 ++++++++++++ 3 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/LeadingWhitespaceTabsAndTextBlock.txt create mode 100644 spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceTabsAndTextBlock.java diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringLeadingWhitespaceCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringLeadingWhitespaceCheck.java index 188e6781..8e3fa83f 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringLeadingWhitespaceCheck.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringLeadingWhitespaceCheck.java @@ -17,7 +17,9 @@ package io.spring.javaformat.checkstyle.check; import java.io.File; +import java.util.ArrayDeque; import java.util.Collections; +import java.util.Deque; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; @@ -26,6 +28,7 @@ import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FileContents; import com.puppycrawl.tools.checkstyle.api.FileText; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; import io.spring.javaformat.config.IndentationStyle; import io.spring.javaformat.config.JavaFormatConfig; @@ -49,14 +52,32 @@ public class SpringLeadingWhitespaceCheck extends AbstractSpringCheck { private IndentationStyle indentationStyle; + private final Deque textBlockPairs = new ArrayDeque<>(); + @Override public int[] getAcceptableTokens() { - return NO_REQUIRED_TOKENS; + return new int[] { TokenTypes.TEXT_BLOCK_LITERAL_BEGIN, TokenTypes.TEXT_BLOCK_LITERAL_END }; + } + + @Override + public void visitToken(DetailAST ast) { + super.visitToken(ast); + if (ast.getType() == TokenTypes.TEXT_BLOCK_LITERAL_BEGIN) { + this.textBlockPairs.add(new TextBlockPair(ast)); + } + else if (ast.getType() == TokenTypes.TEXT_BLOCK_LITERAL_END) { + this.textBlockPairs.getLast().end(ast); + } } @Override public void beginTree(DetailAST rootAST) { super.beginTree(rootAST); + this.textBlockPairs.clear(); + } + + @Override + public void finishTree(DetailAST rootAST) { FileContents fileContents = getFileContents(); FileText fileText = fileContents.getText(); File file = fileText.getFile(); @@ -66,8 +87,11 @@ public void beginTree(DetailAST rootAST) { IndentationStyle indentationStyle = (this.indentationStyle != null) ? this.indentationStyle : JavaFormatConfig.findFrom(file.getParentFile()).getIndentationStyle(); for (int i = 0; i < fileText.size(); i++) { - String line = fileText.get(i); int lineNo = i + 1; + if (isInTextBlock(lineNo)) { + continue; + } + String line = fileText.get(i); Matcher matcher = PATTERN.matcher(line); boolean found = matcher.find(0); while (found @@ -78,6 +102,11 @@ public void beginTree(DetailAST rootAST) { log(lineNo, "leadingwhitespace.incorrect", indentationStyle.toString().toLowerCase()); } } + super.finishTree(rootAST); + } + + private boolean isInTextBlock(int lineNo) { + return this.textBlockPairs.stream().anyMatch((textBlockPair) -> textBlockPair.contains(lineNo)); } public void setIndentationStyle(String indentationStyle) { @@ -85,4 +114,24 @@ public void setIndentationStyle(String indentationStyle) { ? IndentationStyle.valueOf(indentationStyle.toUpperCase()) : null; } + private static class TextBlockPair { + + private final DetailAST begin; + + private DetailAST end; + + TextBlockPair(DetailAST begin) { + this.begin = begin; + } + + public boolean contains(int lineNo) { + return (lineNo > this.begin.getLineNo()) && (lineNo <= this.end.getLineNo()); + } + + void end(DetailAST end) { + this.end = end; + } + + } + } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/LeadingWhitespaceTabsAndTextBlock.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/LeadingWhitespaceTabsAndTextBlock.txt new file mode 100644 index 00000000..23435c7a --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/LeadingWhitespaceTabsAndTextBlock.txt @@ -0,0 +1 @@ ++0 errors diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceTabsAndTextBlock.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceTabsAndTextBlock.java new file mode 100644 index 00000000..e9e27b7b --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceTabsAndTextBlock.java @@ -0,0 +1,33 @@ +/* + * Copyright 2017-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Leading whitepace with a text block. + * + * @author Phillip Webb + */ +public class LeadingWhitespaceTabsAndTextBlock { + + /** + * Comments are ignored. + */ + public void hello() { + System.out.println("""" + Hello + World!"""); + } + +}