/*
* Copyright (C) 2009-2012 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package lombok.javac;
import java.lang.reflect.Method;
import java.util.regex.Pattern;
import com.sun.tools.javac.main.JavaCompiler;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCBinary;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.tree.JCTree.JCLiteral;
import com.sun.tools.javac.tree.JCTree.JCUnary;
import com.sun.tools.javac.tree.TreeMaker;
/**
* Container for static utility methods relevant to lombok's operation on javac.
*/
public class Javac {
private Javac() {
// prevent instantiation
}
/** Matches any of the 8 primitive names, such as {@code boolean}. */
private static final Pattern PRIMITIVE_TYPE_NAME_PATTERN = Pattern.compile("^(boolean|byte|short|int|long|float|double|char)$");
/**
* Checks if the given expression (that really ought to refer to a type
* expression) represents a primitive type.
*/
public static boolean isPrimitive(JCExpression ref) {
String typeName = ref.toString();
return PRIMITIVE_TYPE_NAME_PATTERN.matcher(typeName).matches();
}
/**
* Turns an expression into a guessed intended literal. Only works for
* literals, as you can imagine.
*
* Will for example turn a TrueLiteral into 'Boolean.valueOf(true)'.
*/
public static Object calculateGuess(JCExpression expr) {
if (expr instanceof JCLiteral) {
JCLiteral lit = (JCLiteral) expr;
if (lit.getKind() == com.sun.source.tree.Tree.Kind.BOOLEAN_LITERAL) {
return ((Number) lit.value).intValue() == 0 ? false : true;
}
return lit.value;
} else if (expr instanceof JCIdent || expr instanceof JCFieldAccess) {
String x = expr.toString();
if (x.endsWith(".class")) x = x.substring(0, x.length() - 6);
else {
int idx = x.lastIndexOf('.');
if (idx > -1) x = x.substring(idx + 1);
}
return x;
} else
return null;
}
public static final Object CTC_BOOLEAN = getTypeTag("BOOLEAN");
public static final Object CTC_INT = getTypeTag("INT");
public static final Object CTC_DOUBLE = getTypeTag("DOUBLE");
public static final Object CTC_FLOAT = getTypeTag("FLOAT");
public static final Object CTC_SHORT = getTypeTag("SHORT");
public static final Object CTC_BYTE = getTypeTag("BYTE");
public static final Object CTC_LONG = getTypeTag("LONG");
public static final Object CTC_CHAR = getTypeTag("CHAR");
public static final Object CTC_VOID = getTypeTag("VOID");
public static final Object CTC_NONE = getTypeTag("NONE");
public static final Object CTC_BOT = getTypeTag("BOT");
public static final Object CTC_CLASS = getTypeTag("CLASS");
public static final Object CTC_NOT_EQUAL = getTreeTag("NE");
public static final Object CTC_NOT = getTreeTag("NOT");
public static final Object CTC_BITXOR = getTreeTag("BITXOR");
public static final Object CTC_UNSIGNED_SHIFT_RIGHT = getTreeTag("USR");
public static final Object CTC_MUL = getTreeTag("MUL");
public static final Object CTC_PLUS = getTreeTag("PLUS");
public static final Object CTC_EQUAL = getTreeTag("EQ");
// /**
// * Retrieves the current ordinal position of a type tag.
// *
// * For JDK 8 this is the ordinal position within the
// * com.sun.tools.javac.code.TypeTag enum
for JDK 7 and lower,
// * this is the value of the constant within
// * com.sun.tools.javac.code.TypeTags
// *
// * Solves the problem of compile time constant inlining, resulting in lombok
// * having the wrong value (javac compiler changes private api constants from
// * time to time).
// *
// * @param identifier
// * @return the ordinal value of the typetag constant
// */
// public static int getTypeTag(String identifier) {
// try {
// if (JavaCompiler.version().startsWith("1.8")) {
// Object enumInstance = Class.forName("com.sun.tools.javac.code.TypeTag").getField(identifier).get(null);
// return (int) Class.forName("com.sun.tools.javac.code.TypeTag").getField("order").get(enumInstance);
//
// } else {
// return (int) Class.forName("com.sun.tools.javac.code.TypeTags").getField(identifier).get(null);
// }
// } catch (NoSuchFieldException e) {
// throw new RuntimeException(e);
// } catch (IllegalAccessException e) {
// throw new RuntimeException(e);
// } catch (Exception e) {
// if (e instanceof RuntimeException) throw (RuntimeException) e;
// throw new RuntimeException(e);
// }
// }
public static boolean compareCTC(Object ctc1, Object ctc2) {
return ctc1.equals(ctc2);
}
/**
* Retrieves the current type tag. The actual type object differs depending on the Compiler version
*
* For JDK 8 this is an enum value of type com.sun.tools.javac.code.TypeTag
* for JDK 7 and lower, this is the value of the constant within com.sun.tools.javac.code.TypeTags
*
* Solves the problem of compile time constant inlining, resulting in lombok
* having the wrong value (javac compiler changes private api constants from
* time to time).
*
* @param identifier
* @return the ordinal value of the typetag constant
*/
public static Object getTypeTag(String identifier) {
try {
if (JavaCompiler.version().startsWith("1.8")) {
return Class.forName("com.sun.tools.javac.code.TypeTag").getField(identifier).get(null);
} else {
return Class.forName("com.sun.tools.javac.code.TypeTags").getField(identifier).get(null);
}
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (Exception e) {
if (e instanceof RuntimeException) throw (RuntimeException) e;
throw new RuntimeException(e);
}
}
public static Object getTreeTag(String identifier) {
try {
if (JavaCompiler.version().startsWith("1.8")) {
return Class.forName("com.sun.tools.javac.tree.JCTree$Tag").getField(identifier).get(null);
} else {
return Class.forName("com.sun.tools.javac.tree.JCTree").getField(identifier).get(null);
}
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (Exception e) {
if (e instanceof RuntimeException) throw (RuntimeException) e;
throw new RuntimeException(e);
}
}
public static Object getTreeTypeTag(JCTree tree) {
try {
return TreeMaker.class.getField("typetag").get(tree);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (Exception e) {
if (e instanceof RuntimeException) throw (RuntimeException) e;
throw new RuntimeException(e);
}
}
public static JCExpression makeTypeIdent(TreeMaker maker, Object ctc) {
try {
Method createIdent;
if (JavaCompiler.version().startsWith("1.8")) {
createIdent = TreeMaker.class.getMethod("TypeIdent", Class.forName("com.sun.tools.javac.code.TypeTag"));
} else {
createIdent = TreeMaker.class.getMethod("TypeIdent", Integer.TYPE);
}
return (JCExpression) createIdent.invoke(maker, ctc);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (Exception e) {
if (e instanceof RuntimeException) throw (RuntimeException) e;
throw new RuntimeException(e);
}
}
public static JCLiteral makeLiteral(TreeMaker maker, Object ctc, Object argument) {
try {
Method createLiteral;
if (JavaCompiler.version().startsWith("1.8")) {
createLiteral = TreeMaker.class.getMethod("Literal", Class.forName("com.sun.tools.javac.code.TypeTag"), Object.class);
} else {
createLiteral = TreeMaker.class.getMethod("Literal", Integer.TYPE, Object.class);
}
return (JCLiteral) createLiteral.invoke(maker, ctc, argument);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (Exception e) {
if (e instanceof RuntimeException) throw (RuntimeException) e;
throw new RuntimeException(e);
}
}
public static JCUnary makeUnary(TreeMaker maker, Object ctc, JCExpression argument) {
try {
Method createUnary;
if (JavaCompiler.version().startsWith("1.8")) {
createUnary = TreeMaker.class.getMethod("Unary", Class.forName("com.sun.tools.javac.code.TypeTag"), JCExpression.class);
} else {
createUnary = TreeMaker.class.getMethod("Unary", Integer.TYPE, JCExpression.class);
}
return (JCUnary) createUnary.invoke(maker, ctc, argument);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (Exception e) {
if (e instanceof RuntimeException) throw (RuntimeException) e;
throw new RuntimeException(e);
}
}
public static JCBinary makeBinary(TreeMaker maker, Object ctc, JCExpression rhsArgument, JCExpression lhsArgument) {
try {
Method createUnary;
if (JavaCompiler.version().startsWith("1.8")) {
createUnary = TreeMaker.class.getMethod("Binary", Class.forName("com.sun.tools.javac.code.TypeTag"), JCExpression.class, JCExpression.class);
} else {
createUnary = TreeMaker.class.getMethod("Binary", Integer.TYPE, JCExpression.class, JCExpression.class);
}
return (JCBinary) createUnary.invoke(maker, ctc, rhsArgument, lhsArgument);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (Exception e) {
if (e instanceof RuntimeException) throw (RuntimeException) e;
throw new RuntimeException(e);
}
}
}