1 ////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code for adherence to a set of rules.
3 // Copyright (C) 2001-2014 Oliver Burn
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ////////////////////////////////////////////////////////////////////////////////
19 package com.puppycrawl.tools.checkstyle.checks.metrics;
20
21 import java.math.BigInteger;
22
23 import com.puppycrawl.tools.checkstyle.api.DetailAST;
24 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
25
26 /**
27 * Checks the npath complexity against a specified limit (default = 200).
28 * The npath metric computes the number of possible execution paths
29 * through a function. Similar to the cyclomatic complexity but also
30 * takes into account the nesting of conditional statements and
31 * multi-part boolean expressions.
32 *
33 * @author <a href="mailto:simon@redhillconsulting.com.au">Simon Harris</a>
34 * @author o_sukhodolsky
35 * TODO: For every or: _value += (_orCount * (nestedValue - 1));
36 * TODO: For every and: ???
37 */
38 public final class NPathComplexityCheck extends AbstractComplexityCheck
39 {
40 /** Default allowed complexity. */
41 private static final int DEFAULT_MAX = 200;
42
43 /** Creates new instance of the check. */
44 public NPathComplexityCheck()
45 {
46 super(DEFAULT_MAX);
47 }
48
49 @Override
50 public int[] getDefaultTokens()
51 {
52 return new int[] {
53 TokenTypes.CTOR_DEF,
54 TokenTypes.METHOD_DEF,
55 TokenTypes.STATIC_INIT,
56 TokenTypes.INSTANCE_INIT,
57 TokenTypes.LITERAL_WHILE,
58 TokenTypes.LITERAL_DO,
59 TokenTypes.LITERAL_FOR,
60 TokenTypes.LITERAL_IF,
61 TokenTypes.LITERAL_ELSE,
62 TokenTypes.LITERAL_SWITCH,
63 TokenTypes.LITERAL_CASE,
64 TokenTypes.LITERAL_TRY,
65 TokenTypes.LITERAL_CATCH,
66 TokenTypes.QUESTION,
67 };
68 }
69
70 @Override
71 public void visitToken(DetailAST ast)
72 {
73 switch (ast.getType()) {
74 case TokenTypes.LITERAL_WHILE:
75 case TokenTypes.LITERAL_DO:
76 case TokenTypes.LITERAL_FOR:
77 case TokenTypes.LITERAL_IF:
78 case TokenTypes.QUESTION:
79 case TokenTypes.LITERAL_TRY:
80 case TokenTypes.LITERAL_SWITCH:
81 visitMultiplyingConditional();
82 break;
83 case TokenTypes.LITERAL_ELSE:
84 case TokenTypes.LITERAL_CATCH:
85 case TokenTypes.LITERAL_CASE:
86 visitAddingConditional();
87 break;
88 default:
89 super.visitToken(ast);
90 }
91 }
92
93 @Override
94 public void leaveToken(DetailAST ast)
95 {
96 switch (ast.getType()) {
97 case TokenTypes.LITERAL_WHILE:
98 case TokenTypes.LITERAL_DO:
99 case TokenTypes.LITERAL_FOR:
100 case TokenTypes.LITERAL_IF:
101 case TokenTypes.QUESTION:
102 case TokenTypes.LITERAL_TRY:
103 case TokenTypes.LITERAL_SWITCH:
104 leaveMultiplyingConditional();
105 break;
106 case TokenTypes.LITERAL_ELSE:
107 case TokenTypes.LITERAL_CATCH:
108 case TokenTypes.LITERAL_CASE:
109 leaveAddingConditional();
110 break;
111 default:
112 super.leaveToken(ast);
113 }
114 }
115
116 @Override
117 protected String getMessageID()
118 {
119 return "npathComplexity";
120 }
121
122 /** Visits else, catch or case. */
123 private void visitAddingConditional()
124 {
125 pushValue();
126 }
127
128 /** Leaves else, catch or case. */
129 private void leaveAddingConditional()
130 {
131 setCurrentValue(
132 getCurrentValue().subtract(BigInteger.ONE).add(popValue()));
133 }
134
135 /** Visits while, do, for, if, try, ? (in ?::) or switch. */
136 private void visitMultiplyingConditional()
137 {
138 pushValue();
139 }
140
141 /** Leaves while, do, for, if, try, ? (in ?::) or switch. */
142 private void leaveMultiplyingConditional()
143 {
144 setCurrentValue(
145 getCurrentValue().add(BigInteger.ONE).multiply(popValue()));
146 }
147 }