From b8f9b199ad7de16619cec1f288bd751fad8bc4a9 Mon Sep 17 00:00:00 2001
From: Rick Giles
+ Restricts the number of executable statements to a specified limit. +
+ + +| name | +description | +type | +default value | +
|---|---|---|---|
| max | +the maximum threshold allowed | +integer | +30 | +
| tokens | +members to check | + +subset of tokens CTOR_DEF, + METHOD_DEF, + INSTANCE_INIT, + STATIC_INIT + | + +all tokens | +
+ To configure the check: +
++<module name="ExecutableStatementCount"/> ++
+ To configure the check with a threshold of 20 for constructor and + method definitions: +
++<module name="ExecutableStatementCount"> + <property name="max" value="20"/> + <property name="tokens" value="CTOR_DEF,METHOD_DEF"/> +</module> + ++ +
+ com.puppycrawl.tools.checkstyle.checks.metrics +
+ ++ TreeWalker +
+ diff --git a/docs/releasenotes.html b/docs/releasenotes.html index 433a8e96b..fea689521 100644 --- a/docs/releasenotes.html +++ b/docs/releasenotes.html @@ -155,6 +155,10 @@
diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/metrics/ExecutableStatementCountCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/metrics/ExecutableStatementCountCheck.java
new file mode 100644
index 000000000..26a9102fb
--- /dev/null
+++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/metrics/ExecutableStatementCountCheck.java
@@ -0,0 +1,205 @@
+////////////////////////////////////////////////////////////////////////////////
+// checkstyle: Checks Java source code for adherence to a set of rules.
+// Copyright (C) 2001-2003 Oliver Burn
+//
+// 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.puppycrawl.tools.checkstyle.checks.metrics;
+
+import java.util.Stack;
+
+import com.puppycrawl.tools.checkstyle.api.Check;
+import com.puppycrawl.tools.checkstyle.api.DetailAST;
+import com.puppycrawl.tools.checkstyle.api.TokenTypes;
+
+/**
+ * Restricts the number of executable statements to a specified limit
+ * (default = 30).
+ * @author Simon Harris
+ */
+public final class ExecutableStatementCountCheck
+ extends Check
+{
+ /** default threshold */
+ private static final int DEFAULT_MAX = 30;
+
+ /** threshold to report error for */
+ private int mMax;
+
+ /** Stack of method contexts. */
+ private final Stack mContextStack = new Stack();
+
+ /** Current method context. */
+ private Context mContext;
+
+ /** Constructs a ExecutableStatementCountCheck. */
+ public ExecutableStatementCountCheck()
+ {
+ setMax(DEFAULT_MAX);
+ }
+
+ /** @see com.puppycrawl.tools.checkstyle.api.Check#getDefaultTokens() */
+ public int[] getDefaultTokens()
+ {
+ return new int[] {
+ TokenTypes.CTOR_DEF,
+ TokenTypes.METHOD_DEF,
+ TokenTypes.INSTANCE_INIT,
+ TokenTypes.STATIC_INIT,
+ TokenTypes.SLIST,
+ };
+ }
+
+ /** @see com.puppycrawl.tools.checkstyle.api.Check#getRequiredTokens() */
+ public int[] getRequiredTokens()
+ {
+ return new int[] {TokenTypes.SLIST};
+ }
+
+ /**
+ * Gets the maximum threshold.
+ * @return the maximum threshold.
+ */
+ public int getMax()
+ {
+ return mMax;
+ }
+
+ /**
+ * Sets the maximum threshold.
+ * @param aMax the maximum threshold.
+ */
+ public void setMax(int aMax)
+ {
+ mMax = aMax;
+ }
+
+ /** @see com.puppycrawl.tools.checkstyle.api.Check */
+ public void beginTree(DetailAST aRootAST)
+ {
+ mContext = null;
+ mContextStack.clear();
+ }
+
+ /** @see com.puppycrawl.tools.checkstyle.api.Check */
+ public void visitToken(DetailAST aAST)
+ {
+ switch (aAST.getType()) {
+ case TokenTypes.CTOR_DEF:
+ case TokenTypes.METHOD_DEF:
+ case TokenTypes.INSTANCE_INIT:
+ case TokenTypes.STATIC_INIT:
+ visitMethodDef();
+ break;
+ case TokenTypes.SLIST:
+ visitSlist(aAST);
+ break;
+ default:
+ throw new IllegalStateException(aAST.toString());
+ }
+ }
+
+ /** @see com.puppycrawl.tools.checkstyle.api.Check */
+ public void leaveToken(DetailAST aAST)
+ {
+ switch (aAST.getType()) {
+ case TokenTypes.CTOR_DEF:
+ case TokenTypes.METHOD_DEF:
+ case TokenTypes.INSTANCE_INIT:
+ case TokenTypes.STATIC_INIT:
+ leaveMethodDef(aAST);
+ break;
+ case TokenTypes.SLIST:
+ // Do nothing
+ break;
+ default:
+ throw new IllegalStateException(aAST.toString());
+ }
+ }
+
+ /** Process the start of the method definition. */
+ private void visitMethodDef()
+ {
+ mContextStack.push(mContext);
+ mContext = new Context();
+ }
+
+ /**
+ * Process the end of a method definition.
+ *
+ * @param aAST the token representing the method definition.
+ */
+ private void leaveMethodDef(DetailAST aAST)
+ {
+ final int count = mContext.getCount();
+ if (count > getMax()) {
+ log(
+ aAST.getLineNo(),
+ aAST.getColumnNo(),
+ "executableStatementCount",
+ new Integer(count),
+ new Integer(getMax()));
+ }
+ mContext = (Context) mContextStack.pop();
+ }
+
+ /**
+ * Process the end of a statement list.
+ *
+ * @param aAST the token representing the statement list.
+ */
+ private void visitSlist(DetailAST aAST)
+ {
+ if (mContext != null) {
+ mContext.addCount(aAST.getChildCount() / 2);
+ }
+ }
+
+ /**
+ * Class to encapsulate counting information about one member.
+ * @author Simon Harris
+ */
+ private class Context
+ {
+ /** Counter for context elements. */
+ private int mCount;
+
+ /**
+ * Creates new method context.
+ */
+ public Context()
+ {
+ mCount = 0;
+ }
+
+ /**
+ * Increase count.
+ * @param aCount the count increment.
+ */
+ public void addCount(int aCount)
+ {
+ mCount += aCount;
+ }
+
+ /**
+ * Gets the count.
+ * @return the count.
+ */
+ public int getCount()
+ {
+ return mCount;
+ }
+ }
+}
diff --git a/src/tests/com/puppycrawl/tools/checkstyle/AllTests.java b/src/tests/com/puppycrawl/tools/checkstyle/AllTests.java
index dbe389da1..85c128b4d 100644
--- a/src/tests/com/puppycrawl/tools/checkstyle/AllTests.java
+++ b/src/tests/com/puppycrawl/tools/checkstyle/AllTests.java
@@ -73,6 +73,7 @@ import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocTypeCheckTest;
import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocVariableCheckTest;
import com.puppycrawl.tools.checkstyle.checks.javadoc.PackageHtmlCheckTest;
import com.puppycrawl.tools.checkstyle.checks.metrics.CyclomaticComplexityCheckTest;
+import com.puppycrawl.tools.checkstyle.checks.metrics.ExecutableStatementCountCheckTest;
import com.puppycrawl.tools.checkstyle.checks.naming.AbstractClassNameCheckTest;
import com.puppycrawl.tools.checkstyle.checks.naming.ConstantNameCheckTest;
import com.puppycrawl.tools.checkstyle.checks.naming.LocalFinalVariableNameCheckTest;
@@ -196,6 +197,7 @@ public class AllTests {
suite.addTest(new TestSuite(RightCurlyCheckTest.class));
suite.addTest(new TestSuite(SimplifyBooleanExpressionCheckTest.class));
suite.addTest(new TestSuite(SimplifyBooleanReturnCheckTest.class));
+ suite.addTest(new TestSuite(ExecutableStatementCountCheckTest.class));
suite.addTest(new TestSuite(StaticVariableNameCheckTest.class));
suite.addTest(new TestSuite(StringArrayReaderTest.class));
suite.addTest(new TestSuite(StringLiteralEqualityCheckTest.class));
diff --git a/src/tests/com/puppycrawl/tools/checkstyle/checks/metrics/ExecutableStatementCountCheckTest.java b/src/tests/com/puppycrawl/tools/checkstyle/checks/metrics/ExecutableStatementCountCheckTest.java
new file mode 100644
index 000000000..92eabc2d5
--- /dev/null
+++ b/src/tests/com/puppycrawl/tools/checkstyle/checks/metrics/ExecutableStatementCountCheckTest.java
@@ -0,0 +1,93 @@
+package com.puppycrawl.tools.checkstyle.checks.metrics;
+
+import com.puppycrawl.tools.checkstyle.BaseCheckTestCase;
+import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
+
+public class ExecutableStatementCountCheckTest
+ extends BaseCheckTestCase
+{
+ public void testMaxZero() throws Exception
+ {
+ final DefaultConfiguration checkConfig =
+ createCheckConfig(ExecutableStatementCountCheck.class);
+
+ checkConfig.addAttribute("max", "0");
+
+ final String[] expected = {
+ "4:5: Executable statement count is 3 (max allowed is 0).",
+ "7:17: Executable statement count is 1 (max allowed is 0).",
+ "17:5: Executable statement count is 2 (max allowed is 0).",
+ "27:5: Executable statement count is 1 (max allowed is 0).",
+ "34:5: Executable statement count is 3 (max allowed is 0).",
+ "48:5: Executable statement count is 2 (max allowed is 0).",
+ "58:5: Executable statement count is 2 (max allowed is 0).",
+ "67:5: Executable statement count is 2 (max allowed is 0).",
+ };
+
+ verify(checkConfig, getPath("ComplexityCheckTestInput.java"), expected);
+ }
+
+ public void testMethodDef() throws Exception
+ {
+ final DefaultConfiguration checkConfig =
+ createCheckConfig(ExecutableStatementCountCheck.class);
+
+ checkConfig.addAttribute("max", "0");
+ checkConfig.addAttribute("tokens", "METHOD_DEF");
+
+ final String[] expected = {
+ "4:5: Executable statement count is 3 (max allowed is 0).",
+ "7:17: Executable statement count is 1 (max allowed is 0).",
+ "17:5: Executable statement count is 2 (max allowed is 0).",
+ "27:5: Executable statement count is 1 (max allowed is 0).",
+ "34:5: Executable statement count is 3 (max allowed is 0).",
+ };
+
+ verify(checkConfig, getPath("ComplexityCheckTestInput.java"), expected);
+ }
+
+ public void testCtorDef() throws Exception
+ {
+ final DefaultConfiguration checkConfig =
+ createCheckConfig(ExecutableStatementCountCheck.class);
+
+ checkConfig.addAttribute("max", "0");
+ checkConfig.addAttribute("tokens", "CTOR_DEF");
+
+ final String[] expected = {
+ "48:5: Executable statement count is 2 (max allowed is 0).",
+ };
+
+ verify(checkConfig, getPath("ComplexityCheckTestInput.java"), expected);
+ }
+
+ public void testStaticInit() throws Exception
+ {
+ final DefaultConfiguration checkConfig =
+ createCheckConfig(ExecutableStatementCountCheck.class);
+
+ checkConfig.addAttribute("max", "0");
+ checkConfig.addAttribute("tokens", "STATIC_INIT");
+
+ final String[] expected = {
+ "58:5: Executable statement count is 2 (max allowed is 0).",
+ };
+
+ verify(checkConfig, getPath("ComplexityCheckTestInput.java"), expected);
+ }
+
+ public void testInstanceInit() throws Exception
+ {
+ final DefaultConfiguration checkConfig =
+ createCheckConfig(ExecutableStatementCountCheck.class);
+
+ checkConfig.addAttribute("max", "0");
+ checkConfig.addAttribute("tokens", "INSTANCE_INIT");
+
+ final String[] expected = {
+ "67:5: Executable statement count is 2 (max allowed is 0).",
+ };
+
+ verify(checkConfig, getPath("ComplexityCheckTestInput.java"), expected);
+ }
+}
\ No newline at end of file