Skip to content

Commit

Permalink
Issue checkstyle#4639: added support for lambdas in UnnecessaryParent…
Browse files Browse the repository at this point in the history
…heses
  • Loading branch information
rnveach authored and ArneLimburg committed Aug 23, 2017
1 parent e15a50d commit 1b7bd7d
Show file tree
Hide file tree
Showing 13 changed files with 144 additions and 3 deletions.
Expand Up @@ -89,6 +89,12 @@ public class UnnecessaryParenthesesCheck extends AbstractCheck {
*/
public static final String MSG_RETURN = "unnecessary.paren.return";

/**
* A key is pointing to the warning message text in "messages.properties"
* file.
*/
public static final String MSG_LAMBDA = "unnecessary.paren.lambda";

/** The maximum string length before we chop the string. */
private static final int MAX_QUOTED_LENGTH = 25;

Expand Down Expand Up @@ -153,6 +159,7 @@ public int[] getDefaultTokens() {
TokenTypes.SL_ASSIGN,
TokenTypes.SR_ASSIGN,
TokenTypes.STAR_ASSIGN,
TokenTypes.LAMBDA,
};
}

Expand Down Expand Up @@ -181,6 +188,7 @@ public int[] getAcceptableTokens() {
TokenTypes.SL_ASSIGN,
TokenTypes.SR_ASSIGN,
TokenTypes.STAR_ASSIGN,
TokenTypes.LAMBDA,
};
}

Expand All @@ -190,12 +198,16 @@ public int[] getRequiredTokens() {
return CommonUtils.EMPTY_INT_ARRAY;
}

