Skip to content

Commit

Permalink
Issue checkstyle#8179: Inability to use xpath for violation for Empty…
Browse files Browse the repository at this point in the history
…LineSeparator Check
  • Loading branch information
AkMo3 committed Mar 29, 2021
1 parent 4a1e256 commit 638661b
Show file tree
Hide file tree
Showing 19 changed files with 318 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -122,21 +122,38 @@ public void testFour() throws Exception {
moduleConfig.addAttribute("allowMultipleEmptyLines", "false");

final String[] expectedViolation = {
"12:5: " + getCheckMessage(EmptyLineSeparatorCheck.class,
EmptyLineSeparatorCheck.MSG_MULTIPLE_LINES_AFTER, "METHOD_DEF"),
"12:25: " + getCheckMessage(EmptyLineSeparatorCheck.class,
EmptyLineSeparatorCheck.MSG_MULTIPLE_LINES_AFTER, "}"),
};

final List<String> expectedXpathQueries = Arrays.asList(
final List<String> expectedXpathQueries = Collections.singletonList(
"/CLASS_DEF[./IDENT[@text='SuppressionXpathRegressionEmptyLineSeparator4']]"
+ "/OBJBLOCK/METHOD_DEF[./IDENT[@text='foo1']]",
+ "/OBJBLOCK/METHOD_DEF[./IDENT[@text='foo1']]/SLIST/RCURLY"
);

"/CLASS_DEF[./IDENT[@text='SuppressionXpathRegressionEmptyLineSeparator4']]"
+ "/OBJBLOCK/METHOD_DEF[./IDENT[@text='foo1']]"
+ "/MODIFIERS",
runVerifications(moduleConfig, fileToProcess, expectedViolation, expectedXpathQueries);
}

"/CLASS_DEF[./IDENT[@text='SuppressionXpathRegressionEmptyLineSeparator4']]"
+ "/OBJBLOCK/METHOD_DEF[./IDENT[@text='foo1']]"
+ "/MODIFIERS/LITERAL_PUBLIC"
@Test
public void testFive() throws Exception {
final File fileToProcess = new File(
getPath("SuppressionXpathRegressionEmptyLineSeparator5.java")
);

final DefaultConfiguration moduleConfig =
createModuleConfig(EmptyLineSeparatorCheck.class);
moduleConfig.addAttribute("allowMultipleEmptyLines", "false");
moduleConfig.addAttribute("allowMultipleEmptyLinesInsideClassMembers", "false");

final String[] expectedViolation = {
"14:15: " + getCheckMessage(EmptyLineSeparatorCheck.class,
EmptyLineSeparatorCheck.MSG_MULTIPLE_LINES_INSIDE),
};

final List<String> expectedXpathQueries = Collections.singletonList(
"/CLASS_DEF[./IDENT[@text='SuppressionXpathRegressionEmptyLineSeparator5']]"
+ "/OBJBLOCK/METHOD_DEF[./IDENT[@text='foo1']]/SLIST/LITERAL_TRY/SLIST"
+ "/SINGLE_LINE_COMMENT/COMMENT_CONTENT"
);

runVerifications(moduleConfig, fileToProcess, expectedViolation, expectedXpathQueries);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.checkstyle.suppressionxpathfilter.emptylineseparator;

import java.io.IOException;

public class SuppressionXpathRegressionEmptyLineSeparator5 {

int foo1() throws Exception {
int a = 1;
int b = 2;
try {
if (a != b) {
throw new IOException();
}
// warn


} catch(IOException e) {
return 1;
}
return 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,9 @@ private void checkToken(DetailAST ast, DetailAST nextToken) {
default:
if (nextToken.getType() == TokenTypes.RCURLY) {
if (hasNotAllowedTwoEmptyLinesBefore(nextToken)) {
log(ast, MSG_MULTIPLE_LINES_AFTER, ast.getText());
final DetailAST result = getLastElementBeforeEmptyLines(ast,
nextToken.getLineNo());
log(result, MSG_MULTIPLE_LINES_AFTER, result.getText());
}
}
else if (!hasEmptyLineAfter(ast)) {
Expand Down Expand Up @@ -477,12 +479,65 @@ private void processMultipleLinesInside(DetailAST ast) {
if (isClassMemberBlock(astType)) {
final List<Integer> emptyLines = getEmptyLines(ast);
final List<Integer> emptyLinesToLog = getEmptyLinesToLog(emptyLines);

for (Integer lineNo : emptyLinesToLog) {
// Checkstyle counts line numbers from 0 but IDE from 1
log(lineNo + 1, MSG_MULTIPLE_LINES_INSIDE);
log(getLastElementBeforeEmptyLines(ast, lineNo), MSG_MULTIPLE_LINES_INSIDE);
}
}
}

/**
* Returns the element after which empty lines exist.
*
* @param ast the ast to check.
* @param line the empty line which gives violation.
* @return The DetailAST after which empty lines are present.
*/
private static DetailAST getLastElementBeforeEmptyLines(DetailAST ast, int line) {
DetailAST result = ast;
if (ast.getFirstChild().getLineNo() <= line) {
result = ast.getFirstChild();
while (result.getNextSibling() != null
&& result.getNextSibling().getLineNo() <= line) {
result = result.getNextSibling();
}
if (result.hasChildren()) {
result = getLastElementBeforeEmptyLines(result, line);
}
}

if (result.getNextSibling() != null) {
final Optional<DetailAST> postFixNode = getPostFixNode(result.getNextSibling());
if (postFixNode.isPresent()) {
// A post fix AST will always have a sibling METHOD CALL
// METHOD CALL will at least have two children
// The first first child is DOT in case of POSTFIX which have at least 2 children
// First child of DOT again puts us back to normal AST tree which will
// recurse down below from here
final DetailAST firstChildAfterPostFix = postFixNode.get();
result = getLastElementBeforeEmptyLines(firstChildAfterPostFix, line);
}
}
return result;
}

/**
* Gets postfix Node from AST if present.
*
* @param ast the ast to check.
* @return Optional postfix node.
*/
private static Optional<DetailAST> getPostFixNode(DetailAST ast) {
Optional<DetailAST> result = Optional.empty();
if (ast.getType() == TokenTypes.EXPR
// EXPR always has at least one child
&& ast.getFirstChild().getType() == TokenTypes.METHOD_CALL) {
// METHOD CALL always has at two least child
final DetailAST node = ast.getFirstChild().getFirstChild();
if (node.getType() == TokenTypes.DOT) {
result = Optional.of(node);
}
}
return result;
}

/**
Expand Down Expand Up @@ -534,7 +589,7 @@ private static List<Integer> getEmptyLinesToLog(List<Integer> emptyLines) {
int previousEmptyLineNo = emptyLines.get(0);
for (int emptyLineNo : emptyLines) {
if (previousEmptyLineNo + 1 == emptyLineNo) {
emptyLinesToLog.add(emptyLineNo);
emptyLinesToLog.add(previousEmptyLineNo);
}
previousEmptyLineNo = emptyLineNo;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ containsTab=Line contains a tab character.
empty.line.separator=''{0}'' should be separated from previous statement.
empty.line.separator.multiple.lines=''{0}'' has more than 1 empty lines before.
empty.line.separator.multiple.lines.after=''{0}'' has more than 1 empty lines after.
empty.line.separator.multiple.lines.inside=There is more than 1 empty line one after another.
empty.line.separator.multiple.lines.inside=There is more than 1 empty line after this line.
file.containsTab=File contains tab characters (this is the first instance).
line.new=''{0}'' should be on a new line.
line.previous=''{0}'' should be on the previous line.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ containsTab=Die Zeile enthält ein Tabulatorzeichen.
empty.line.separator=''{0}'' sollte von der vorherigen Anweisung durch eine leere Zeile getrennt werden.
empty.line.separator.multiple.lines=Vor ''{0}'' steht mehr als eine leere Zeile.
empty.line.separator.multiple.lines.after=Hinter ''{0}'' steht mehr als eine leere Zeile.
empty.line.separator.multiple.lines.inside=Es stehen mehrere leere Zeilen hintereinander.
empty.line.separator.multiple.lines.inside=Nach dieser Zeile befindet sich mehr als eine leere Zeile.
file.containsTab=Die Datei enthält Tabulatorzeichen (dies ist das erste Vorkommen).
line.new=''{0}'' sollte in einer neuen Zeile stehen.
line.previous=''{0}'' sollte in der vorherigen Zeile stehen.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ containsTab=La línea contiene un carácter de tabulación.
empty.line.separator=''{0}'' debe ser separado de la declaración anterior.
empty.line.separator.multiple.lines=''{0}'' cuenta con más de 1 líneas vacías antes.
empty.line.separator.multiple.lines.after=''{0}'' cuenta con más de 1 líneas vacías después.
empty.line.separator.multiple.lines.inside=Hay más de 1 una línea vacía después de otra.
empty.line.separator.multiple.lines.inside=Hay más de una línea vacía después de esta línea.
file.containsTab=Archivo contiene caracteres de tabulación (este es el primer ejemplo).
line.new=''{0}'' debería estar en una línea nueva.
line.previous=''{0}'' debería estar en la línea anterior.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ containsTab=Rivi sisältää sarkainmerkin.
empty.line.separator=''{0}'' olisi erotettava edellisen selonteon.
empty.line.separator.multiple.lines=''{0}'' on yli 1 tyhjää riviä ennen.
empty.line.separator.multiple.lines.after=''{0}'' on yli 1 tyhjää riviä jälkeen.
empty.line.separator.multiple.lines.inside=On enemmän kuin 1 tyhjä rivi yksi toisensa jälkeen.
empty.line.separator.multiple.lines.inside=Tämän rivin jälkeen on enemmän kuin 1 tyhjä rivi.
file.containsTab=Tiedosto sisältää sarkainmerkeillä (tämä on ensisijaisesti).
line.new=''{0}'' pitää olla uudella rivillä.
line.previous=''{0}'' pitää olla edellisellä rivillä.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ containsTab=La ligne contient un caractère tabulation.
empty.line.separator=''{0}'' doit être séparé de la déclaration précédente.
empty.line.separator.multiple.lines=''{0}'' a plus d''une ligne vide avant.
empty.line.separator.multiple.lines.after=''{0}'' compte plus d''une ligne vide après.
empty.line.separator.multiple.lines.inside=Il y a plus d''une ligne vide une après l'autre.
empty.line.separator.multiple.lines.inside=Il y a plus d'une ligne vide après cette ligne.
file.containsTab=Le fichier contient des caractères de tabulation (ce n''est que la première occurence).
line.new=''{0}'' devrait être sur une nouvelle ligne.
line.previous=''{0}'' devrait être sur la ligne précédente.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ containsTab=行にタブ文字が含まれています。
empty.line.separator=''{0}'' は前の文から分離する必要があります。
empty.line.separator.multiple.lines=''{0}'' の前に空行が複数あります。
empty.line.separator.multiple.lines.after=''{0}'' の後に空行が複数あります。
empty.line.separator.multiple.lines.inside=空行が複数続いています
empty.line.separator.multiple.lines.inside=この行の後に複数の空の行があります
file.containsTab=ファイルにタブ文字が含まれています(ここが最初の出現箇所です)。
line.new=''{0}'' は新しい行にあるべきです。
line.previous=''{0}'' は前の行にあるべきです。
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ containsTab=A linha contém um caractere de tabulação.
empty.line.separator=''{0}'' deveria ser separado da instrução anterior.
empty.line.separator.multiple.lines=''{0}'' é precedido por mais do que 1 linha vazia.
empty.line.separator.multiple.lines.after=''{0}'' é sucedido por mais do que 1 linha vazia.
empty.line.separator.multiple.lines.inside=Há duas ou mais linhas vazias consecutivas.
empty.line.separator.multiple.lines.inside=Existe mais de 1 linha vazia após esta linha.
file.containsTab=O arquivo contém caracteres de tabulação (esta é a primeira ocorrência).
line.new=''{0}'' deveria estar numa nova linha.
line.previous=''{0}'' deveria estar na linha anterior.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ containsTab=Satır, sekme karakteri içermekte.
empty.line.separator={0} 'Bir önceki deyimi ayrılmalıdır.
empty.line.separator.multiple.lines={0} daha önce en fazla 1 boş hatları vardır.
empty.line.separator.multiple.lines.after=''{0}'' sonra 1'den fazla boş hatları vardır.
empty.line.separator.multiple.lines.inside=birbiri ardına 1'den fazla boş satır biri var.
empty.line.separator.multiple.lines.inside=Bu satırdan sonra 1'den fazla boş satır var.
file.containsTab=Dosya, sekme karakterleri içermekte (sadece ilk bulunan gösteriliyor).
line.new=''{0}'' ifadesi yeni bir satırda olmalı.
line.previous=''{0}'' ifadesi önceki satırda olmalı.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ containsTab=行内含有制表符 tab 。
empty.line.separator=''{0}' 前应有空行。
empty.line.separator.multiple.lines=''{0}'' 前只应有一个空行。
empty.line.separator.multiple.lines.after=''{0}'' 后只应有一个空行。
empty.line.separator.multiple.lines.inside=还有陆续超过1空行之一
empty.line.separator.multiple.lines.inside=该行之后有多于1个空行
file.containsTab=文件含有制表符 tab (这只是第一例)。
line.new=''{0}'' 应另起一行。
line.previous=''{0}'' 应在前一行。
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public void testMultipleEmptyLinesBetweenClassMembers() throws Exception {
"33:5: " + getCheckMessage(MSG_MULTIPLE_LINES, "VARIABLE_DEF"),
"38:5: " + getCheckMessage(MSG_MULTIPLE_LINES, "VARIABLE_DEF"),
"43:5: " + getCheckMessage(MSG_MULTIPLE_LINES, "METHOD_DEF"),
"45:5: " + getCheckMessage(MSG_MULTIPLE_LINES_AFTER, "METHOD_DEF"),
"45:33: " + getCheckMessage(MSG_MULTIPLE_LINES_AFTER, "}"),
};
verify(checkConfig, getPath("InputEmptyLineSeparatorMultipleEmptyLines.java"), expected);
}
Expand Down Expand Up @@ -256,10 +256,12 @@ public void testPreviousLineEmptiness() throws Exception {
final DefaultConfiguration checkConfig = createModuleConfig(EmptyLineSeparatorCheck.class);
checkConfig.addAttribute("allowMultipleEmptyLinesInsideClassMembers", "false");
final String[] expected = {
"11: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"16: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"22: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"31: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"9:30: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"14:5: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"20:67: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"29:48: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"39:21: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),

};
verify(checkConfig,
getPath("InputEmptyLineSeparatorPreviousLineEmptiness.java"), expected);
Expand All @@ -270,12 +272,11 @@ public void testDisAllowMultipleEmptyLinesInsideClassMembers() throws Exception
final DefaultConfiguration checkConfig = createModuleConfig(EmptyLineSeparatorCheck.class);
checkConfig.addAttribute("allowMultipleEmptyLinesInsideClassMembers", "false");
final String[] expected = {
"27: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"39: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"45: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"50: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"55: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"56: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"25:11: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"37:11: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"43:11: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"48:31: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"53:11: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"60:1: " + getCheckMessage(MSG_SHOULD_BE_SEPARATED, "CLASS_DEF"),
};
verify(checkConfig,
Expand Down Expand Up @@ -464,8 +465,8 @@ public void testEmptyLineSeparatorRecordsAndCompactCtorsNoEmptyLines() throws Ex

final String[] expected = {
"2:1: " + getCheckMessage(MSG_SHOULD_BE_SEPARATED, "package"),
"16: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"22: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"14:27: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"20:29: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
};

verify(checkConfig,
Expand All @@ -486,4 +487,55 @@ public void testEmptyLineSeparatorMultipleSingleTypeVariables() throws Exception
expected);
}

@Test
public void testEmptyLineSeparatorEmptyLinesInsideClassMembersRecursive() throws Exception {
final DefaultConfiguration checkConfig = createModuleConfig(EmptyLineSeparatorCheck.class);
checkConfig.addAttribute("allowMultipleEmptyLinesInsideClassMembers", "false");
final String[] expected = {
"19:15: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
};
verify(checkConfig,
getPath("InputEmptyLineSeparatorRecursive.java"),
expected);
}

@Test
public void testEmptyLineSeparatorNewMethodDef() throws Exception {
final DefaultConfiguration checkConfig = createModuleConfig(EmptyLineSeparatorCheck.class);
checkConfig.addAttribute("allowMultipleEmptyLinesInsideClassMembers", "false");
final String[] expected = {
"21:34: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"30:26: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
};
verify(checkConfig,
getPath("InputEmptyLineSeparatorNewMethodDef.java"),
expected);
}

@Test
public void testEmptyLineSeparatorPostFixCornerCases() throws Exception {
final DefaultConfiguration checkConfig = createModuleConfig(EmptyLineSeparatorCheck.class);
checkConfig.addAttribute("allowMultipleEmptyLinesInsideClassMembers", "false");
final String[] expected = {
"10:19: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"24:29: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
"35:29: " + getCheckMessage(MSG_MULTIPLE_LINES_INSIDE),
};
verify(checkConfig,
getPath("InputEmptyLineSeparatorPostFixCornerCases.java"),
expected);
}

@Test
public void testEmptyLineSeparatorAnnotation() throws Exception {
final DefaultConfiguration checkConfig = createModuleConfig(EmptyLineSeparatorCheck.class);
checkConfig.addAttribute("allowMultipleEmptyLines", "false");
final String[] expected = {
"10:22: " + getCheckMessage(MSG_MULTIPLE_LINES_AFTER, "}"),
};
verify(checkConfig,
getPath("InputEmptyLineSeparatorAnnotations.java"),
expected);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@
*
*/
public class InputEmptyLineSeparatorRecordsAndCompactCtorsNoEmptyLines {
public void foo() {
public void foo() { // violation


} // ^ violation
}

public record MyRecord1(){
public MyRecord1{
public MyRecord1{ // violation


} // ^ violation
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.puppycrawl.tools.checkstyle.checks.whitespace.emptylineseparator;

/**
* Config:
* allowMultipleEmptyLines = false
*/
public class InputEmptyLineSeparatorAnnotations {
@Deprecated
@SuppressWarnings("unchecked")
class SomeClass {} // violation




}
Loading

0 comments on commit 638661b

Please sign in to comment.