[java] Move rule SignatureDeclareThrowsException from typeresolution to strictexception

Replace existing rule with the typeresolution-based implementation.
This commit is contained in:
Andreas Dangel
2017-10-13 14:04:27 +02:00
parent 8470d32322
commit 944b2f448b
11 changed files with 224 additions and 430 deletions

View File

@ -180,6 +180,10 @@ Notice this last scenario is slightly different to the Java syntax. This is due
* The rule `UnusedImports` (ruleset `java-imports`) has been replaced by the typeresolution-based
implementation and is now able to detect unused on-demand imports.
* The rule `SignatureDeclareThrowsException` (ruleset 'java-strictexception') has been replaced by the
typeresolution-based implementation. It has a new property `IgnoreJUnitCompletely`, which allows all
methods in a JUnit testcase to throws exceptions.
#### Deprecated Rules
* The rules `NcssConstructorCount`, `NcssMethodCount`, and `NcssTypeCount` (ruleset `java-codesize`) have been
@ -194,6 +198,9 @@ Notice this last scenario is slightly different to the Java syntax. This is due
* The rule `UnusedImports` in ruleset `java-typeresolution` is deprecated. Use the rule with
the same name from ruleset `java-imports` instead.
* The rule `SignatureDeclareThrowsException` in ruleset `java-typeresolution` is deprecated. Use the rule
with the same name from ruleset `java-strictexception` instead.
#### Removed Rules
* The deprecated rule `UseSingleton` has been removed from the ruleset `java-design`. The rule has been renamed

View File

