1   package com.stateofflow.eclipse.metrics.calculators;
2   
3   import java.util.Collection;
4   import java.util.HashSet;
5   import java.util.Set;
6   
7   import org.eclipse.jdt.core.dom.ArrayType;
8   import org.eclipse.jdt.core.dom.ClassInstanceCreation;
9   import org.eclipse.jdt.core.dom.CompilationUnit;
10  import org.eclipse.jdt.core.dom.ITypeBinding;
11  import org.eclipse.jdt.core.dom.InstanceofExpression;
12  import org.eclipse.jdt.core.dom.MethodDeclaration;
13  import org.eclipse.jdt.core.dom.Name;
14  import org.eclipse.jdt.core.dom.PrimitiveType;
15  import org.eclipse.jdt.core.dom.SimpleType;
16  import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
17  import org.eclipse.jdt.core.dom.Type;
18  
19  import com.stateofflow.eclipse.metrics.metric.MetricId;
20  
21  public final class EfferentCouplingsCalculator extends AbstractASTVisitorCalculator {
22      public static final MetricId METRIC_ID = MetricId.createTypeId(EfferentCouplingsCalculator.class);
23  
24      private Set<ITypeBinding> types = new HashSet<ITypeBinding>();
25  
26      private void addNamedTypes(final Collection<Name> typesToAdd) {
27          for (final Name name : typesToAdd) {
28              addType(name.resolveTypeBinding());
29          }
30      }
31  
32      private void addType(final ITypeBinding typeBinding) {
33          if (typeBinding != null) {
34              types.add(typeBinding);
35          }
36      }
37  
38      private void addType(final Type type) {
39          if (type == null) {
40              return;
41          } else if (type.isArrayType()) {
42              addType(((ArrayType) type).getComponentType());
43          } else if (type.isSimpleType() || type.isPrimitiveType() && ((PrimitiveType) type).getPrimitiveTypeCode() != PrimitiveType.VOID) {
44              addType(type.resolveBinding());
45          }
46      }
47  
48      private void addTypes(final ITypeBinding[] typesToAdd) {
49          for (final ITypeBinding element : typesToAdd) {
50              addType(element);
51          }
52      }
53  
54      @Override
55      public void endVisit(final CompilationUnit node) {
56          super.endVisit(node);
57      }
58  
59      @Override
60      protected Object getRestorableState() {
61          return new HashSet<ITypeBinding>(types);
62      }
63  
64      @Override
65      protected void handleEndOfType() {
66          final ITypeBinding type = getTypeNodeBinding();
67          if (type != null) {
68              types.remove(type);
69          }
70          noteTypeValue(EfferentCouplingsCalculator.METRIC_ID, types.size());
71          types.clear();
72      }
73  
74      @SuppressWarnings("unchecked")
75      @Override
76      protected void handleNestedClass(final Object innerTypes) {
77          types.addAll((Set<ITypeBinding>) innerTypes);
78      }
79  
80      @Override
81      protected void handleStartOfType() {
82          types.clear();
83  
84          final ITypeBinding type = getTypeNodeBinding();
85          if (type != null) {
86              addType(type.getSuperclass());
87              addTypes(type.getInterfaces());
88          }
89      }
90  
91      @SuppressWarnings("unchecked")
92      @Override
93      protected void restoreSpecificState(final Object restorableState) {
94          types = (Set<ITypeBinding>) restorableState;
95      }
96  
97      @Override
98      public boolean visit(final ClassInstanceCreation node) {
99          addType(node.resolveTypeBinding());
100         return super.visit(node);
101     }
102 
103     @Override
104     public boolean visit(final InstanceofExpression node) {
105         addType(node.resolveTypeBinding());
106         return super.visit(node);
107     }
108 
109     @SuppressWarnings("unchecked")
110     @Override
111     public boolean visit(final MethodDeclaration node) {
112         addType(node.getReturnType2());
113         addNamedTypes(node.thrownExceptions());
114         return super.visit(node);
115     }
116 
117     @Override
118     public boolean visit(final PrimitiveType node) {
119         addType(node);
120         return super.visit(node);
121     }
122 
123     @Override
124     public boolean visit(final SimpleType node) {
125         addType(node);
126         return super.visit(node);
127     }
128 
129     @Override
130     public boolean visit(final SingleVariableDeclaration node) {
131         addType(node.getType());
132         return super.visit(node);
133     }
134 }
135