package org.incha.core.jswingripples.parser; /** * AST node Visitor use by the ASTExplorer * @author Manoel Marques */ import java.io.File; import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Set; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTParser; import org.eclipse.jdt.core.dom.CastExpression; import org.eclipse.jdt.core.dom.ClassInstanceCreation; import org.eclipse.jdt.core.dom.FieldDeclaration; 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 org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.MethodInvocation; import org.eclipse.jdt.core.dom.SuperConstructorInvocation; import org.eclipse.jdt.core.dom.SuperMethodInvocation; import org.eclipse.jdt.core.dom.Type; import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.incha.compiler.dom.JavaDomUtils; import org.incha.core.JavaProject; public class EdgesCalculator extends JRipplesASTVisitor { protected final Set<Edge> edges = new HashSet<Edge>(); public Set<Edge> getEdges() { return this.edges; } public EdgesCalculator (final ICompilationUnit unit, final ICompilationUnit[] units) throws JavaModelException { super(unit, new BindingSupport(units), new NullProgressMonitor()); } public EdgesCalculator (final ICompilationUnit unit, final ICompilationUnit[] units, final int codeBlockFirstCharacter, final int codeBlockLastCharacter) throws JavaModelException { super(unit, new BindingSupport(units), new NullProgressMonitor(), codeBlockFirstCharacter, codeBlockLastCharacter); } @Override public boolean visit(final ClassInstanceCreation node) { final Type type = node.getType(); processTypeEdge(type); return true; } //method declaration @Override public boolean visit(final MethodDeclaration node) { final Type type = node.getReturnType2(); processTypeEdge(type); return true; } @Override public boolean visit(final TypeDeclaration node) { final Type type = node.getSuperclassType(); processTypeEdge(type); for (final Object in : node.superInterfaceTypes()) { processTypeEdge((Type) in); } return true; } /* (non-Javadoc) * @see org.incha.core.jswingripples.parser.JRipplesASTVisitor#visit(org.eclipse.jdt.core.dom.AnnotationTypeDeclaration) */ @Override public boolean visit(final CastExpression node) { final Type type = node.getType(); processTypeEdge(type); return true; } /** * @param typeNode */ private void processTypeEdge(final Type typeNode) { if (typeNode == null || typeNode.isPrimitiveType()) { return; } analyzeBinding(typeNode.resolveBinding()); } /** * @return */ public IType getCurrentType() { return getCurrentMember().getDeclaringType(); } @Override public boolean visit(final MethodInvocation node) { final IMethodBinding binding = node.resolveMethodBinding(); if (binding == null && node.getExpression() != null) { //TODO implement method to method binding. final ITypeBinding tb = node.getExpression().resolveTypeBinding(); if (tb != null) { analyzeBinding(tb); } } else { analyzeBinding(binding); } return true; } @Override public boolean visit(final VariableDeclarationFragment node) { final IVariableBinding binding = node.resolveBinding(); if (binding == null) { return true; } final ITypeBinding typeBinding = binding.getType(); if (typeBinding != null) { final IType fieldFragmentType = (IType) getJavaElement(typeBinding); if (fieldFragmentType != null && fieldFragmentType.getFullyQualifiedName() != null) { IType declaringType=JavaDomUtils.getTopDeclaringType(fieldFragmentType); if (declaringType==null) { declaringType=fieldFragmentType; } if (edges != null){ edges.add(new Edge(getCurrentMember() ,fieldFragmentType)); } } } return true; } @Override public boolean visit(final SuperConstructorInvocation node) { analyzeBinding(node.resolveConstructorBinding()); return true; } @Override public boolean visit(final SuperMethodInvocation node) { analyzeBinding(node.resolveMethodBinding()); return true; } @Override public boolean visit(final FieldDeclaration node) { final Type type = node.getType(); if (type != null) { analyzeBinding(type.resolveBinding()); } return true; } private void analyzeBinding(final IBinding binding) { if (binding==null) { return; } try { final IMember member = getCurrentMember(); final IMember tmpMember = getMember(binding); if (tmpMember==null || tmpMember == member) { return; } final IType declaringType = JavaDomUtils.getTopDeclaringType(tmpMember); if (declaringType==null || declaringType.getFullyQualifiedName()==null) { return; } edges.add(new Edge(member, tmpMember)); } catch (final Exception e) { } } /** * @param binding * @param el * @return */ public IMember getMember(final IBinding binding) { final IJavaElement el = getJavaElement(binding); return el instanceof IMember ? (IMember) el : null; } /** * @param javaProject java project. * @param unit compilation unit to process. * @param units full set of units of project for resolving of types and variables. * @return the set of edges [IMember, IMember] * @throws JavaModelException */ public static Set<Edge> getEdges(final JavaProject javaProject, final ICompilationUnit unit, final ICompilationUnit[] units) throws JavaModelException { return getEdges(new EdgesCalculator(unit, units), javaProject, unit); } /** * @param calculator * @param javaProject java project. * @param unit compilation unit to process. * @return the set of edges [IMember, IMember] */ public static Set<Edge> getEdges(final EdgesCalculator calculator, final JavaProject javaProject, final ICompilationUnit unit) { calculator.init(); //parse compilation unit to AST final ASTParser parser = createASTParser(javaProject, unit); final ASTNode ast=parser.createAST(null); //process AST and calculate edges. ast.accept(calculator); return calculator.getEdges(); } /** * @param javaProject java project. * @param unit compilation unit to parse. * @return */ private static ASTParser createASTParser(final JavaProject javaProject, final ICompilationUnit unit) { final ASTParser parser = ASTParser.newParser(AST.JLS8); parser.setProject(null); parser.setKind(ASTParser.K_COMPILATION_UNIT); parser.setResolveBindings(true); parser.setBindingsRecovery(true); parser.setUnitName(unit.getElementName()); @SuppressWarnings("unchecked") final Hashtable<String,String> options=JavaCore.getOptions(); options.put(JavaCore.COMPILER_COMPLIANCE,"1.7"); options.put(JavaCore.COMPILER_SOURCE,"1.7"); parser.setCompilerOptions(options); parser.setKind(ASTParser.K_COMPILATION_UNIT); //get source folders final List<File> sourceFiles = javaProject.getBuildPath().getSources(); final String[] sources = new String[sourceFiles.size()]; for (int i = 0; i < sources.length; i++) { sources[i] = sourceFiles.get(i).getAbsolutePath(); } parser.setEnvironment(new String[0], sources, null, false); try { parser.setSource(unit.getSource().toCharArray()); } catch (final Exception e) { e.printStackTrace(); } return parser; } }