package com.example.lawofdemeter;
import java.util.ArrayList;
import java.util.Collection;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IParent;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import com.example.lawofdemeter.model.Model;
import com.example.lawofdemeter.model.Type;
public class ModelBuilder {
private IJavaProject project;
private Model model;
private Collection<IJavaElement> toBeResolved;
public ModelBuilder(IJavaProject project) {
this.project = project;
this.model = new Model();
this.toBeResolved = new ArrayList<IJavaElement>();
}
public void run() {
this.visit(project);
this.resolveElements();
System.out.println(model);
}
private void resolveElements() {
ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setResolveBindings(true);
parser.setProject(project);
IJavaElement[] elements = toBeResolved.toArray(new IJavaElement[toBeResolved.size()]);
IBinding[] bindings = parser.createBindings(elements, null);
for (IBinding each: bindings) this.resolveBinding(each);
}
private Void resolveBinding(IBinding binding) {
if (binding == null) return null;
switch (binding.getKind()) {
case IBinding.METHOD: return resolveMethodBinding((IMethodBinding) binding);
case IBinding.VARIABLE: return resolveVariableBinding((IVariableBinding) binding);
default: System.out.println(binding.getClass());
return null;
}
}
private Void resolveVariableBinding(IVariableBinding binding) {
Type declaringType = findType(binding.getDeclaringClass());
if (declaringType == null) return null;
Type fieldType = findType(binding.getType());
declaringType.putField(binding.getName(), fieldType);
return null;
}
private Type findType(ITypeBinding binding) {
if (binding == null) return null;
IJavaElement javaElement = binding.getJavaElement();
if (javaElement == null) return null;
return model.get(javaElement.getHandleIdentifier());
}
private Type[] findTypes(ITypeBinding[] bindings) {
Type[] types = new Type[bindings.length];
for (int i = 0; i < types.length; i++) types[i] = findType(bindings[i]);
return types;
}
private Void resolveMethodBinding(IMethodBinding binding) {
if (binding.isConstructor()) return null;
Type declaringType = findType(binding.getDeclaringClass());
if (declaringType == null) return null;
Type returnType = findType(binding.getReturnType());
Type[] parameterTypes = findTypes(binding.getParameterTypes());
declaringType.putMethod(binding.getName(), returnType, parameterTypes);
return null;
}
private void visit(IJavaElement element) {
if (this.dispatchVisit(element) && element instanceof IParent) this.visitChildren((IParent) element);
}
private void visitChildren(IParent element) {
try {
for (IJavaElement child: element.getChildren()) this.visit(child);
} catch (JavaModelException ex) {
throw new RuntimeException(ex);
}
}
private boolean dispatchVisit(IJavaElement element) {
switch (element.getElementType()) {
case IJavaElement.COMPILATION_UNIT: return visitCompilationUnit((ICompilationUnit) element);
case IJavaElement.TYPE: return visitType((IType) element);
case IJavaElement.FIELD: return visitField((IField) element);
case IJavaElement.METHOD: return visitMethod((IMethod) element);
case IJavaElement.PACKAGE_FRAGMENT: return visitPackageFragment((IPackageFragment) element);
case IJavaElement.PACKAGE_FRAGMENT_ROOT: return visitPackageFragmentRoot((IPackageFragmentRoot) element);
default: return true;
}
}
private boolean visitPackageFragmentRoot(IPackageFragmentRoot element) {
return !element.isArchive();
}
private boolean visitPackageFragment(IPackageFragment element) {
return true;
}
private boolean visitField(IField element) {
toBeResolved.add(element);
return true;
}
private boolean visitMethod(IMethod element) {
toBeResolved.add(element);
return true;
}
private boolean visitType(IType element) {
Type type = model.get(element.getHandleIdentifier());
type.setName(element.getFullyQualifiedName());
return true;
}
private boolean visitCompilationUnit(ICompilationUnit element) {
return true;
}
}