@ -74,6 +74,7 @@ public class RuleSetFactoryCompatibility {
addFilterRuleMoved("java", "typeresolution", "coupling", "LooseCoupling");
addFilterRuleMoved("java", "typeresolution", "clone", "CloneMethodMustImplementCloneable");
addFilterRuleMoved("java", "typeresolution", "imports", "UnusedImports");
addFilterRuleMoved("java", "typeresolution", "strictexception", "SignatureDeclareThrowsException");
}
void addFilterRuleRenamed(String language, String ruleset, String oldName, String newName) {

View File

@ -9,15 +9,27 @@ import java.util.List;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTAnnotation;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTExtendsList;
import net.sourceforge.pmd.lang.java.ast.ASTImplementsList;
import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
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.properties.BooleanProperty;
/**
* A method/constructor shouldn't explicitly throw java.lang.Exception, since it
* is unclear which exceptions that can be thrown from the methods. It might be
* difficult to document and understand such vague interfaces. Use either a class
* derived from RuntimeException or a checked exception.
*
* <p>This rule uses PMD's type resolution facilities, and can detect
* if the class implements or extends TestCase class
*
* @author <a href="mailto:trondandersen@c2i.net">Trond Andersen</a>
* @version 1.0
@ -26,7 +38,15 @@ import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
public class SignatureDeclareThrowsExceptionRule extends AbstractJavaRule {
private boolean junitImported;
private static final BooleanProperty IGNORE_JUNIT_COMPLETELY_DESCRIPTOR = new BooleanProperty(
"IgnoreJUnitCompletely", "Allow all methods in a JUnit testcase to throw Exceptions", false, 1.0f);
// Set to true when the class is determined to be a JUnit testcase
private boolean junitImported = false;
public SignatureDeclareThrowsExceptionRule() {
definePropertyDescriptor(IGNORE_JUNIT_COMPLETELY_DESCRIPTOR);
}
@Override
public Object visit(ASTCompilationUnit node, Object o) {
@ -34,6 +54,64 @@ public class SignatureDeclareThrowsExceptionRule extends AbstractJavaRule {
return super.visit(node, o);
}
@Override
public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
if (junitImported) {
return super.visit(node, data);
}
ASTImplementsList impl = node.getFirstChildOfType(ASTImplementsList.class);
if (impl != null && impl.jjtGetParent().equals(node)) {
for (int ix = 0; ix < impl.jjtGetNumChildren(); ix++) {
Node child = impl.jjtGetChild(ix);
if (child.getClass() != ASTClassOrInterfaceType.class) {
continue;
}
ASTClassOrInterfaceType type = (ASTClassOrInterfaceType) child;
if (isJUnitTest(type)) {
junitImported = true;
return super.visit(node, data);
}
}
}
if (node.jjtGetNumChildren() != 0 && node.jjtGetChild(0) instanceof ASTExtendsList) {
ASTClassOrInterfaceType type = (ASTClassOrInterfaceType) node.jjtGetChild(0).jjtGetChild(0);
if (isJUnitTest(type)) {
junitImported = true;
return super.visit(node, data);
}
}
return super.visit(node, data);
}
private boolean isJUnitTest(ASTClassOrInterfaceType type) {
Class<?> clazz = type.getType();
if (clazz == null) {
if ("junit.framework.Test".equals(type.getImage())) {
return true;
}
} else if (isJUnitTest(clazz)) {
return true;
} else {
while (clazz != null && !Object.class.equals(clazz)) {
for (Class<?> intf : clazz.getInterfaces()) {
if (isJUnitTest(intf)) {
return true;
}
}
clazz = clazz.getSuperclass();
}
}
return false;
}
private boolean isJUnitTest(Class<?> clazz) {
return clazz.getName().equals("junit.framework.Test");
}
@Override
public Object visit(ASTImportDeclaration node, Object o) {
if (node.getImportedName().indexOf("junit") != -1) {
@ -44,8 +122,7 @@ public class SignatureDeclareThrowsExceptionRule extends AbstractJavaRule {
@Override
public Object visit(ASTMethodDeclaration methodDeclaration, Object o) {
if ((methodDeclaration.getMethodName().equals("setUp") || methodDeclaration.getMethodName().equals("tearDown"))
&& junitImported) {
if (junitImported && isAllowedMethod(methodDeclaration)) {
return super.visit(methodDeclaration, o);
}
@ -62,24 +139,39 @@ public class SignatureDeclareThrowsExceptionRule extends AbstractJavaRule {
}
}
checkExceptions(methodDeclaration, o);
return super.visit(methodDeclaration, o);
}
private boolean isAllowedMethod(ASTMethodDeclaration methodDeclaration) {
if (getProperty(IGNORE_JUNIT_COMPLETELY_DESCRIPTOR)) {
return true;
} else {
return methodDeclaration.getMethodName().equals("setUp")
|| methodDeclaration.getMethodName().equals("tearDown");
}
}
@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<ASTName> exceptionList = Collections.emptyList();
ASTNameList nameList = methodDeclaration.getFirstChildOfType(ASTNameList.class);
ASTNameList nameList = method.getFirstChildOfType(ASTNameList.class);
if (nameList != null) {
exceptionList = nameList.findDescendantsOfType(ASTName.class);
}
if (!exceptionList.isEmpty()) {
evaluateExceptions(exceptionList, o);
}
return super.visit(methodDeclaration, o);
}
@Override
public Object visit(ASTConstructorDeclaration constructorDeclaration, Object o) {
List<ASTName> exceptionList = constructorDeclaration.findDescendantsOfType(ASTName.class);
if (!exceptionList.isEmpty()) {
evaluateExceptions(exceptionList, o);
}
return super.visit(constructorDeclaration, o);
}
/**

View File

@ -1,195 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.typeresolution.rules;
import java.util.List;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTAnnotation;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTExtendsList;
import net.sourceforge.pmd.lang.java.ast.ASTImplementsList;
import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTName;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.properties.BooleanProperty;
/**
* A method/constructor shouldn't explicitly throw java.lang.Exception, since it
* is unclear which exceptions that can be thrown from the methods. It might be
* difficult to document and understand the vague interfaces. Use either a class
* derived from RuntimeException or a checked exception. This version uses PMD's
* type resolution facilities, and can detect if the class implements or extends
* TestCase class
*
* @author <a href="mailto:trondandersen@c2i.net">Trond Andersen</a>
* @author acaplan
* @author Wouter Zelle
*/
public class SignatureDeclareThrowsException extends AbstractJavaRule {
private static final BooleanProperty IGNORE_JUNIT_COMPLETELY_DESCRIPTOR = new BooleanProperty(
"IgnoreJUnitCompletely", "Allow all methods in a JUnit testcase to throw Exceptions", false, 1.0f);
// Set to true when the class is determined to be a JUnit testcase
private boolean junitImported = false;
public SignatureDeclareThrowsException() {
definePropertyDescriptor(IGNORE_JUNIT_COMPLETELY_DESCRIPTOR);
}
@Override
public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
if (junitImported) {
return super.visit(node, data);
}
ASTImplementsList impl = node.getFirstChildOfType(ASTImplementsList.class);
if (impl != null && impl.jjtGetParent().equals(node)) {
for (int ix = 0; ix < impl.jjtGetNumChildren(); ix++) {
Node child = impl.jjtGetChild(ix);
if (child.getClass() != ASTClassOrInterfaceType.class) {
continue;
}
ASTClassOrInterfaceType type = (ASTClassOrInterfaceType) child;
if (isJUnitTest(type)) {
junitImported = true;
return super.visit(node, data);
}
}
}
if (node.jjtGetNumChildren() != 0 && node.jjtGetChild(0) instanceof ASTExtendsList) {
ASTClassOrInterfaceType type = (ASTClassOrInterfaceType) node.jjtGetChild(0).jjtGetChild(0);
if (isJUnitTest(type)) {
junitImported = true;
return super.visit(node, data);
}
}
return super.visit(node, data);
}
private boolean isJUnitTest(ASTClassOrInterfaceType type) {
Class<?> clazz = type.getType();
if (clazz == null) {
if ("junit.framework.Test".equals(type.getImage())) {
return true;
}
} else if (isJUnitTest(clazz)) {
return true;
} else {
while (clazz != null && !Object.class.equals(clazz)) {
for (Class<?> intf : clazz.getInterfaces()) {
if (isJUnitTest(intf)) {
return true;
}
}
clazz = clazz.getSuperclass();
}
}
return false;
}
private boolean isJUnitTest(Class<?> clazz) {
return clazz.getName().equals("junit.framework.Test");
}
@Override
public Object visit(ASTImportDeclaration node, Object o) {
if (node.getImportedName().indexOf("junit") != -1) {
junitImported = true;
}
return super.visit(node, o);
}
@Override
public Object visit(ASTMethodDeclaration methodDeclaration, Object o) {
if (junitImported && isAllowedMethod(methodDeclaration)) {
return super.visit(methodDeclaration, o);
}
// Ignore overridden methods, the issue should be marked on the method definition
final List<ASTAnnotation> methodAnnotations = methodDeclaration.jjtGetParent().findChildrenOfType(ASTAnnotation.class);
for (final ASTAnnotation annotation : methodAnnotations) {
final ASTName annotationName = annotation.getFirstDescendantOfType(ASTName.class);
if (annotationName.hasImageEqualTo("Override") || annotationName.hasImageEqualTo("java.lang.Override")) {
return super.visit(methodDeclaration, o);
}
}
checkExceptions(methodDeclaration, o);
return super.visit(methodDeclaration, o);
}
private boolean isAllowedMethod(ASTMethodDeclaration methodDeclaration) {
if (getProperty(IGNORE_JUNIT_COMPLETELY_DESCRIPTOR)) {
return true;
} else {
return methodDeclaration.getMethodName().equals("setUp")
|| methodDeclaration.getMethodName().equals("tearDown");
}
}
@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<ASTName> exceptionList = method.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<ASTName> exceptionList, Object context) {
for (ASTName exception : exceptionList) {
if (hasDeclaredExceptionInSignature(exception)) {
addViolation(context, exception);
}
}
}
/**
* Checks if the given value is defined as <code>Exception</code> and the
* parent is either a method or constructor declaration.
*
* @param exception
* to evaluate
* @return true if <code>Exception</code> is declared and has proper parents
*/
private boolean hasDeclaredExceptionInSignature(ASTName exception) {
return exception.hasImageEqualTo("Exception") && isParentSignatureDeclaration(exception);
}
/**
* @param exception
* to evaluate
* @return true if parent node is either a method or constructor declaration
*/
private boolean isParentSignatureDeclaration(ASTName exception) {
Node parent = exception.jjtGetParent().jjtGetParent();
return parent instanceof ASTMethodDeclaration || parent instanceof ASTConstructorDeclaration;
}
}

