/* * Copyright (c) 2016, Oracle and/or its affiliates. * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of * conditions and the following disclaimer in the documentation and/or other materials provided * with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to * endorse or promote products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.oracle.truffle.llvm.option.processor; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.List; import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.type.ArrayType; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.ExecutableType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.type.WildcardType; /** * Methods of this class are copied from com.oracle.truffle.dsl.processor.java.ElementUtils. */ final class Utils { public static String printException(Throwable e) { StringWriter string = new StringWriter(); PrintWriter writer = new PrintWriter(string); e.printStackTrace(writer); writer.flush(); string.flush(); return e.getMessage() + "\r\n" + string.toString(); } static String getSimpleSubClassName(TypeElement innerClass) { return getSimpleName(innerClass) + "Gen"; } static String getSimpleName(Element element) { return getSimpleName(element.asType()); } private static TypeMirror getTypeMirror(ProcessingEnvironment env, Class<?> clazz) { String name = clazz.getCanonicalName(); TypeElement elem = env.getElementUtils().getTypeElement(name); return elem.asType(); } private static String getSimpleName(TypeMirror mirror) { switch (mirror.getKind()) { case BOOLEAN: return "boolean"; case BYTE: return "byte"; case CHAR: return "char"; case DOUBLE: return "double"; case FLOAT: return "float"; case SHORT: return "short"; case INT: return "int"; case LONG: return "long"; case DECLARED: return getDeclaredName((DeclaredType) mirror, true); case ARRAY: return getSimpleName(((ArrayType) mirror).getComponentType()) + "[]"; case VOID: return "void"; case NULL: return "null"; case WILDCARD: return getWildcardName((WildcardType) mirror); case TYPEVAR: return "?"; case ERROR: throw new RuntimeException("Type error " + mirror); default: throw new RuntimeException("Unknown type specified " + mirror.getKind() + " mirror: " + mirror); } } private static String getQualifiedName(TypeMirror mirror) { switch (mirror.getKind()) { case BOOLEAN: return "boolean"; case BYTE: return "byte"; case CHAR: return "char"; case DOUBLE: return "double"; case SHORT: return "short"; case FLOAT: return "float"; case INT: return "int"; case LONG: return "long"; case DECLARED: return getQualifiedName(fromTypeMirror(mirror)); case ARRAY: return getQualifiedName(((ArrayType) mirror).getComponentType()); case VOID: return "void"; case NULL: return "null"; case TYPEVAR: return getSimpleName(mirror); case ERROR: throw new RuntimeException("Type error " + mirror); case EXECUTABLE: return ((ExecutableType) mirror).toString(); case NONE: return "$none"; default: throw new RuntimeException("Unknown type specified " + mirror + " mirror: " + mirror); } } private static String getQualifiedName(TypeElement element) { String qualifiedName = element.getQualifiedName().toString(); if (qualifiedName.contains("$")) { /* * If a class gets loaded in its binary form by the ECJ compiler it fails to produce the * proper canonical class name. It leaves the $ in the qualified name of the class. So * one instance of a TypeElement may be loaded in binary and one in source form. The * current type comparison in #typeEquals compares by the qualified name so the * qualified name must match. This is basically a hack to fix the returned qualified * name of eclipse. */ qualifiedName = qualifiedName.replace('$', '.'); } return qualifiedName; } private static TypeElement fromTypeMirror(TypeMirror mirror) { switch (mirror.getKind()) { case DECLARED: return (TypeElement) ((DeclaredType) mirror).asElement(); case ARRAY: return fromTypeMirror(((ArrayType) mirror).getComponentType()); default: return null; } } private static String getDeclaredName(DeclaredType element, boolean includeTypeVariables) { String simpleName = fixECJBinaryNameIssue(element.asElement().getSimpleName().toString()); if (!includeTypeVariables || element.getTypeArguments().size() == 0) { return simpleName; } StringBuilder b = new StringBuilder(simpleName); b.append("<"); if (element.getTypeArguments().size() > 0) { for (int i = 0; i < element.getTypeArguments().size(); i++) { b.append(getSimpleName(element.getTypeArguments().get(i))); if (i < element.getTypeArguments().size() - 1) { b.append(", "); } } } b.append(">"); return b.toString(); } private static String fixECJBinaryNameIssue(String name) { if (name.contains("$")) { int lastIndex = name.lastIndexOf('$'); return name.substring(lastIndex + 1, name.length()); } return name; } private static String getWildcardName(WildcardType type) { StringBuilder b = new StringBuilder(); if (type.getExtendsBound() != null) { b.append("? extends ").append(getSimpleName(type.getExtendsBound())); } else if (type.getSuperBound() != null) { b.append("? super ").append(getSimpleName(type.getExtendsBound())); } return b.toString(); } static String getPackageName(TypeElement element) { return findPackageElement(element).getQualifiedName().toString(); } private static PackageElement findPackageElement(Element type) { List<Element> hierarchy = getElementHierarchy(type); for (Element element : hierarchy) { if (element.getKind() == ElementKind.PACKAGE) { return (PackageElement) element; } } return null; } private static List<Element> getElementHierarchy(Element e) { List<Element> elements = new ArrayList<>(); elements.add(e); Element enclosing = e.getEnclosingElement(); while (enclosing != null && enclosing.getKind() != ElementKind.PACKAGE) { elements.add(enclosing); enclosing = enclosing.getEnclosingElement(); } if (enclosing != null) { elements.add(enclosing); } return elements; } static String getFullOptionsClassName(TypeElement clazz) { return getPackageName(clazz) + "." + getSimpleSubClassName(clazz); } private static boolean typeEquals(TypeMirror type1, TypeMirror type2) { if (type1 == type2) { return true; } else if (type1 == null || type2 == null) { return false; } else { if (type1.getKind() == type2.getKind()) { return getUniqueIdentifier(type1).equals(getUniqueIdentifier(type2)); } else { return false; } } } private static String getUniqueIdentifier(TypeMirror typeMirror) { if (typeMirror.getKind() == TypeKind.ARRAY) { return getUniqueIdentifier(((ArrayType) typeMirror).getComponentType()) + "[]"; } else { return getQualifiedName(typeMirror); } } static boolean isInt(ProcessingEnvironment processingEnv, TypeMirror e) { return Utils.typeEquals(e, Utils.getTypeMirror(processingEnv, Integer.class)); } static boolean isBoolean(ProcessingEnvironment processingEnv, TypeMirror e) { return Utils.typeEquals(e, Utils.getTypeMirror(processingEnv, Boolean.class)); } static boolean isString(ProcessingEnvironment processingEnv, TypeMirror e) { return Utils.typeEquals(e, Utils.getTypeMirror(processingEnv, String.class)); } static boolean isStringArr(TypeMirror e) { return e.toString().equals("java.lang.String[]"); } }