View Javadoc
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 }