diff --git a/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/coding/checkstyle-metadata.properties b/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/coding/checkstyle-metadata.properties
index b7859c2c4a..be09250de4 100755
--- a/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/coding/checkstyle-metadata.properties
+++ b/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/coding/checkstyle-metadata.properties
@@ -83,7 +83,7 @@ IllegalCatchExtendedCheck.illegalClassNames = Illegal class names
LogicConditionNeedOptimizationCheck.name = Logic condition need optimization
LogicConditionNeedOptimizationCheck.desc = This check prevents the placement of local variables and fields after calling methods in '&&' and '||' conditions.
-MapIterationInForEachLoopCheck.name = Map Iteration In For Each Loop
+MapIterationInForEachLoopCheck.name = Map Iteration In For Each Loop
MapIterationInForEachLoopCheck.desc = This check can help you to write the whole for-each map iteration more correctly:
- If you iterate over a map using map.keySet() or map.entrySet(), but your code uses only map values, Check will propose you to use map.values() instead of map.keySet() or map.entrySet(). Replacing map.keySet() or map.entrySet() with map.values() for such cases can a bit improve an iteration performance.
Bad:
for (Map.Entry; entry : map.entrySet()){
System.out.println(entry.getValue());
}
for (String key : map.keySet(){
System.out.println(map.get(key));
}Good:
for (String value : map.values()){
System.out.println(value);
} - If you iterate over a map using map.entrySet(), but never call entry.getValue(), Check will propose you to use map.keySet() instead of map.entrySet(). to iterate over map keys only.
Bad:
for (Map.Entry entry : map.entrySet()){
System.out.println(entry.getKey());
}
Good:
for (String key : map.keySet()){
System.out.println(key);
} - If you iterate over a map with map.keySet() and use both keys and values, check will propose you to use map.entrySet() to improve an iteration performance by avoiding search operations inside a map. For this case, iteration can significantly grow up a performance.
Bad:
for (String key : map.keySet()){
System.out.println(key + " " + map.get(key));
}Good:
for (Map.Entry entry : map.entrySet()){
System.out.println(entry.getValue() + " " + entry.getKey());
}
MapIterationInForEachLoopCheck.supportedMapImplQualifiedNames = Enter your own Map implementations.
MapIterationInForEachLoopCheck.proposeValuesUsage = If this checkbox is checked, Check will propose to replace wrong usage to value().
@@ -92,7 +92,7 @@ MapIterationInForEachLoopCheck.proposeEntrySetUsage = If this checkbox is checke
MultipleVariableDeclarationsExtendedCheck.name = Multiple Variable Declarations Extended
MultipleVariableDeclarationsExtendedCheck.desc = Warn when declaring several variables in one line
-MultipleVariableDeclarationsExtendedCheck.ignoreCycles = Turning on this option makes check not to warn on multiple variable definitions inside cycles.
+MultipleVariableDeclarationsExtendedCheck.ignoreCycles = Turning on this option makes check not to warn on multiple variable definitions inside cycles.
MultipleVariableDeclarationsExtendedCheck.ignoreMethods = Turning on this option makes check not to warn on multiple variable definitions inside methods.
MultipleStringLiteralsExtendedCheck.allowedDuplicates = The maximum number of occurences to allow without generating a warning
@@ -106,7 +106,7 @@ TernaryPerExpressionCountCheck.name = Ternary Per Expression Count
TernaryPerExpressionCountCheck.desc = Restricts the number of ternary operators in expression to a specific limit.
Rationale: This Check helps to improve code readability by pointing developer on
expressions which contain more than user-defined count of ternary operators.
It points to complicated ternary expressions. Reason:
- Complicated ternary expressions are not easy to read.
- Complicated ternary expressions could lead to ambiguous result if user
does not know Java's operators priority well, e.g.:
String str = null;
String x = str != null ? "A" : "B" + str == null ? "C" : "D";
System.out.println(x);
Output for code above is "D", but more obvious would be "BC".
Check has following properties:
- maxTernaryPerExpressionCount - limit of ternary operators per expression
- ignoreTernaryOperatorsInBraces - if true Check will ignore ternary operators
in braces (braces explicitly set priority level)
- ignoreIsolatedTernaryOnLine - if true Check will ignore one line ternary operators,
if only it is places in line alone.
Options ignoreTernaryOperatorsInBraces and ignoreIsolatedTernaryOnLine can
make Check less strict, e.g.:
Using ignoreTernaryOperatorsInBraces option (value = true)
does not put violation on code below:
callString = "{? = call " +
(StringUtils.hasLength(catalogNameToUse) ? catalogNameToUse + "." : "") +
(StringUtils.hasLength(schemaNameToUse) ? schemaNameToUse + "." : "") +
procedureNameToUse + "(";
When using ignoreIsolatedTernaryOnLine (value = true), even without
ignoreTernaryOperatorsInBraces option Check won't warn on code below:
int a = (d == 5) ? d : f
+
((d == 6) ? g : k);
@author Aleksey Nesterenko
TernaryPerExpressionCountCheck.maxTernaryPerExpressionCount = Maximum number of ternary operators in expression
TernaryPerExpressionCountCheck.ignoreTernaryOperatorsInBraces = Ignore ternary operators in expression in case if priority level is set explicitly
-TernaryPerExpressionCountCheck.ignoreIsolatedTernaryOnLine = Ignore ternary operators in expression in case if ternary operator is isolated in line
+TernaryPerExpressionCountCheck.ignoreIsolatedTernaryOnLine = Ignore ternary operators in expression in case if ternary operator is isolated in line
NameConventionForJunit4TestClassesCheck.name = Name Convention For JUnit4 Test Classes Check
NameConventionForJunit4TestClassesCheck.desc = This check verifies the name of JUnit4 test class for compliance with user defined naming convention(by default Check expects test classes names matching ".+Test\\d*|.+Tests\\d*|Test.+|Tests.+|.+IT|.+ITs|.+TestCase\\d*|.+TestCases\\d*" regex).
Class is considered to be a test if its definition or one of its method definitions annotated with user defined annotations. By default Check looks for classes which contain methods annotated with "Test" or "org.junit.Test".
Check has following options:
"expectedClassNameRegex" - regular expression which matches expected test class names. If test class name does not matches this regex then Check will log violation. This option defaults to ".+Test\\d*|.+Tests\\d*|Test.+|Tests.+|.+IT|.+ITs|.+TestCase\\d*|.+TestCases\\d*".
"classAnnotationNameRegex" - regular expression which matches test annotation names on classes. If class annotated with matching annotation, it is considered to be a test. This option defaults to empty regex(one that matches nothing). If for example this option set to "RunWith", then class "SomeClass" is considered to be a test:
@RunWith(Parameterized.class)
class SomeClass
{
}
"methodAnnotationNameRegex" - regular expression which matches test annotation names on methods. If class contains a method annotated with matching annotation, it is considered to be a test. This option defaults to "Test|org.junit.Test". For example, if this option set to "Test", then class SomeClass" is considered to be a test.
class SomeClass
{
@Test
void method() {
}
}
Annotation names must be specified exactly the same way it specified in code, thus if Check must match annotation with fully qualified name, corresponding options must contain qualified annotation name and vice versa. For example, if annotation regex is "org.junit.Test" Check will recognize "@org.junit.Test" annotation and will skip "@Test" annotation and vice versa if annotation regex is "Test" Check will recognize "@Test" annotation and skip "@org.junit.Test" annotation.
@author Zuy Alexey
@@ -142,7 +142,7 @@ ReturnCountExtendedCheck.name=Return Count Extended
ReturnCountExtendedCheck.desc=Checks that method/ctor "return" literal count is not greater than the given value ("maxReturnCount" property).
Rationale:
One return per method is a good practice as its ease understanding of method logic.
Reasoning is that:
It is easier to understand control flow when you know exactly where the method returns.Methods with 2-3 or many "return" statements are much more difficult to understand, debug and refactor.Setting up the check options will make it to ignore:- Methods by name ("ignoreMethodsNames" property). Note, that the "ignoreMethodsNames" property type is NOT regexp: using this property you can list the names of ignored methods separated by comma.
- Methods which linelength less than given value ("linesLimit" property).
- "return" statements which depth is greater or equal to the given value ("returnDepthLimit" property). There are few supported
coding blocks when depth counting: "if-else", "for", "while"/"do-while" and "switch". - "Empty" return statements = return statements in void methods and ctors that have not any expression ("ignoreEmptyReturns" property).
- Return statements, which are located in the top lines of method/ctor (you can specify the count of top method/ctor lines that will be ignored using "rowsToIgnoreCount" property).
So, this is much improved version of the existing Return Count check.
ReturnCountExtendedCheck.maxReturnCount=maximum allowed number of return statements per method/ctor (1 by default).
ReturnCountExtendedCheck.ignoreMethodLinesCount=Option to ignore methods/ctors which body has the linelength is less than given (20 lines by default). Set "0" to switch this option off and check all methods/ctors.
-ReturnCountExtendedCheck.minIgnoreReturnDepth=Option to ignore methods/ctors that have return statement(s) with depth value is less than N levels(scopes). 4 by default. 0 is the min depth. Depth is 0 when the "return" statement is not wrapped on one of the supported coding blocks.
+ReturnCountExtendedCheck.minIgnoreReturnDepth=Option to ignore methods/ctors that have return statement(s) with depth value is less than N levels(scopes). 4 by default. 0 is the min depth. Depth is 0 when the "return" statement is not wrapped on one of the supported coding blocks.
ReturnCountExtendedCheck.ignoreEmptyReturns=Option to ignore "empty" (with no any expression) return statements in void methods and ctors. 'False' by default.
ReturnCountExtendedCheck.topLinesToIgnoreCount=Option to set the count of code lines that will be ignored in top of all methods.
ReturnCountExtendedCheck.ignoreMethodsNames=Option to set the RegExp patterns for methods' names which would be ignored by check.
@@ -161,6 +161,9 @@ SimpleAccessorNameNotationCheck.prefix=prefix of field's name
SingleBreakOrContinueCheck.name = Single break or continue inside a loop
SingleBreakOrContinueCheck.desc = This check restricts the number of break and continue statements inside cycle body (only one is allowed).
Restricting the number of break and continue statements in a loop is done in the interest of good structured programming.
+SingleMethodTypeParameterCheck.name = Single type parameter method check
+SingleMethodTypeParameterCheck.desc = This check restricts the use of type parameters. If a type parameter appears only once in a method declaration, it should be replaced with a wildcard.
+
UnnecessaryParenthesesExtendedCheck.desc = Checks for the use of unnecessary parentheses.
UnnecessaryParenthesesExtendedCheck.name = Unnecessary Parentheses Extended
UnnecessaryParenthesesExtendedCheck.ignoreCalculationOfBooleanVariables = Cancel validation setups of unnecessary parentheses in Boolean computations.
@@ -178,7 +181,7 @@ UselessSuperCtorCallCheck.allowCallToNoArgsSuperCtorIfMultiplePublicCtor = Allow
EitherLogOrThrowCheck.desc = Either log the exception, or throw it, but never do both. Logging and throwing results in multiple log messages for a single problem in the code, and makes problems for the support engineer who is trying to dig through the logs. This is one of the most annoying error-handling antipatterns. All of these examples are equally wrong.
Examples:
catch (NoSuchMethodException e) {\t\nLOG.error("Message", e);\t\nthrow e;\n}orcatch (NoSuchMethodException e) {\t\nLOG.error("Message", e);\t\nthrow new MyServiceException("AnotherMessage", e);\n}orcatch (NoSuchMethodException e) {\t\ne.printStackTrace();\t\nthrow new MyServiceException("Message", e);\n}What check can detect:
Loggers
- logger is declared as class field
- logger is declared as method's local variable
- logger is declared as local variable in
catch block - logger is passed through method's parameters
Exceptions- logger logs
catch parameter exception or it's message - throw
catch parameter exception - throw another exception which is based on
catch parameter exception - printStackTrace was called on
catch parameter exception
What check can not detect:
- loggers that is used like method's return value. Example:
getLogger().error("message", e) - loggers that is used like static fields from another classes:
MyAnotherClass.LOGGER.error("message", e);
Default parameters are:
- loggerFullyQualifiedClassName - fully qualified class name of logger type. Default value is "org.slf4j.Logger".
- loggingMethodNames - comma separated names of logging methods. Default value is "error, warn, info, debug".
Note that check works with only one logger type. If you have multiple different loggers, then create another instance of this check.
EitherLogOrThrowCheck.name = Either log exception or throw exception.
EitherLogOrThrowCheck.loggerFullyQualifiedClassName = Logger fully qualified class name. Example: "org.slf4j.Logger".
-EitherLogOrThrowCheck.loggingMethodNames = Logging method names separated with commas. Example: "error,warn".
+EitherLogOrThrowCheck.loggingMethodNames = Logging method names separated with commas. Example: "error,warn".
WhitespaceBeforeArrayInitializerCheck.name = Whitespace Before Array Initializer
WhitespaceBeforeArrayInitializerCheck.desc = This checks enforces whitespace before array initializer.
diff --git a/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/coding/checkstyle-metadata.xml b/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/coding/checkstyle-metadata.xml
index fcba5c0679..f309c9162d 100644
--- a/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/coding/checkstyle-metadata.xml
+++ b/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/coding/checkstyle-metadata.xml
@@ -535,6 +535,13 @@
+
+
+ %SingleMethodTypeParameterCheck.desc
+
+
+
+
%WhitespaceBeforeArrayInitializerCheck.desc
diff --git a/sevntu-checks/sevntu-checks.xml b/sevntu-checks/sevntu-checks.xml
index bc40e129f3..5939dada86 100644
--- a/sevntu-checks/sevntu-checks.xml
+++ b/sevntu-checks/sevntu-checks.xml
@@ -142,6 +142,7 @@
+
diff --git a/sevntu-checks/src/main/java/com/github/sevntu/checkstyle/checks/coding/SingleMethodTypeParameterCheck.java b/sevntu-checks/src/main/java/com/github/sevntu/checkstyle/checks/coding/SingleMethodTypeParameterCheck.java
new file mode 100644
index 0000000000..0fbd0d7feb
--- /dev/null
+++ b/sevntu-checks/src/main/java/com/github/sevntu/checkstyle/checks/coding/SingleMethodTypeParameterCheck.java
@@ -0,0 +1,213 @@
+////////////////////////////////////////////////////////////////////////////////
+// checkstyle: Checks Java source code for adherence to a set of rules.
+// Copyright (C) 2001-2020 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.github.sevntu.checkstyle.checks.coding;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
+import com.puppycrawl.tools.checkstyle.api.DetailAST;
+import com.puppycrawl.tools.checkstyle.api.TokenTypes;
+
+/**
+ *
+ * This check restricts the use of type parameters. If a type parameter appears only once in a
+ * method declaration, it should be replaced with a wildcard. For more information read "Effective
+ * Java (3nd edition)", "Item 31: use bounded wildcards to increase API flexibility".
+ *
+ *
+ *
+ * For example:
+ *
+ *
+ * {@code
+ * public static void swap(List> list, int i, int j); // OK, using wildcards
+ * public static void swap(List list, int i, int j); // Violation, single type parameter
+ * }
+ *
+ *
+ * "Please note that there's one problem with the second declaration for swap. The straightforward
+ * implementation won't compile:"
+ *
+ *
+ * {@code
+ * public static void swap(List> list, int i, int j) {
+ * list.set(i, list.set(j, list.get(i)));
+ * }
+ * }
+ *
+ *
+ * Swap.java:5: error: incompatible types: Object cannot be converted to CAP#1
+ *
+ * {@code
+ * list.set(i, list.set(j, list.get(i)));
+ * }
+ *
+ *
+ * "It doesn't seem right that we can't put an element back into the list that we just took it out
+ * of. The problem is that the type of list is List{@code >}, and you can't put any value
+ * except null into a List{@code >}. Fortunately, there is a way to implement this method
+ * without resorting to an unsafe cast or a raw type. The idea is to write a private helper method
+ * to capture the wildcard type. The helper method must be a generic method in order to capture the
+ * type. Here's how it looks:"
+ *
+ *
+ * {@code
+ * public static void swap(List> list, int i, int j) {
+ * swapHelper(list, i, j);
+ * }
+ *
+ * // Private helper method for wildcard capture
+ * private static void swapHelper(List list, int i, int j) {
+ * list.set(i, list.set(j, list.get(i)));
+ * }
+ * }
+ *
+ *
+ * This check is only applicable to public methods.
+ *
+ *
+ *
+ * Limitation: this check does not identify methods which use both generics and wildcards in
+ * tandem.
+ *
+ *
+ * {@code
+ * public void copy(List dest, List src) // OK, no violation
+ * public void copy(List dest, List extends T> src); // OK, with wildcards
+ * }
+ *
+ * @author Yasser Aziza
+ * @since 1.38.0
+ */
+public class SingleMethodTypeParameterCheck extends AbstractCheck {
+
+ /**
+ * Warning message key.
+ */
+ public static final String MSG_KEY = "single.method.type.parameter";
+
+ @Override
+ public int[] getDefaultTokens() {
+ return new int[] {
+ TokenTypes.METHOD_DEF,
+ };
+ }
+
+ @Override
+ public int[] getAcceptableTokens() {
+ return getDefaultTokens();
+ }
+
+ @Override
+ public int[] getRequiredTokens() {
+ return getDefaultTokens();
+ }
+
+ @Override
+ public void visitToken(DetailAST ast) {
+ if (isPublicMethod(ast)) {
+ final List typeArguments = getTypeArguments(ast);
+
+ if (isSingleTypeParameter(typeArguments)) {
+ log(typeArguments.get(0), MSG_KEY);
+ }
+ }
+ }
+
+ /**
+ * Checks whether this method is public or not.
+ * @param ast the method node for the evaluation
+ * @return {@code true} if this method is public, {@code false} otherwise.
+ */
+ private static boolean isPublicMethod(DetailAST ast) {
+ final boolean isInterface =
+ ast.getParent().getParent().getType() == TokenTypes.INTERFACE_DEF;
+
+ final boolean hasPublicModifier = ast.findFirstToken(TokenTypes.MODIFIERS)
+ .findFirstToken(TokenTypes.LITERAL_PUBLIC) != null;
+
+ return isInterface || hasPublicModifier;
+ }
+
+ /**
+ * Checks if the given {@link DetailAST} {@link List} contains a single type parameter.
+ * @param astList {@link List} of the found {@link TokenTypes#TYPE_PARAMETER}
+ * @return {@code true} if the {@link List} contains only one non
+ * {@link TokenTypes#WILDCARD_TYPE} element, {@link false otherwise}.
+ */
+ private boolean isSingleTypeParameter(List astList) {
+ return astList.size() == 1
+ && astList.get(0).getType() != TokenTypes.WILDCARD_TYPE;
+ }
+
+ /**
+ * Returns all {@link TokenTypes#TYPE_ARGUMENTS} found in this method, expect
+ * {@link TokenTypes#WILDCARD_TYPE}.
+ * @param ast the method node for the evaluation
+ * @return {@link List} containing all {@link TokenTypes#TYPE_ARGUMENTS} found,
+ * {@code null} otherwise.
+ */
+ private static List getTypeArguments(DetailAST ast) {
+ final List typeParameters = new ArrayList<>();
+ DetailAST child = ast.findFirstToken(TokenTypes.PARAMETERS).getFirstChild();
+
+ while (child != null) {
+ if (child.getType() == TokenTypes.PARAMETER_DEF) {
+ final DetailAST type = child.findFirstToken(TokenTypes.TYPE);
+ if (type.findFirstToken(TokenTypes.TYPE_ARGUMENTS) != null) {
+ final DetailAST typeArgument = type.findFirstToken(TokenTypes.TYPE_ARGUMENTS)
+ .findFirstToken(TokenTypes.TYPE_ARGUMENT);
+ final DetailAST wildcard =
+ findFirstTokenByType(typeArgument, TokenTypes.WILDCARD_TYPE);
+
+ if (wildcard == null) {
+ typeParameters.add(type.findFirstToken(TokenTypes.TYPE_ARGUMENTS));
+ }
+ else {
+ typeParameters.add(wildcard);
+ }
+ }
+ }
+ child = child.getNextSibling();
+ }
+ return typeParameters;
+ }
+
+ /**
+ * Returns the first child token that has a specified type.
+ * @param ast the root node for the search
+ * @param type the token type to be find. Should be a constant from {@link TokenTypes}
+ * @return either the first token found, {@code null} otherwise.
+ */
+ private static DetailAST findFirstTokenByType(DetailAST ast, int type) {
+ DetailAST returnValue = null;
+
+ for (DetailAST node = ast.getFirstChild(); node != null; node = node.getNextSibling()) {
+ if (node.getType() == type) {
+ returnValue = node;
+ break;
+ }
+ }
+
+ return returnValue;
+ }
+
+}
diff --git a/sevntu-checks/src/main/resources/com/github/sevntu/checkstyle/checks/coding/messages.properties b/sevntu-checks/src/main/resources/com/github/sevntu/checkstyle/checks/coding/messages.properties
index 465f6cf02c..4e6b6ed856 100644
--- a/sevntu-checks/src/main/resources/com/github/sevntu/checkstyle/checks/coding/messages.properties
+++ b/sevntu-checks/src/main/resources/com/github/sevntu/checkstyle/checks/coding/messages.properties
@@ -73,6 +73,7 @@ return.count.extended.lambda=Return count for the lambda is {0} (max allowed is
return.count.extended.method=Return count for ''{0}'' method is {1} (max allowed is {2}).
return.null.Boolean=Method declares to return Boolean and returns null.
single.break.or.continue.in.loops=Loops should not contain more than a single "break" or "continue" statement
+single.method.type.parameter=Single type parameter should be replaced with a wildcard. Private helper method may be needed for wildcard capture in this case.
ternary.per.expression.count=More than {0} ternary operators in expression.
unnecessary.paren.assign=Unnecessary parentheses around assignment right-hand side.
unnecessary.paren.expr=Unnecessary parentheses around expression.
diff --git a/sevntu-checks/src/test/java/com/github/sevntu/checkstyle/checks/coding/SingleMethodTypeParameterCheckTest.java b/sevntu-checks/src/test/java/com/github/sevntu/checkstyle/checks/coding/SingleMethodTypeParameterCheckTest.java
new file mode 100644
index 0000000000..8f3c3cd3f6
--- /dev/null
+++ b/sevntu-checks/src/test/java/com/github/sevntu/checkstyle/checks/coding/SingleMethodTypeParameterCheckTest.java
@@ -0,0 +1,64 @@
+////////////////////////////////////////////////////////////////////////////////
+// checkstyle: Checks Java source code for adherence to a set of rules.
+// Copyright (C) 2001-2020 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.github.sevntu.checkstyle.checks.coding;
+
+import static com.github.sevntu.checkstyle.checks.coding.SingleMethodTypeParameterCheck.MSG_KEY;
+
+import org.junit.Test;
+
+import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
+import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
+
+/**
+ * @author Yasser Aziza
+ */
+public class SingleMethodTypeParameterCheckTest extends AbstractModuleTestSupport {
+
+ /**
+ * An error message for current check.
+ */
+ private final String warningMessage = getCheckMessage(MSG_KEY);
+
+ @Override
+ protected String getPackageLocation() {
+ return "com/github/sevntu/checkstyle/checks/coding";
+ }
+
+ @Test
+ public void testDefault() throws Exception {
+ final DefaultConfiguration checkConfig =
+ createModuleConfig(SingleMethodTypeParameterCheck.class);
+
+ final String[] expected = {
+ "11:32: " + warningMessage,
+ "13:34: " + warningMessage,
+ "28:44: " + warningMessage,
+ "30:46: " + warningMessage,
+ "32:66: " + warningMessage,
+ "42:40: " + warningMessage,
+ "46:48: " + warningMessage,
+ "50:48: " + warningMessage,
+ "52:43: " + warningMessage,
+ };
+
+ verify(checkConfig, getPath("InputSingleMethodTypeParameterCheck.java"), expected);
+ }
+
+}
diff --git a/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputSingleMethodTypeParameterCheck.java b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputSingleMethodTypeParameterCheck.java
new file mode 100644
index 0000000000..420bd7e876
--- /dev/null
+++ b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputSingleMethodTypeParameterCheck.java
@@ -0,0 +1,58 @@
+package com.github.sevntu.checkstyle.checks.coding;
+
+import java.util.List;
+import java.util.Map;
+
+public abstract class InputSingleMethodTypeParameterCheck {
+
+ public interface A {
+ void complaint(List> list, int i, int j);
+
+ void violation(List list, int i, int j);
+
+ void violation(Map map, int i, int j);
+
+ void complaint(int key, Map,?> map, int value);
+
+ void complaint(List first, List second, int i, int j);
+ }
+
+ protected abstract void complaint(List list, int i, int j);
+
+ abstract void complaint(Map map, int i, int j);
+
+ abstract void complaint(int key, Map,?> map, int value);
+
+ abstract void complaint(List first, List second, int i, int j);
+
+ public abstract void violation(List list, int i, int j);
+
+ public abstract void violation(Map map, int i, int j);
+
+ public abstract > void violation(List list, int i);
+
+ public abstract void complaint(List extends Comparable> list, int i);
+
+ public abstract > void complaint(List first, List second);
+
+ public abstract void complaint(int i, int j);
+
+ public abstract void complaint();
+
+ public abstract void violation(List modules);
+
+ public abstract List> complaint(List> modules, String string);
+
+ public abstract List violation(List modules, String string);
+
+ public abstract List complaint(List> modules);
+
+ public abstract List violation(List> modules, int i, String names);
+
+ public abstract void violation(Map map);
+
+ public abstract void complaint(List dest, List extends T> src, String str);
+
+ public abstract void complaint(List dest, List src, int i);
+
+}
diff --git a/sevntu-checkstyle-sonar-plugin/src/main/resources/com/github/sevntu/checkstyle/sonar/checkstyle-extensions.xml b/sevntu-checkstyle-sonar-plugin/src/main/resources/com/github/sevntu/checkstyle/sonar/checkstyle-extensions.xml
index 53ef2ae7dd..594d896485 100644
--- a/sevntu-checkstyle-sonar-plugin/src/main/resources/com/github/sevntu/checkstyle/sonar/checkstyle-extensions.xml
+++ b/sevntu-checkstyle-sonar-plugin/src/main/resources/com/github/sevntu/checkstyle/sonar/checkstyle-extensions.xml
@@ -712,6 +712,14 @@
Checker/TreeWalker/com.github.sevntu.checkstyle.checks.coding.SingleBreakOrContinueCheck
+
+ com.github.sevntu.checkstyle.checks.coding.SingleMethodTypeParameterCheck
+ Single type parameter in public methods
+ coding
+ Single type parameter in public methods should be replaced with a wildcard.
+ Checker/TreeWalker/com.github.sevntu.checkstyle.checks.coding.SingleMethodTypeParameterCheck
+
+
com.github.sevntu.checkstyle.checks.coding.TernaryPerExpressionCountCheck
Ternary Per Expression Count
diff --git a/sevntu-checkstyle-sonar-plugin/src/test/java/com/github/sevntu/checkstyle/sonar/CheckstyleExtensionRulesDefinitionTest.java b/sevntu-checkstyle-sonar-plugin/src/test/java/com/github/sevntu/checkstyle/sonar/CheckstyleExtensionRulesDefinitionTest.java
index 332e3b77b2..969e3844ef 100644
--- a/sevntu-checkstyle-sonar-plugin/src/test/java/com/github/sevntu/checkstyle/sonar/CheckstyleExtensionRulesDefinitionTest.java
+++ b/sevntu-checkstyle-sonar-plugin/src/test/java/com/github/sevntu/checkstyle/sonar/CheckstyleExtensionRulesDefinitionTest.java
@@ -40,7 +40,7 @@ public void testAllRulesValid() {
Assert.assertEquals("Incorrect repository language", "java", repository.language());
final List rules = repository.rules();
- Assert.assertEquals("Incorrect number of loaded rules", 59, rules.size());
+ Assert.assertEquals("Incorrect number of loaded rules", 60, rules.size());
for (RulesDefinition.Rule rule : rules) {
Assert.assertNotNull("Rule key is not set", rule.key());