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