// -@cs[CyclomaticComplexity] All logs should be in visit token.
@Override
public void visitToken(DetailAST ast) {
final int type = ast.getType();
final DetailAST parent = ast.getParent();

if (type != TokenTypes.ASSIGN
if (type == TokenTypes.LAMBDA && isLambdaSingleParameterSurrounded(ast)) {
log(ast, MSG_LAMBDA, ast.getText());
}
else if (type != TokenTypes.ASSIGN
|| parent.getType() != TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR) {

final boolean surrounded = isSurrounded(ast);
Expand Down Expand Up @@ -291,6 +303,22 @@ private static boolean isExprSurrounded(DetailAST ast) {
return ast.getFirstChild().getType() == TokenTypes.LPAREN;
}

/**
* Tests if the given lambda node has a single parameter, no defined type, and is surrounded
* by parentheses.
* @param ast a {@code DetailAST} whose type is
* {@code TokenTypes.LAMBDA}.
* @return {@code true} if the lambda has a single parameter, no defined type, and is
* surrounded by parentheses.
*/
private static boolean isLambdaSingleParameterSurrounded(DetailAST ast) {
final DetailAST firstChild = ast.getFirstChild();
return firstChild.getType() == TokenTypes.LPAREN
&& firstChild.getNextSibling().getChildCount(TokenTypes.PARAMETER_DEF) == 1
&& firstChild.getNextSibling().getFirstChild().findFirstToken(TokenTypes.TYPE)
.getChildCount() == 0;
}

/**
* Check if the given token type can be found in an array of token types.
* @param type the token type.
Expand Down
Expand Up @@ -51,6 +51,7 @@ string.literal.equality=Literal Strings should be compared using equals(), not '
unnecessary.paren.assign=Unnecessary parentheses around assignment right-hand side.
unnecessary.paren.expr=Unnecessary parentheses around expression.
unnecessary.paren.ident=Unnecessary parentheses around identifier ''{0}''.
unnecessary.paren.lambda=Unnecessary parentheses around lambda value.
unnecessary.paren.literal=Unnecessary parentheses around literal ''{0}''.
unnecessary.paren.return=Unnecessary parentheses around return value.
unnecessary.paren.string=Unnecessary parentheses around string {0}.
Expand Down
Expand Up @@ -51,6 +51,7 @@ string.literal.equality=Der Vergleich von String-Literalen sollte mit equals() e
unnecessary.paren.assign=Überflüssige Klammern um die rechte Seite der Zuweisung.
unnecessary.paren.expr=Überflüssige Klammern um den Ausdruck.
unnecessary.paren.ident=Überflüssige Klammern um den Bezeichner ''{0}''.
unnecessary.paren.lambda=Überflüssige Klammern um Lambdawert.
unnecessary.paren.literal=Überflüssige Klammern um das Literal ''{0}''.
unnecessary.paren.return=Überflüssige Klammern um den Rückgabewert.
unnecessary.paren.string=Überflüssige Klammern um den String ''{0}''.
Expand Down
Expand Up @@ -51,6 +51,7 @@ string.literal.equality=Las cadenas literales deben compararse usando equals(),
unnecessary.paren.assign=Paréntesis innecesarios alrededor de la parte derecha de una asignación.
unnecessary.paren.expr=Paréntesis innecesarios alrededor de la expresión.
unnecessary.paren.ident=Paréntesis innecesarios alrededor del identificador ''{0}''.
unnecessary.paren.lambda=Paréntesis innecesarios alrededor del valor lambda.
unnecessary.paren.literal=Paréntesis innecesarios alrededor del literal ''{0}''.
unnecessary.paren.return=Paréntesis innecesarios alrededor del valor de retorno.
unnecessary.paren.string=Paréntesis innecesarios alrededor de la cadena {0}.
Expand Down
Expand Up @@ -51,6 +51,7 @@ string.literal.equality=Kirjaimellinen Strings pitäisi verrata käyttämällä
unnecessary.paren.assign=Tarpeettomia sulkuja noin tehtävän oikealla puolella.
unnecessary.paren.expr=Tarpeettomia sulkuja noin ilme.
unnecessary.paren.ident=Tarpeettomia sulkuja noin tunniste ''{0}''.
unnecessary.paren.lambda=Tarpeettomat sulkeet lambda-arvon ympärillä.
unnecessary.paren.literal=Tarpeettomia sulkuja noin kirjaimellisesti ''{0}''.
unnecessary.paren.return=Tarpeettomia sulkuja noin paluuarvo.
unnecessary.paren.string=Tarpeettomia sulkuja noin merkkijono {0} .
Expand Down
Expand Up @@ -51,6 +51,7 @@ string.literal.equality=Les chaines de caractères littérales devraient être c
unnecessary.paren.assign=Parenthèses inutiles autour la partie droite de l''affectation.
unnecessary.paren.expr=Parenthèses inutiles autour de l''expression.
unnecessary.paren.ident=Parenthèses inutiles autour de l''identifiant ''{0}''.
unnecessary.paren.lambda=Parenthèses inutiles autour de la valeur lambda.
unnecessary.paren.literal=Parenthèses inutiles autour de la chaîne littérale ''{0}''.
unnecessary.paren.return=Parenthèses inutiles autour de la valeur de retour.
unnecessary.paren.string=Parenthèses inutiles autour de la chaîne {0}.
Expand Down
Expand Up @@ -51,6 +51,7 @@ string.literal.equality=リテラルの文字列は ''{0}'' ではなく、 equa
unnecessary.paren.assign=代入式の右辺に不要な括弧があります。
unnecessary.paren.expr=式の前後に不要な括弧があります。
unnecessary.paren.ident=識別子 ''{0}'' の前後に不要な括弧があります。
unnecessary.paren.lambda=ラムダ値の周りの不必要なカッコ。
unnecessary.paren.literal=リテラル ''{0}'' の前後に不要な括弧があります。
unnecessary.paren.return=戻り値の前後に不要な括弧があります。
unnecessary.paren.string=文字列 {0} の前後に不要な括弧があります。
Expand Down
Expand Up @@ -51,6 +51,7 @@ string.literal.equality=\"Strings\" literais devem ser comparadas com equals(),
unnecessary.paren.assign=Parênteses desnecessários ao redor do lado direito atribuição.
unnecessary.paren.expr=Parênteses desnecessários ao redor expressão.
unnecessary.paren.ident=Parênteses desnecessários ao redor identificador ''{0}''.
unnecessary.paren.lambda=Parêntesis desnecessários em torno do valor lambda.
unnecessary.paren.literal=Parênteses desnecessários em torno literal ''{0}''.
unnecessary.paren.return=Parênteses desnecessários em torno de valor de retorno.
unnecessary.paren.string=Parênteses desnecessários em torno cadeia {0}
Expand Down
Expand Up @@ -52,6 +52,7 @@ string.literal.equality=''String'' ifadeleri ''{0}'' kullanarak değil, equals()
unnecessary.paren.assign=Atama ifadesinin sağ tarafında gereksiz parantez mevcut.
unnecessary.paren.expr=İfadenin etrafında gereksiz parantez mevcut.
unnecessary.paren.ident=''{0}'' belirteçinin etrafında gereksiz parantez mevcut.
unnecessary.paren.lambda=Lamba değeri etrafında gereksiz parantezler var.
unnecessary.paren.literal=''{0}'' etrafında gereksiz parantez mevcut.
unnecessary.paren.return=Geri dönüş değeri etrafında gereksiz parantez mevcut.
unnecessary.paren.string=''{0}'' etrafında gereksiz parantez mevcut.
Expand Down
Expand Up @@ -51,6 +51,7 @@ string.literal.equality=字符串应使用equals()方法进行比较,而非''{
unnecessary.paren.assign=赋值语句右方不必要的小括号。
unnecessary.paren.expr=表达式周围不必要的小括号。
unnecessary.paren.ident=关键字 ''{0}'' 周围不必要的小括号。
unnecessary.paren.lambda=lambda 值周围不必要的小括号。
unnecessary.paren.literal=字符串 ''{0}'' 周围不必要的小括号。
unnecessary.paren.return=return 值周围不必要的小括号。
unnecessary.paren.string=字符串 {0} 周围不必要的小括号。
Expand Down
Expand Up @@ -22,6 +22,7 @@
import static com.puppycrawl.tools.checkstyle.checks.coding.UnnecessaryParenthesesCheck.MSG_ASSIGN;
import static com.puppycrawl.tools.checkstyle.checks.coding.UnnecessaryParenthesesCheck.MSG_EXPR;
import static com.puppycrawl.tools.checkstyle.checks.coding.UnnecessaryParenthesesCheck.MSG_IDENT;
import static com.puppycrawl.tools.checkstyle.checks.coding.UnnecessaryParenthesesCheck.MSG_LAMBDA;
import static com.puppycrawl.tools.checkstyle.checks.coding.UnnecessaryParenthesesCheck.MSG_LITERAL;
import static com.puppycrawl.tools.checkstyle.checks.coding.UnnecessaryParenthesesCheck.MSG_RETURN;
import static com.puppycrawl.tools.checkstyle.checks.coding.UnnecessaryParenthesesCheck.MSG_STRING;
Expand Down Expand Up @@ -107,6 +108,24 @@ public void test15Extensions() throws Exception {
verify(checkConfig, getPath("InputUnnecessaryParentheses15Extensions.java"), expected);
}

@Test
public void testLambdas() throws Exception {
final DefaultConfiguration checkConfig =
createModuleConfig(UnnecessaryParenthesesCheck.class);
checkConfig.addAttribute("tokens", "LAMBDA");
final String[] expected = {
"10:35: " + getCheckMessage(MSG_LAMBDA),
"11:35: " + getCheckMessage(MSG_LAMBDA),
"18:18: " + getCheckMessage(MSG_LAMBDA),
"19:57: " + getCheckMessage(MSG_LAMBDA),
"38:25: " + getCheckMessage(MSG_LAMBDA),
"38:33: " + getCheckMessage(MSG_LAMBDA),
"41:25: " + getCheckMessage(MSG_LAMBDA),
"44:31: " + getCheckMessage(MSG_LAMBDA),
};
verify(checkConfig, getPath("InputUnnecessaryParenthesesLambdas.java"), expected);
}

@Test
public void testTokensNotNull() {
final UnnecessaryParenthesesCheck check = new UnnecessaryParenthesesCheck();
Expand Down
@@ -0,0 +1,79 @@
package com.puppycrawl.tools.checkstyle.checks.coding.unnecessaryparentheses;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Objects;
import java.util.function.Function;

public class InputUnnecessaryParenthesesLambdas {
int foo(int y) {
MathOperation case1 = (x) -> x + x;
MathOperation case2 = (x) -> { return x + x; };
MathOperation case3 = (int x) -> x + x;
MathOperation case4 = x -> x + x;
MathOperation2 case5 = (a, b) -> a + b;
MathOperation2 case6 = (int a, int b) -> a + b;
MathOperation2 case7 = (int a, int b) -> { return a + b; };
Objects.requireNonNull(null, () -> "message");
call((x) -> x + x);
new HashSet<Integer>().stream().filter((filter) -> filter > 0);
return y;
}

static <T> CheckedFunction1<T, T> identitity() {
return t -> t;
}

public interface CheckedFunction2<T1, T2, R> extends Lambda<R> {
R apply(T1 t1, T2 t2) throws Throwable;

default CheckedFunction1<T2, R> apply(T1 t1) {
return (T2 t2) -> apply(t1, t2);
}
@Override
default Function1<T1, CheckedFunction1<T2, R>> curried() {
return t1 -> t2 -> apply(t1, t2);
}
default Function1<T1, CheckedFunction1<T2, R>> curried2() {
return (t1) -> (t2) -> apply(t1, t2);
}
default Function1<T1, CheckedFunction1<T2, R>> curried3() {
return (t1) -> t2 -> apply(t1, t2);
}
default Function1<T1, CheckedFunction1<T2, R>> curried4() {
return t1 -> (t2) -> apply(t1, t2);
}
}

private void call(MathOperation o) {
o.operation(1);
}

interface MathOperation {
int operation(int a);
}

interface MathOperation2 {
int operation(int a, int b);
}

interface Lambda<R> extends Serializable {
Lambda<?> curried();
}

public interface Function1<T1, R> extends Lambda<R>, Function<T1, R> {
@Override
default Function1<T1, R> curried() {
return this;
}
}

public interface CheckedFunction1<T1, R> extends Lambda<R> {
R apply(T1 t1) throws Throwable;

@Override
default CheckedFunction1<T1, R> curried() {
return this;
}
}
}
10 changes: 8 additions & 2 deletions src/xdocs/config_coding.xml
Expand Up @@ -4365,7 +4365,8 @@ if (&quot;something&quot;.equals(x))
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#PLUS_ASSIGN">PLUS_ASSIGN</a>,
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#SL_ASSIGN">SL_ASSIGN</a>,
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#SR_ASSIGN">SR_ASSIGN</a>,
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#STAR_ASSIGN">STAR_ASSIGN</a>.
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#STAR_ASSIGN">STAR_ASSIGN</a>,
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LAMBDA">LAMBDA</a>.
</td>
<td>
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#EXPR">EXPR</a>,
Expand All @@ -4389,7 +4390,8 @@ if (&quot;something&quot;.equals(x))
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#PLUS_ASSIGN">PLUS_ASSIGN</a>,
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#SL_ASSIGN">SL_ASSIGN</a>,
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#SR_ASSIGN">SR_ASSIGN</a>,
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#STAR_ASSIGN">STAR_ASSIGN</a>.
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#STAR_ASSIGN">STAR_ASSIGN</a>,
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LAMBDA">LAMBDA</a>.
</td>
<td>3.4</td>
</tr>
Expand Down Expand Up @@ -4428,6 +4430,10 @@ if (&quot;something&quot;.equals(x))
<a href="https://github.com/search?q=path%3Asrc%2Fmain%2Fresources%2Fcom%2Fpuppycrawl%2Ftools%2Fcheckstyle%2Fchecks%2Fcoding+filename%3Amessages*.properties+repo%3Acheckstyle%2Fcheckstyle+%22unnecessary.paren.ident%22">
unnecessary.paren.ident</a>
</li>
<li>
<a href="https://github.com/search?q=path%3Asrc%2Fmain%2Fresources%2Fcom%2Fpuppycrawl%2Ftools%2Fcheckstyle%2Fchecks%2Fcoding+filename%3Amessages*.properties+repo%3Acheckstyle%2Fcheckstyle+%22unnecessary.paren.lambda%22">
unnecessary.paren.lambda</a>
</li>
<li>
<a href="https://github.com/search?q=path%3Asrc%2Fmain%2Fresources%2Fcom%2Fpuppycrawl%2Ftools%2Fcheckstyle%2Fchecks%2Fcoding+filename%3Amessages*.properties+repo%3Acheckstyle%2Fcheckstyle+%22unnecessary.paren.literal%22">
unnecessary.paren.literal</a>
Expand Down

0 comments on commit 1b7bd7d

Please sign in to comment.