1   package com.stateofflow.eclipse.metrics.calculators.cohesion;
2   
3   import org.eclipse.jdt.core.IJavaElement;
4   import org.eclipse.jdt.core.IMethod;
5   import org.eclipse.jdt.core.IType;
6   import org.eclipse.jdt.core.JavaModelException;
7   
8   final class ReferencedFieldResultCollector extends FieldResultCollector {
9       private final DeclaredFieldResultCollector declaredFields;
10  
11      public ReferencedFieldResultCollector(final String source, final DeclaredFieldResultCollector declaredFields) {
12          super(source);
13          this.declaredFields = declaredFields;
14      }
15  
16      @Override
17      protected void acceptSearchMatch(final IJavaElement element, final int start, final int end) throws JavaModelException {
18          addReferencedField(element, start, end);
19      }
20  
21      private void addReferencedField(final IJavaElement enclosingElement, final int start, final int end) {
22          if (!isInterestingFieldReference(start, end, enclosingElement, declaredFields)) {
23              return;
24          }
25  
26          addField(findMethod(enclosingElement), start, end);
27      }
28  
29      private IJavaElement findMethod(final IJavaElement enclosingElement) {
30          IJavaElement enclosingMethod = enclosingElement;
31          if (isMethod(enclosingElement)) {
32              enclosingMethod = enclosingElement.getAncestor(IJavaElement.METHOD);
33          }
34          return enclosingMethod;
35      }
36  
37      private boolean isInterestingFieldReference(final int start, final int end, final IJavaElement enclosingElement, final DeclaredFieldResultCollector declaredFields) {
38          return isFieldAccessWithinMethod(start, end, enclosingElement, declaredFields) && isReferenceToDeclaredField(start);
39      }
40  
41      private boolean isReferenceToDeclaredField(final int start) {
42          final int dot = getSource().findPreviousNonWhitespaceIndex(start - 1);
43          if (getSource().getCharAt(dot) != '.') {
44              return true;
45          }
46  
47          final int thisEnd = getSource().findPreviousNonWhitespaceIndex(dot - 1);
48          return "this".equals(getSource().getSection(thisEnd - 4, thisEnd));
49      }
50  
51      private boolean isFieldAccessWithinMethod(final int start, final int end, final IJavaElement enclosingElement, final DeclaredFieldResultCollector declaredFields) {
52          return isMethod(enclosingElement) && declaredFields.hasFieldInEnclosingType(enclosingElement, start, end);
53      }
54  
55      private boolean isMethod(final IJavaElement enclosingElement) {
56          return enclosingElement.getElementType() == IJavaElement.METHOD;
57      }
58  
59      public ClassComposition getFieldSets(final IType type) {
60          final ClassComposition composition = new ClassComposition();
61          for (final IJavaElement element : getKeys()) {
62              final IMethod method = (IMethod) element;
63              if (method.getAncestor(IJavaElement.TYPE).equals(type)) {
64                  composition.addMethod(getFields(method));
65              }
66          }
67  
68          return composition;
69      }
70  }
71