diff --git a/pmd/etc/changelog.txt b/pmd/etc/changelog.txt
index 2825797bb0..c33fb61ba9 100644
--- a/pmd/etc/changelog.txt
+++ b/pmd/etc/changelog.txt
@@ -1,3 +1,6 @@
+????, 2004 - 1.8:
+New rule: ExceptionAsFlowControlRule
+
April 22, 2004 - 1.7:
Moved development environment to Maven 1.0-RC2.
Fixed bug 925840 - Messages were no longer getting variable names plugged in correctly
@@ -7,7 +10,7 @@ Implemented RFE 925839 - Added some more detail to the UseSingletonRule.
Added an optional 'failuresPropertyName' attribute to the Ant task.
Refactored away duplicate copies of XPath rule definitions in regress/, yay!
Removed manifest from jar file; it was only there for the Main-class attribute, and it's not very useful now since PMD has several dependencies.
-
+
March 15, 2004 - 1.6:
Fixed bug 895661 - XML reports containing error elements no longer have malformed XML.
Fixed a bug in UnconditionalIfStatement - it no longer flags things like "if (x==true)".
diff --git a/pmd/regress/test/net/sourceforge/pmd/rules/design/ExceptionAsFlowControlRuleTest.java b/pmd/regress/test/net/sourceforge/pmd/rules/design/ExceptionAsFlowControlRuleTest.java
new file mode 100644
index 0000000000..a7085e243b
--- /dev/null
+++ b/pmd/regress/test/net/sourceforge/pmd/rules/design/ExceptionAsFlowControlRuleTest.java
@@ -0,0 +1,39 @@
+package test.net.sourceforge.pmd.rules.design;
+
+import test.net.sourceforge.pmd.testframework.SimpleAggregatorTst;
+import test.net.sourceforge.pmd.testframework.TestDescriptor;
+import net.sourceforge.pmd.rules.design.NullAssignmentRule;
+import net.sourceforge.pmd.rules.design.ExceptionAsFlowControlRule;
+import net.sourceforge.pmd.PMD;
+
+public class ExceptionAsFlowControlRuleTest extends SimpleAggregatorTst {
+
+ public void testAll() {
+ runTests(new TestDescriptor[] {
+ new TestDescriptor(TEST1, "failure case", 1, new ExceptionAsFlowControlRule()),
+ new TestDescriptor(TEST2, "normal throw catch", 0, new ExceptionAsFlowControlRule())
+ });
+ }
+
+ private static final String TEST1 =
+ "public class Foo {" + PMD.EOL +
+ " void bar() {" + PMD.EOL +
+ " try {" + PMD.EOL +
+ " try {" + PMD.EOL +
+ " } catch (Exception e) {" + PMD.EOL +
+ " throw new WrapperException(e);" + PMD.EOL +
+ " // this is essentially a GOTO to the WrapperException catch block" + PMD.EOL +
+ " }" + PMD.EOL +
+ " } catch (WrapperException e) {" + PMD.EOL +
+ " // do some more stuff " + PMD.EOL +
+ " }" + PMD.EOL +
+ " }" + PMD.EOL +
+ "}";
+
+ private static final String TEST2 =
+ "public class Foo {" + PMD.EOL +
+ " void bar() {" + PMD.EOL +
+ " try {} catch (Exception e) {}" + PMD.EOL +
+ " }" + PMD.EOL +
+ "}";
+}
diff --git a/pmd/rulesets/newrules.xml b/pmd/rulesets/newrules.xml
index 246e47527f..e187012f4c 100644
--- a/pmd/rulesets/newrules.xml
+++ b/pmd/rulesets/newrules.xml
@@ -6,6 +6,31 @@ These are new rules for the next release
+
+
+ Using Exceptions as flow control leads to GOTOish code.
+
+ 3
+
+
+
+
diff --git a/pmd/src/net/sourceforge/pmd/rules/design/ExceptionAsFlowControlRule.java b/pmd/src/net/sourceforge/pmd/rules/design/ExceptionAsFlowControlRule.java
new file mode 100644
index 0000000000..8b8371fac0
--- /dev/null
+++ b/pmd/src/net/sourceforge/pmd/rules/design/ExceptionAsFlowControlRule.java
@@ -0,0 +1,49 @@
+package net.sourceforge.pmd.rules.design;
+
+import net.sourceforge.pmd.ast.ASTName;
+import net.sourceforge.pmd.ast.Node;
+import net.sourceforge.pmd.ast.ASTThrowStatement;
+import net.sourceforge.pmd.ast.ASTType;
+import net.sourceforge.pmd.ast.ASTCatch;
+import net.sourceforge.pmd.ast.ASTTryStatement;
+import net.sourceforge.pmd.RuleContext;
+import net.sourceforge.pmd.AbstractRule;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Catches the use of exception statements as a flow control device.
+ *
+ * @author Will Sargent
+ */
+public class ExceptionAsFlowControlRule extends AbstractRule {
+ public Object visit(ASTThrowStatement node, Object data) {
+ String throwName = getThrowsName(node);
+ for (Node parent = node.jjtGetParent(); parent != null; parent = parent.jjtGetParent()) {
+ if (parent instanceof ASTTryStatement) {
+ List list = ((ASTTryStatement) parent).getCatchBlocks();
+ for (Iterator iter = list.iterator(); iter.hasNext();) {
+ ASTCatch catchStmt = (ASTCatch) iter.next();
+ ASTType type = (ASTType) catchStmt.getFormalParameter().findChildrenOfType(ASTType.class).get(0);
+ ASTName name = (ASTName) type.findChildrenOfType(ASTName.class).get(0);
+ if (throwName != null && throwName.equals(name.getImage())) {
+ ((RuleContext) data).getReport().addRuleViolation(createRuleViolation((RuleContext) data, name.getBeginLine()));
+ }
+ }
+ }
+ }
+ return data;
+ }
+
+ private String getThrowsName(ASTThrowStatement node) {
+ Node childNode = node;
+ while (childNode.jjtGetNumChildren() > 0) {
+ childNode = childNode.jjtGetChild(0);
+ }
+ if (childNode instanceof ASTName) {
+ return ((ASTName) childNode).getImage();
+ }
+ return null;
+ }
+}
diff --git a/pmd/xdocs/credits.xml b/pmd/xdocs/credits.xml
index d71971582b..52c3598243 100644
--- a/pmd/xdocs/credits.xml
+++ b/pmd/xdocs/credits.xml
@@ -39,6 +39,7 @@
+ - Will Sargent - ExceptionAsFlowControlRule
- Bertrand Mollinier Toublet - Bug report which led to platform character set encoding enhancement
- Choi Ki Soo - Found bug in XMLRenderer
- wedemann - Found bug in RuleSetFactory XPath message variable plugging