package org.eclipse.che.jdt.util;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
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.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
/**
* @author Evgen Vidolob
*/
public class JavaModelUtil {
/**
* The name of the package-info.java file.
*
* @since 3.8
*/
public static final String PACKAGE_INFO_JAVA = "package-info.java"; //$NON-NLS-1$
/**
* The name of the package-info.class file.
*
* @since 3.9
*/
public static final String PACKAGE_INFO_CLASS = "package-info.class"; //$NON-NLS-1$
/**
* The name of the package.html file.
*
* @since 3.9
*/
public static final String PACKAGE_HTML = "package.html"; //$NON-NLS-1$
/**
* @param type
* the type to test
* @return <code>true</code> iff the type is an interface or an annotation
* @throws org.eclipse.jdt.core.JavaModelException
* thrown when the field can not be accessed
*/
public static boolean isInterfaceOrAnnotation(IType type) throws JavaModelException {
return type.isInterface();
}
/**
* @param version1
* the first version
* @param version2
* the second version
* @return <code>true</code> iff version1 is less than version2
*/
public static boolean isVersionLessThan(String version1, String version2) {
if (JavaCore.VERSION_CLDC_1_1.equals(version1)) {
version1 = JavaCore.VERSION_1_1 + 'a';
}
if (JavaCore.VERSION_CLDC_1_1.equals(version2)) {
version2 = JavaCore.VERSION_1_1 + 'a';
}
return version1.compareTo(version2) < 0;
}
/**
* Resolves a type name in the context of the declaring type.
*
* @param refTypeSig
* the type name in signature notation (for example 'QVector') this can also be an array type, but dimensions will be ignored.
* @param declaringType
* the context for resolving (type where the reference was made in)
* @return returns the fully qualified type name or build-in-type name. if a unresolved type couldn't be resolved null is returned
* @throws JavaModelException
* thrown when the type can not be accessed
*/
public static String getResolvedTypeName(String refTypeSig, IType declaringType) throws JavaModelException {
int arrayCount = Signature.getArrayCount(refTypeSig);
char type = refTypeSig.charAt(arrayCount);
if (type == Signature.C_UNRESOLVED) {
String name = ""; //$NON-NLS-1$
int bracket = refTypeSig.indexOf(Signature.C_GENERIC_START, arrayCount + 1);
if (bracket > 0)
name = refTypeSig.substring(arrayCount + 1, bracket);
else {
int semi = refTypeSig.indexOf(Signature.C_SEMICOLON, arrayCount + 1);
if (semi == -1) {
throw new IllegalArgumentException();
}
name = refTypeSig.substring(arrayCount + 1, semi);
}
String[][] resolvedNames = declaringType.resolveType(name);
if (resolvedNames != null && resolvedNames.length > 0) {
return JavaModelUtil.concatenateName(resolvedNames[0][0], resolvedNames[0][1]);
}
return null;
} else {
return Signature.toString(refTypeSig.substring(arrayCount));
}
}
/**
* Concatenates two names. Uses a dot for separation.
* Both strings can be empty or <code>null</code>.
*
* @param name1
* the first name
* @param name2
* the second name
* @return the concatenated name
*/
public static String concatenateName(String name1, String name2) {
StringBuffer buf = new StringBuffer();
if (name1 != null && name1.length() > 0) {
buf.append(name1);
}
if (name2 != null && name2.length() > 0) {
if (buf.length() > 0) {
buf.append('.');
}
buf.append(name2);
}
return buf.toString();
}
/**
* Returns the package fragment root of <code>IJavaElement</code>. If the given
* element is already a package fragment root, the element itself is returned.
*
* @param element
* the element
* @return the package fragment root of the element or <code>null</code>
*/
public static IPackageFragmentRoot getPackageFragmentRoot(IJavaElement element) {
return (IPackageFragmentRoot)element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
}
public static boolean isPolymorphicSignature(IMethod method) {
return method.getAnnotation("java.lang.invoke.MethodHandle$PolymorphicSignature").exists(); //$NON-NLS-1$
}
public static boolean is18OrHigher(String compliance) {
return !isVersionLessThan(compliance, JavaCore.VERSION_1_8);
}
/**
* Checks if the given project or workspace has source compliance 1.8 or greater.
*
* @param project
* the project to test or <code>null</code> to test the workspace settings
* @return <code>true</code> if the given project or workspace has source compliance 1.8 or
* greater.
*/
public static boolean is18OrHigher(IJavaProject project) {
return is18OrHigher(getSourceCompliance(project));
}
private static String getSourceCompliance(IJavaProject project) {
return project != null ? project.getOption(JavaCore.COMPILER_SOURCE, true) : JavaCore.getOption(JavaCore.COMPILER_SOURCE);
}
/**
* Finds a type container by container name. The returned element will be of type
* <code>IType</code> or a <code>IPackageFragment</code>. <code>null</code> is returned if the
* type container could not be found.
*
* @param jproject
* The Java project defining the context to search
* @param typeContainerName
* A dot separated name of the type container
* @return returns the container
* @throws JavaModelException
* thrown when the project can not be accessed
* @see #getTypeContainerName(IType)
*/
public static IJavaElement findTypeContainer(IJavaProject jproject, String typeContainerName) throws JavaModelException {
// try to find it as type
IJavaElement result = jproject.findType(typeContainerName);
if (result == null) {
// find it as package
IPath path = new Path(typeContainerName.replace('.', '/'));
result = jproject.findElement(path);
if (!(result instanceof IPackageFragment)) {
result = null;
}
}
return result;
}
}