1   package com.stateofflow.eclipse.metrics.location;
2   
3   import java.util.HashMap;
4   import java.util.List;
5   import java.util.Map;
6   
7   import org.eclipse.jdt.core.IType;
8   import org.eclipse.jdt.core.JavaModelException;
9   import org.eclipse.jdt.core.dom.ASTNode;
10  import org.eclipse.jdt.core.dom.CompilationUnit;
11  import org.eclipse.jdt.core.dom.ITypeBinding;
12  import org.eclipse.jdt.core.dom.MethodDeclaration;
13  import org.eclipse.jdt.core.dom.PackageDeclaration;
14  import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
15  
16  import com.stateofflow.eclipse.metrics.type.NonNullType;
17  
18  public final class MetricLocationFactory {
19      private final Map<MetricLocation, MetricLocation> locations = new HashMap<MetricLocation, MetricLocation>();
20  
21      private void appendMethodParameterList(final StringBuffer sb, final MethodDeclaration methodNode) {
22          @SuppressWarnings("unchecked")
23          final List<SingleVariableDeclaration> parameters = methodNode.parameters();
24          for (int i = 0; i < parameters.size(); i++) {
25              if (i > 0) {
26                  sb.append(", ");
27              }
28              sb.append(getQualifiedTypeName(parameters.get(i)));
29          }
30      }
31  
32      private NamedLineNumber createMethodNamedLineNumber(final MethodDeclaration methodNode, final CompilationUnit compilationUnit) {
33          return new NamedLineNumber(getMethodName(methodNode), getStartLineNumber(compilationUnit, methodNode));
34      }
35  
36      private NamedLineNumber createTypeNamedLineNumber(final NonNullType typeNode, final CompilationUnit compilationUnit) {
37          return new NamedLineNumber(typeNode.getName(), compilationUnit.getLineNumber(typeNode.getStartPosition()));
38      }
39  
40      public MetricLocation findOrCreate(final IType type, final CompilationUnit compilationUnit) throws JavaModelException {
41          return findOrCreate(new NamedLineNumber(type.getTypeQualifiedName(), getTypeLineNumber(type, compilationUnit)), compilationUnit);
42      }
43  
44      private MetricLocation findOrCreate(final NamedLineNumber typeInfo, final CompilationUnit compilationUnit) {
45          return findOrCreate(typeInfo, null, compilationUnit);
46      }
47  
48      private MetricLocation findOrCreate(final NamedLineNumber typeInfo, final NamedLineNumber methodInfo, final CompilationUnit compilationUnit) {
49          final MetricLocation location = new MetricLocation(getPackageName(compilationUnit), typeInfo, methodInfo);
50          if (locations.containsKey(location)) {
51              return locations.get(location);
52          }
53  
54          locations.put(location, location);
55          return location;
56      }
57  
58      public MetricLocation findOrCreate(final NonNullType typeNode, final CompilationUnit compilationUnit) {
59          return findOrCreate(createTypeNamedLineNumber(typeNode, compilationUnit), compilationUnit);
60      }
61  
62      public MetricLocation findOrCreate(final NonNullType typeNode, final MethodDeclaration methodNode, final CompilationUnit compilationUnit) {
63          return findOrCreate(createTypeNamedLineNumber(typeNode, compilationUnit), createMethodNamedLineNumber(methodNode, compilationUnit), compilationUnit);
64      }
65  
66      private String getMethodName(final MethodDeclaration methodNode) {
67          final StringBuffer sb = new StringBuffer(64);
68          sb.append(methodNode.getName().toString()).append('(');
69          appendMethodParameterList(sb, methodNode);
70          sb.append(')');
71  
72          return sb.toString();
73      }
74  
75      private String getPackageName(final CompilationUnit compilationUnit) {
76          final PackageDeclaration packageNode = compilationUnit.getPackage();
77          return packageNode != null ? packageNode.getName().getFullyQualifiedName() : "";
78      }
79  
80      private String getQualifiedTypeName(final SingleVariableDeclaration declaration) {
81          final ITypeBinding type = declaration.getType().resolveBinding();
82          return type == null ? "?" : type.getQualifiedName();
83      }
84  
85      private int getStartLineNumber(final CompilationUnit compilationUnit, final ASTNode node) {
86          return compilationUnit.getLineNumber(node.getStartPosition());
87      }
88  
89      private int getTypeLineNumber(final IType type, final CompilationUnit compilationUnit) throws JavaModelException {
90          return compilationUnit.getLineNumber(type.getNameRange().getOffset());
91      }
92  
93  }
94