/*
* Copyright (c) 2012 Andrejs Jermakovics.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Andrejs Jermakovics - initial implementation
*/
package jmockit.assist;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.ITypeRoot;
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.Annotation;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.IAnnotationBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.ParameterizedType;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.internal.corext.dom.Bindings;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.ui.SharedASTProvider;
@SuppressWarnings("restriction")
public class ASTUtil
{
public static ITypeBinding getFirstTypeParameter(final ASTNode node)
{
ITypeBinding declaringType = null;
if( node.getParent() instanceof ClassInstanceCreation ) // for anonymous
{
ClassInstanceCreation creation = (ClassInstanceCreation) node.getParent();
Type ctype = creation.getType();
declaringType = getFirstTypeParam(ctype);
}
else if( node instanceof TypeDeclaration )
{
Type ctype = ((TypeDeclaration) node).getSuperclassType();
declaringType = getFirstTypeParam(ctype);
}
return declaringType;
}
@SuppressWarnings("unchecked")
public static ITypeBinding getFirstTypeParam(final Type ctype)
{
ITypeBinding declaringType = null;
if( ctype instanceof ParameterizedType )
{
ParameterizedType paramType = (ParameterizedType) ctype;
List<Type> typeArgs = paramType.typeArguments();
if( !typeArgs.isEmpty() )
{
Type arg1 = typeArgs.get(0);
declaringType = arg1.resolveBinding();
}
}
return declaringType;
}
public static void addAnnotation(final String annotation,
final IJavaProject project, final ASTRewrite rewrite, final MethodDeclaration decl,
final IMethodBinding binding)
{
String version= project.getOption(JavaCore.COMPILER_COMPLIANCE, true);
if (!binding.getDeclaringClass().isInterface()
|| !JavaModelUtil.isVersionLessThan(version, JavaCore.VERSION_1_6))
{
final Annotation marker= rewrite.getAST().newMarkerAnnotation();
marker.setTypeName(rewrite.getAST().newSimpleName(annotation)); //$NON-NLS-1$
rewrite.getListRewrite(decl, MethodDeclaration.MODIFIERS2_PROPERTY).insertFirst(marker, null);
}
}
public static boolean isAnnotationPresent(final IAnnotationBinding[] annotations, final String annName)
{
return findAnnotation(annotations, annName) != null;
}
public static IAnnotationBinding findAnnotation(final IAnnotationBinding[] annotations, final String annName)
{
for(IAnnotationBinding ann: annotations)
{
if( annName.equals( ann.getAnnotationType().getQualifiedName()) )
{
return ann;
}
}
return null;
}
public static CompilationUnit getAstOrParse(final ITypeRoot iTypeRoot, final IProgressMonitor mon)
{
CompilationUnit cu = SharedASTProvider.getAST(iTypeRoot, SharedASTProvider.WAIT_NO, mon);
if( cu == null && (mon == null || !mon.isCanceled()) )
{
cu = parse(iTypeRoot, mon);
}
return cu;
}
public static CompilationUnit parse(final ITypeRoot unit, final IProgressMonitor mon)
{
ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setKind(ASTParser.K_COMPILATION_UNIT);
parser.setSource(unit);
parser.setProject(unit.getJavaProject());
parser.setResolveBindings(true);
parser.setStatementsRecovery(true);
return (CompilationUnit) parser.createAST(mon); // parse
}
@SuppressWarnings("unchecked")
public static <T extends ASTNode> T findAncestor(final ASTNode node, final Class<T> clazz)
{
ASTNode parent = node.getParent();
while( parent != null )
{
if( parent.getClass() == clazz )
{
break;
}
parent = parent.getParent();
}
return (T) parent;
}
public static IMethodBinding findMethodInType(final ITypeBinding type, final String name,
final ITypeBinding[] paramTypes)
{
IMethodBinding origMethod;
if (type.isInterface())
{
origMethod = Bindings.findMethodInHierarchy(type, name, paramTypes);
}
else
{
origMethod = Bindings.findMethodInType(type, name, paramTypes);
}
return origMethod;
}
public static Set<String> getMethodSignatures(final ITypeBinding objType) throws JavaModelException
{
Set<String> methods = new TreeSet<String>();
for(IMethodBinding m: objType.getDeclaredMethods() )
{
methods.add( getSig(m) );
}
return methods;
}
public static String getSig(final IMethodBinding m)
{
String sig = m.getKey().split(";", 2)[1]; // remove declaring type
return m.getName() + sig;
}
public static Collection<IMethodBinding> getAllMethods(final ITypeBinding paramType, final AST ast)
throws JavaModelException
{
Set<IMethodBinding> methods = new TreeSet<IMethodBinding>(new Comparator<IMethodBinding>()
{
@Override
public int compare(final IMethodBinding m1, final IMethodBinding m2)
{
return getSig(m1).compareTo( getSig(m2) );
}
});
methods.addAll(Arrays.asList( paramType.getDeclaredMethods() ) );
if( paramType.isInterface() )
{
ITypeBinding[] superTypes = Bindings.getAllSuperTypes(paramType);
for(ITypeBinding superType: superTypes )
{
methods.addAll( Arrays.asList(superType.getDeclaredMethods()) );
}
ITypeBinding obj = ast.resolveWellKnownType(Object.class.getName());
for(IMethodBinding m: obj.getDeclaredMethods())
{
if( !m.isConstructor() )
{
methods.add(m);
}
}
}
return methods;
}
}