View File

@ -33,12 +33,15 @@ public void bar() {
<rule name="SignatureDeclareThrowsException"
since="1.2"
message="A method/constructor shouldn't explicitly throw java.lang.Exception"
message="A method/constructor should not explicitly throw java.lang.Exception"
class="net.sourceforge.pmd.lang.java.rule.strictexception.SignatureDeclareThrowsExceptionRule"
typeResolution="true"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_strictexception.html#signaturedeclarethrowsexception">
<description>
Methods that declare the generic Exception as a possible throwable are not very helpful since their
failure modes are unclear. Use a class derived from RuntimeException or a more specific checked exception.
A method/constructor shouldn't explicitly throw the generic java.lang.Exception, since it
is unclear which exceptions that can be thrown from the methods. It might be
difficult to document and understand such vague interfaces. Use either a class
derived from RuntimeException or a checked exception.
</description>
<priority>3</priority>
<example>

View File

@ -6,37 +6,13 @@
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
<description>
These are rules which resolve java Class files for comparison, as opposed to a String
All rules in this ruleset have been moved to other rulesets. Please use the other rules
directly and don't use this ruleset anymore.
</description>
<rule ref="java-coupling/LooseCoupling" deprecated="true" />
<rule ref="java-clone/CloneMethodMustImplementCloneable" deprecated="true" />
<rule ref="java-imports/UnusedImports" deprecated="true" />
<rule name="SignatureDeclareThrowsException"
since="4.0"
message="A method/constructor shouldn't explicitly throw java.lang.Exception"
class="net.sourceforge.pmd.lang.java.typeresolution.rules.SignatureDeclareThrowsException"
typeResolution="true"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_typeresolution.html#signaturedeclarethrowsexception">
<description>
It is unclear which exceptions that can be thrown from the methods.
It might be difficult to document and understand the vague interfaces.
Use either a class derived from RuntimeException or a checked exception.
JUnit classes are excluded.
</description>
<priority>3</priority>
<properties>
<property description="If true, all methods in a JUnit testcase may throw Exception"
name="IgnoreJUnitCompletely" value="false"/>
</properties>
<example>
<![CDATA[
public void methodThrowingException() throws Exception {
}
]]>
</example>
</rule>
<rule ref="java-strictexception/SignatureDeclareThrowsException" deprecated="true" />
</ruleset>

View File

@ -2,7 +2,7 @@
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.rule.typeresolution.xml;
package net.sourceforge.pmd.lang.java.rule.strictexception;
/**
* Warning, this class ARE not useless. It is used by the some of regression

View File

@ -2,7 +2,7 @@
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.rule.typeresolution.xml;
package net.sourceforge.pmd.lang.java.rule.strictexception;
import org.junit.Ignore;
@ -12,10 +12,8 @@ import junit.framework.TestCase;
* Warning, this class IS NOT useless. It is used by the some regression tests.
*
* See file: SignatureDeclareThrowsException.xml
*
* The file is already excluded from maven/surefire.
*/
@Ignore
@Ignore("not a test case")
public class MyTestCase extends TestCase {
}

View File

@ -1,17 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.rule.typeresolution;
import net.sourceforge.pmd.testframework.SimpleAggregatorTst;
public class SignatureDeclareThrowsExceptionTest extends SimpleAggregatorTst {
private static final String RULESET = "java-typeresolution";
@Override
public void setUp() {
addRule(RULESET, "SignatureDeclareThrowsException");
}
}

View File

@ -62,6 +62,104 @@ public class Foo {
</test-code>
<test-code>
<description><![CDATA[
JUnit 4 testcase
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import org.junit.*;
public class Foo {
@Before
void setUp() throws Exception {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
skip method in class that extends TestCase
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import junit.framework.*;
public class Foo extends TestCase {
void setUp() throws Exception {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
Don't skip other methods
]]></description>
<expected-problems>1</expected-problems>
<code><![CDATA[
import junit.framework.*;
public class Foo extends TestCase {
void bar() throws Exception {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
Unless
]]></description>
<rule-property name="IgnoreJUnitCompletely">true</rule-property>
<expected-problems>0</expected-problems>
<code><![CDATA[
import junit.framework.*;
public class Foo extends TestCase {
void bar() throws Exception {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
skip junit setUp method where the superclass is TestCase
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo extends net.sourceforge.pmd.lang.java.rule.strictexception.MyTestCase {
void setUp() throws Exception {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
skip junit setUp method where the superclass is TestCase, imported explicitly
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import net.sourceforge.pmd.lang.java.rule.strictexception.MyTestCase;
public class Foo extends MyTestCase {
void setUp() throws Exception {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
skip junit setUp method where the superclass is TestCase, but is imported implicitly
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import net.sourceforge.pmd.lang.java.rule.strictexception.*;
public class Foo extends MyTestCase {
void setUp() throws Exception {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
skip junit setUp method where the superclass is TestCase and is in the same package
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
package net.sourceforge.pmd.lang.java.rule.strictexception;
public class Foo extends MyTestCase {
void setUp() throws Exception {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
Generics
]]></description>
<expected-problems>0</expected-problems>

View File

@ -1,169 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<test-data
xmlns="http://pmd.sourceforge.net/rule-tests"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd">
<test-code>
<description><![CDATA[
method throws Exception
]]></description>
<expected-problems>1</expected-problems>
<code><![CDATA[
public class Foo {
void foo() throws Exception {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
ok
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo {
void foo() {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
constructor throws Exception
]]></description>
<expected-problems>1</expected-problems>
<code><![CDATA[
public class Foo {
Foo() throws Exception {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
JUnit 4 testcase
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import org.junit.*;
public class Foo {
@Before
void setUp() throws Exception {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
skip method in class that extends TestCase
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import junit.framework.*;
public class Foo extends TestCase {
void setUp() throws Exception {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
Don't skip other methods
]]></description>
<expected-problems>1</expected-problems>
<code><![CDATA[
import junit.framework.*;
public class Foo extends TestCase {
void bar() throws Exception {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
Unless
]]></description>
<rule-property name="IgnoreJUnitCompletely">true</rule-property>
<expected-problems>0</expected-problems>
<code><![CDATA[
import junit.framework.*;
public class Foo extends TestCase {
void bar() throws Exception {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
skip junit setUp method where the superclass is TestCase
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo extends net.sourceforge.pmd.lang.java.rule.typeresolution.xml.MyTestCase {
void setUp() throws Exception {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
skip junit setUp method where the superclass is TestCase, imported explicitly
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import net.sourceforge.pmd.lang.java.rule.typeresolution.xml.MyTestCase;
public class Foo extends MyTestCase {
void setUp() throws Exception {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
skip junit setUp method where the superclass is TestCase, but is imported implicitly
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import net.sourceforge.pmd.lang.java.rule.typeresolution.xml.*;
public class Foo extends MyTestCase {
void setUp() throws Exception {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
skip junit setUp method where the superclass is TestCase and is in the same package
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
package net.sourceforge.pmd.lang.java.rule.typeresolution.xml;
public class Foo extends MyTestCase {
void setUp() throws Exception {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
Generics
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo {
public <T> Bar<T> foo() { /* blah */}
}
]]></code>
<source-type>java 1.5</source-type>
</test-code>
<test-code>
<description>#1535 [java] SignatureDeclareThrowsException: ClassCastException with Annotation</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class UnmodifiableList<T> implements @Readonly List<@Readonly T> {}
]]></code>
</test-code>
<test-code>
<description>#350 allow throws exception when overriding a method defined elsewhere</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class BugSignature implements LousyInterface {
@Override
public void record() throws Exception {
}
}
]]></code>
</test-code>
</test-data>