com.puppycrawl.tools.checkstyle.checks.whitespace.GenericWhitespaceCheck Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of checkstyle Show documentation
Show all versions of checkstyle Show documentation
Checkstyle is a development tool to help programmers write Java code that adheres to a coding standard
////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code for adherence to a set of rules.
// Copyright (C) 2001-2017 the original author or authors.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
////////////////////////////////////////////////////////////////////////////////
package com.puppycrawl.tools.checkstyle.checks.whitespace;
import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
/**
*
* Checks that the whitespace around the Generic tokens (angle brackets)
* "<" and ">" are correct to the typical convention.
* The convention is not configurable.
*
*
*
* Left angle bracket ("<"):
*
*
*
* - should be preceded with whitespace only
* in generic methods definitions.
* - should not be preceded with whitespace
* when it is precede method name or following type name.
* - should not be followed with whitespace in all cases.
*
*
*
* Right angle bracket (">"):
*
*
*
* - should not be preceded with whitespace in all cases.
* - should be followed with whitespace in almost all cases,
* except diamond operators and when preceding method name.
*
*
* Examples with correct spacing:
*
*
*
* public void <K, V extends Number> boolean foo(K, V) {} // Generic methods definitions
* class name<T1, T2, ..., Tn> {} // Generic type definition
* OrderedPair<String, Box<Integer>> p; // Generic type reference
* boolean same = Util.<Integer, String>compare(p1, p2); // Generic preceded method name
* Pair<Integer, String> p1 = new Pair<>(1, "apple");// Diamond operator
* List<T> list = ImmutableList.Builder<T>::new; // Method reference
* sort(list, Comparable::<String>compareTo); // Method reference
*
* @author Oliver Burn
*/
public class GenericWhitespaceCheck extends AbstractCheck {
/**
* A key is pointing to the warning message text in "messages.properties"
* file.
*/
public static final String MSG_WS_PRECEDED = "ws.preceded";
/**
* A key is pointing to the warning message text in "messages.properties"
* file.
*/
public static final String MSG_WS_FOLLOWED = "ws.followed";
/**
* A key is pointing to the warning message text in "messages.properties"
* file.
*/
public static final String MSG_WS_NOT_PRECEDED = "ws.notPreceded";
/**
* A key is pointing to the warning message text in "messages.properties"
* file.
*/
public static final String MSG_WS_ILLEGAL_FOLLOW = "ws.illegalFollow";
/** Open angle bracket literal. */
private static final String OPEN_ANGLE_BRACKET = "<";
/** Close angle bracket literal. */
private static final String CLOSE_ANGLE_BRACKET = ">";
/** Used to count the depth of a Generic expression. */
private int depth;
@Override
public int[] getDefaultTokens() {
return getAcceptableTokens();
}
@Override
public int[] getAcceptableTokens() {
return new int[] {TokenTypes.GENERIC_START, TokenTypes.GENERIC_END};
}
@Override
public int[] getRequiredTokens() {
return getAcceptableTokens();
}
@Override
public void beginTree(DetailAST rootAST) {
// Reset for each tree, just increase there are errors in preceding
// trees.
depth = 0;
}
@Override
public void visitToken(DetailAST ast) {
switch (ast.getType()) {
case TokenTypes.GENERIC_START:
processStart(ast);
depth++;
break;
case TokenTypes.GENERIC_END:
processEnd(ast);
depth--;
break;
default:
throw new IllegalArgumentException("Unknown type " + ast);
}
}
/**
* Checks the token for the end of Generics.
* @param ast the token to check
*/
private void processEnd(DetailAST ast) {
final String line = getLine(ast.getLineNo() - 1);
final int before = ast.getColumnNo() - 1;
final int after = ast.getColumnNo() + 1;
if (before >= 0 && Character.isWhitespace(line.charAt(before))
&& !CommonUtils.hasWhitespaceBefore(before, line)) {
log(ast.getLineNo(), before, MSG_WS_PRECEDED, CLOSE_ANGLE_BRACKET);
}
if (after < line.length()) {
// Check if the last Generic, in which case must be a whitespace
// or a '(),[.'.
if (depth == 1) {
processSingleGeneric(ast, line, after);
}
else {
processNestedGenerics(ast, line, after);
}
}
}
/**
* Process Nested generics.
* @param ast token
* @param line line content
* @param after position after
*/
private void processNestedGenerics(DetailAST ast, String line, int after) {
// In a nested Generic type, so can only be a '>' or ',' or '&'
// In case of several extends definitions:
//
// class IntEnumValueType & IntEnum>
// ^
// should be whitespace if followed by & -+
//
final int indexOfAmp = line.indexOf('&', after);
if (indexOfAmp >= 0
&& containsWhitespaceBetween(after, indexOfAmp, line)) {
if (indexOfAmp - after == 0) {
log(ast.getLineNo(), after, MSG_WS_NOT_PRECEDED, "&");
}
else if (indexOfAmp - after != 1) {
log(ast.getLineNo(), after, MSG_WS_FOLLOWED, CLOSE_ANGLE_BRACKET);
}
}
else if (line.charAt(after) == ' ') {
log(ast.getLineNo(), after, MSG_WS_FOLLOWED, CLOSE_ANGLE_BRACKET);
}
}
/**
* Process Single-generic.
* @param ast token
* @param line line content
* @param after position after
*/
private void processSingleGeneric(DetailAST ast, String line, int after) {
final char charAfter = line.charAt(after);
// Need to handle a number of cases. First is:
// Collections.