From 31a8156b4f6b2a382cd19cacade4f47b9a05818b Mon Sep 17 00:00:00 2001 From: Bhanu Date: Thu, 28 Feb 2019 19:30:56 -0600 Subject: [PATCH] Added signature declare throws runtime exception --- docs/pages/pmd/rules/java.md | 1 + docs/pages/pmd/rules/java/design.md | 24 +++++- ...tureDeclareThrowsRuntimeExceptionRule.java | 81 +++++++++++++++++++ .../main/resources/category/java/design.xml | 18 +++++ ...tureDeclareThrowsRuntimeExceptionTest.java | 11 +++ 5 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SignatureDeclareThrowsRuntimeExceptionRule.java create mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/SignatureDeclareThrowsRuntimeExceptionTest.java diff --git a/docs/pages/pmd/rules/java.md b/docs/pages/pmd/rules/java.md index eea3a593fd..2e0c0f89b5 100644 --- a/docs/pages/pmd/rules/java.md +++ b/docs/pages/pmd/rules/java.md @@ -161,6 +161,7 @@ folder: pmd/rules * [NcssTypeCount](pmd_rules_java_design.html#ncsstypecount): Deprecated This rule uses the NCSS (Non-Commenting Source Statements) algorithm to determine the number of l... * [NPathComplexity](pmd_rules_java_design.html#npathcomplexity): The NPath complexity of a method is the number of acyclic execution paths through that method.Whi... * [SignatureDeclareThrowsException](pmd_rules_java_design.html#signaturedeclarethrowsexception): A method/constructor shouldn't explicitly throw the generic java.lang.Exception, since itis uncle... +* [SignatureDeclareThrowsRuntimeException](pmd_rules_java_design.html#signaturedeclarethrowsruntimeexception): A method/constructor should not explicitly declare java.lang.RuntimeException or it's subclasses ... * [SimplifiedTernary](pmd_rules_java_design.html#simplifiedternary): Look for ternary operators with the form 'condition ? literalBoolean : foo'or 'condition ? foo : ... * [SimplifyBooleanAssertion](pmd_rules_java_design.html#simplifybooleanassertion): Avoid negation in an assertTrue or assertFalse test.For example, rephrase: assertTrue(!expr);a... * [SimplifyBooleanExpressions](pmd_rules_java_design.html#simplifybooleanexpressions): Avoid unnecessary comparisons in boolean expressions, they serve no purpose and impacts readability. diff --git a/docs/pages/pmd/rules/java/design.md b/docs/pages/pmd/rules/java/design.md index 3f9254ba7d..7f5112df3a 100644 --- a/docs/pages/pmd/rules/java/design.md +++ b/docs/pages/pmd/rules/java/design.md @@ -5,7 +5,7 @@ permalink: pmd_rules_java_design.html folder: pmd/rules/java sidebaractiveurl: /pmd_rules_java.html editmepath: ../pmd-java/src/main/resources/category/java/design.xml -keywords: Design, AbstractClassWithoutAnyMethod, AvoidCatchingGenericException, AvoidDeeplyNestedIfStmts, AvoidRethrowingException, AvoidThrowingNewInstanceOfSameException, AvoidThrowingNullPointerException, AvoidThrowingRawExceptionTypes, ClassWithOnlyPrivateConstructorsShouldBeFinal, CollapsibleIfStatements, CouplingBetweenObjects, CyclomaticComplexity, DataClass, DoNotExtendJavaLangError, ExceptionAsFlowControl, ExcessiveClassLength, ExcessiveImports, ExcessiveMethodLength, ExcessiveParameterList, ExcessivePublicCount, FinalFieldCouldBeStatic, GodClass, ImmutableField, LawOfDemeter, LogicInversion, LoosePackageCoupling, ModifiedCyclomaticComplexity, NcssConstructorCount, NcssCount, NcssMethodCount, NcssTypeCount, NPathComplexity, SignatureDeclareThrowsException, SimplifiedTernary, SimplifyBooleanAssertion, SimplifyBooleanExpressions, SimplifyBooleanReturns, SimplifyConditional, SingularField, StdCyclomaticComplexity, SwitchDensity, TooManyFields, TooManyMethods, UselessOverridingMethod, UseObjectForClearerAPI, UseUtilityClass +keywords: Design, AbstractClassWithoutAnyMethod, AvoidCatchingGenericException, AvoidDeeplyNestedIfStmts, AvoidRethrowingException, AvoidThrowingNewInstanceOfSameException, AvoidThrowingNullPointerException, AvoidThrowingRawExceptionTypes, ClassWithOnlyPrivateConstructorsShouldBeFinal, CollapsibleIfStatements, CouplingBetweenObjects, CyclomaticComplexity, DataClass, DoNotExtendJavaLangError, ExceptionAsFlowControl, ExcessiveClassLength, ExcessiveImports, ExcessiveMethodLength, ExcessiveParameterList, ExcessivePublicCount, FinalFieldCouldBeStatic, GodClass, ImmutableField, LawOfDemeter, LogicInversion, LoosePackageCoupling, ModifiedCyclomaticComplexity, NcssConstructorCount, NcssCount, NcssMethodCount, NcssTypeCount, NPathComplexity, SignatureDeclareThrowsException, SignatureDeclareThrowsRuntimeException, SimplifiedTernary, SimplifyBooleanAssertion, SimplifyBooleanExpressions, SimplifyBooleanReturns, SimplifyConditional, SingularField, StdCyclomaticComplexity, SwitchDensity, TooManyFields, TooManyMethods, UselessOverridingMethod, UseObjectForClearerAPI, UseUtilityClass language: Java --- @@ -1343,6 +1343,28 @@ public void foo() throws Exception { ``` +## SignatureDeclareThrowsRuntimeException + +**Since:** PMD 1.2 + +**Priority:** Medium (3) + +A method/constructor should not explicitly declare java.lang.RuntimeException or it's subclasses in throws clause of it's signature, since it is advised to avoid declaring unchecked exceptions in method signature. + +**This rule is defined by the following Java class:** [net.sourceforge.pmd.lang.java.rule.design.SignatureDeclareThrowsRuntimeExceptionRule](https://github.com/pmd/pmd/blob/master/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SignatureDeclareThrowsRuntimeExceptionRule.java) + +**Example(s):** + +``` java +public void foo() throws RuntimeException { +} +``` + +**Use this rule by referencing it:** +``` xml + +``` + ## SimplifiedTernary **Since:** PMD 5.4.0 diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SignatureDeclareThrowsRuntimeExceptionRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SignatureDeclareThrowsRuntimeExceptionRule.java new file mode 100644 index 0000000000..0680c45919 --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SignatureDeclareThrowsRuntimeExceptionRule.java @@ -0,0 +1,81 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.design; + +import java.util.Collections; +import java.util.List; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTName; +import net.sourceforge.pmd.lang.java.ast.ASTNameList; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; + +/** + * A method/constructor should not explicitly declare java.lang.RuntimeException or + * it's subclasses in throws clause of it's signature, since it is advised to avoid + * declaring unchecked exceptions in method signature. + * + * @author Bhanu Prakash Pamidi + */ +public class SignatureDeclareThrowsRuntimeExceptionRule extends AbstractJavaRule { + + @Override + public Object visit(ASTMethodDeclaration methodDeclaration, Object o) { + checkExceptions(methodDeclaration, o); + return super.visit(methodDeclaration, o); + } + + + @Override + public Object visit(ASTConstructorDeclaration constructorDeclaration, Object o) { + checkExceptions(constructorDeclaration, o); + return super.visit(constructorDeclaration, o); + } + + /** + * Search the list of thrown exceptions for Exception + */ + private void checkExceptions(Node method, Object o) { + List exceptionList = Collections.emptyList(); + ASTNameList nameList = method.getFirstChildOfType(ASTNameList.class); + if (nameList != null) { + exceptionList = nameList.findDescendantsOfType(ASTName.class); + } + if (!exceptionList.isEmpty()) { + evaluateExceptions(exceptionList, o); + } + } + + /** + * Checks all exceptions for possible violation on the exception + * declaration. + * + * @param exceptionList + * containing all exception for declaration + * @param context + */ + private void evaluateExceptions(List exceptionList, Object context) { + for (ASTName exception : exceptionList) { + if (hasDeclaredRunTimeExceptionInSignature(exception)) { + addViolation(context, exception); + } + } + } + + /** + * Checks if the given value is defined as Exception and the + * parent is either a method or constructor declaration. + * + * @param exception + * to evaluate + * @return true if Exception is declared and has proper parents + */ + private boolean hasDeclaredRunTimeExceptionInSignature(ASTName exception) { + return exception.getType() != null && TypeHelper.isA(exception, RuntimeException.class); + } +} diff --git a/pmd-java/src/main/resources/category/java/design.xml b/pmd-java/src/main/resources/category/java/design.xml index 25062f3eb1..26eb6e2322 100644 --- a/pmd-java/src/main/resources/category/java/design.xml +++ b/pmd-java/src/main/resources/category/java/design.xml @@ -1136,6 +1136,24 @@ derived from RuntimeException or a checked exception. + + + + + +A method/constructor should not explicitly declare java.lang.RuntimeException or it's subclasses in throws clause of it's signature, since it is advised to avoid declaring unchecked exceptions in method signature. + + 3 + + diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/SignatureDeclareThrowsRuntimeExceptionTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/SignatureDeclareThrowsRuntimeExceptionTest.java new file mode 100644 index 0000000000..9acdac1f31 --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/SignatureDeclareThrowsRuntimeExceptionTest.java @@ -0,0 +1,11 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.design; + +import net.sourceforge.pmd.testframework.PmdRuleTst; + +public class SignatureDeclareThrowsRuntimeExceptionTest extends PmdRuleTst { + // no additional unit tests +}