1   package com.stateofflow.eclipse.metrics.calculators.complexity;
2   
3   import org.eclipse.jdt.core.dom.CatchClause;
4   import org.eclipse.jdt.core.dom.ConditionalExpression;
5   import org.eclipse.jdt.core.dom.DoStatement;
6   import org.eclipse.jdt.core.dom.EnhancedForStatement;
7   import org.eclipse.jdt.core.dom.ForStatement;
8   import org.eclipse.jdt.core.dom.IfStatement;
9   import org.eclipse.jdt.core.dom.MethodDeclaration;
10  import org.eclipse.jdt.core.dom.SwitchCase;
11  import org.eclipse.jdt.core.dom.WhileStatement;
12  
13  import com.stateofflow.eclipse.metrics.calculators.AbstractASTVisitorCalculator;
14  import com.stateofflow.eclipse.metrics.configuration.MetricsConfiguration;
15  import com.stateofflow.eclipse.metrics.metric.MetricId;
16  import com.stateofflow.eclipse.metrics.metric.MetricPropertyKey;
17  
18  public final class CyclomaticComplexityCalculator extends AbstractASTVisitorCalculator {
19      public static final MetricId METHOD_METRIC_ID = MetricId.createMethodId(CyclomaticComplexityCalculator.class);
20      public static final MetricId WEIGHTED_METHODS_PER_CLASS_METRIC_ID = MetricId.createTypeId(CyclomaticComplexityCalculator.class);
21  
22      public static final MetricPropertyKey COUNT_CASE_STATEMENTS_KEY = new MetricPropertyKey(METHOD_METRIC_ID, "countCaseStatements");
23      public static final MetricPropertyKey COUNT_CATCH_CLAUSES_KEY = new MetricPropertyKey(METHOD_METRIC_ID, "countCatchClauses");
24      public static final MetricPropertyKey COUNT_TERNARY_OPERATORS_KEY = new MetricPropertyKey(METHOD_METRIC_ID, "countTernaryOperators");
25  
26      private Complexity complexity = new Complexity();
27  
28      private final MetricsConfiguration configuration;
29  
30      public CyclomaticComplexityCalculator(final MetricsConfiguration configuration) {
31          this.configuration = configuration;
32      }
33  
34      public void endVisit(final MethodDeclaration arg0) {
35          if (isConcrete(arg0)) {
36              noteMethodValue(CyclomaticComplexityCalculator.METHOD_METRIC_ID, complexity.getMethodComplexity());
37          }
38          super.endVisit(arg0);
39      }
40  
41      protected Object getRestorableState() {
42          return new Complexity(complexity);
43      }
44  
45      protected void handleEndOfType() {
46          noteTypeValue(CyclomaticComplexityCalculator.WEIGHTED_METHODS_PER_CLASS_METRIC_ID, complexity.getClassComplexity());
47          super.handleEndOfType();
48      }
49  
50      protected void handleNestedClass(final Object inner) {
51          complexity.handleNestedClass(isInMethod(), (Complexity) inner);
52      }
53  
54      protected void handleStartOfType() {
55          complexity.startType();
56          super.handleStartOfType();
57      }
58  
59      protected void restoreSpecificState(final Object restorableState) {
60          complexity = (Complexity) restorableState;
61      }
62  
63      public boolean visit(final CatchClause arg0) {
64          if (configuration.getBoolean(COUNT_CATCH_CLAUSES_KEY)) {
65              complexity.increment();
66          }
67          return super.visit(arg0);
68      }
69  
70      public boolean visit(final ConditionalExpression arg0) {
71          if (configuration.getBoolean(COUNT_TERNARY_OPERATORS_KEY)) {
72              complexity.increment();
73          }
74          return super.visit(arg0);
75      }
76  
77      public boolean visit(final DoStatement arg0) {
78          complexity.increment();
79          return super.visit(arg0);
80      }
81  
82      public boolean visit(final EnhancedForStatement arg0) {
83          complexity.increment();
84          return super.visit(arg0);
85      }
86  
87      public boolean visit(final ForStatement arg0) {
88          complexity.increment();
89          return super.visit(arg0);
90      }
91  
92      public boolean visit(final IfStatement arg0) {
93          complexity.increment();
94          return super.visit(arg0);
95      }
96  
97      public boolean visit(final MethodDeclaration arg0) {
98          if (isConcrete(arg0)) {
99              complexity.startMethod();
100             return super.visit(arg0);
101         }
102         return false;
103     }
104 
105     public boolean visit(final SwitchCase arg0) {
106         if (configuration.getBoolean(COUNT_CASE_STATEMENTS_KEY)) {
107             complexity.increment();
108         }
109         return super.visit(arg0);
110     }
111 
112     public boolean visit(final WhileStatement arg0) {
113         complexity.increment();
114         return super.visit(arg0);
115     }
116 }