void test(Object value, TypeTag tag, Type type, Object constValue) { JCLiteral l = maker.Literal(value); if (!l.type.hasTag(tag)) error("unexpected tag: " + l.getTag() + ": expected: " + tag); if (!types.isSameType(l.type, type)) error("unexpected type: " + l.type + ": expected: " + type); if (l.type.constValue().getClass() != constValue.getClass() || !constValue.equals(l.type.constValue())) { error("unexpected const value: " + l.type.constValue().getClass() + " " + l.type.constValue() + ": expected:" + constValue.getClass() + " " + constValue); } if (l.getValue().getClass() != value.getClass() || !value.equals(l.getValue())) { error("unexpected const value: " + l.getValue().getClass() + " " + l.type.constValue() + ": expected:" + value.getClass() + " " + value); } }
/** * 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 void visitLiteral(JCLiteral tree) { TypeTag typeTag = typeTag(tree); try { if (CTC_INT.equals(typeTag)) print(tree.value.toString()); else if (CTC_LONG.equals(typeTag)) print(tree.value + "L"); else if (CTC_FLOAT.equals(typeTag)) print(tree.value + "F"); else if (CTC_DOUBLE.equals(typeTag)) print(tree.value.toString()); else if (CTC_CHAR.equals(typeTag)) { print("\'" + quoteChar((char)((Number)tree.value).intValue()) + "\'"); } else if (CTC_BOOLEAN.equals(typeTag)) print(((Number)tree.value).intValue() == 1 ? "true" : "false"); else if (CTC_BOT.equals(typeTag)) print("null"); else print("\"" + quoteChars(tree.value.toString()) + "\""); } catch (IOException e) { throw new UncheckedIOException(e); } }
@Override public JCLiteral inline(Inliner inliner) { Object value = this.getValue(); switch (getKind()) { case CHAR_LITERAL: // Why do they do it like this? I wish I knew. value = (int) ((Character) value).charValue(); break; case BOOLEAN_LITERAL: value = ((Boolean) value) ? 1 : 0; break; default: // do nothing } return inliner.maker().Literal(LIT_KIND_TAG.get(getKind()), value); }
/** * Verify if the boolean expression have a true value despite of any variable values. * @param expression The boolean expression examined. * @return 1 When the expression is always true. */ private int hasTrueValue(JCTree expression) { if(expression instanceof JCParens){ if(hasTrueValue(((JCParens)expression).expr) != 0) return 1; }else if(expression instanceof JCLiteral){ if(((JCLiteral) expression).value == null) return VAR_FALSE_VALUE; return (int) ((JCLiteral) expression).value; }else if(expression instanceof JmlSingleton){ return 1; }else if(expression instanceof JCBinary){ return resolveBooleanOperations(expression); } return VAR_FALSE_VALUE; }
/** Returns the compile-time constant value of a tree if it has one, or {@code null}. */ @Nullable public static Object constValue(Tree tree) { if (tree == null) { return null; } tree = stripParentheses(tree); Type type = ASTHelpers.getType(tree); Object value; if (tree instanceof JCLiteral) { value = ((JCLiteral) tree).value; } else if (type != null) { value = type.constValue(); } else { return null; } if (type.hasTag(TypeTag.BOOLEAN) && value instanceof Integer) { return ((Integer) value) == 1; } return value; }
@Override public Description matchBinary(BinaryTree tree, VisitorState state) { if (!(tree.getLeftOperand() instanceof JCLiteral)) { return Description.NO_MATCH; } if (!(tree.getRightOperand() instanceof JCLiteral)) { return Description.NO_MATCH; } Boolean constValue = ASTHelpers.constValue(tree, Boolean.class); if (constValue == null) { return Description.NO_MATCH; } return buildDescription(tree) .addFix(SuggestedFix.replace(tree, constValue.toString())) .setMessage( String.format( "This expression always evalutes to `%s`, prefer a boolean literal for clarity.", constValue)) .build(); }
private void verifyPrintf(MethodInvocationTree tree, FormatParameters parameters) throws FormatFlagsConversionMismatchException, IllegalFormatException, FormatterException { List<? extends ExpressionTree> args = tree.getArguments(); JCLiteral format = (JCLiteral) args.get(parameters.getFormatIndex()); String formatString = (String) format.getValue(); List<String> argTypes = new ArrayList<String>(); for (int i = parameters.getFormatIndex() + 1; i < args.size(); ++i) { Type type = ((JCExpression) args.get(i)).type; argTypes.add(getFormatterType(type)); } try { Formatter.check(formatString, argTypes.toArray(new String[0])); } catch (ExtraFormatArgumentsException e) { return; // We can handle this. } }
/** * Note: Do not include node.toString() as part of the hash or the equals. We generate * the WrappedTreeMap after the parse phase, but we compare after the flow phase. The * attribute phase may alter the structure of the AST nodes such that their string * representations no longer match. For example, annotation nodes after the parse phase look * like: * @SuppressWarnings("foo") * But after the flow phase, they look like: * @SuppressWarnings(value = "foo") */ @Override public int hashCode() { int result = 17; result = 31 * result + node.getStartPosition(); result = 31 * result + node.getPreferredPosition(); try { result = 31 * result + node.getKind().ordinal(); } catch (AssertionError e) { // getKind() throws an AssertionError for LetExpr and TypeBoundKind. Ignore it for // calculating the hash code. } result = 31 * result + JDKCompatible.getJCTreeTag(node); if (node instanceof JCLiteral) { Object value = ((JCLiteral) node).getValue(); if (value != null) { result = 31 * result + value.hashCode(); } } return result; }
/** * 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; }
protected int diffLiteral(JCLiteral oldT, JCLiteral newT, int[] bounds) { if (oldT.typetag != newT.typetag || (oldT.value != null && !oldT.value.equals(newT.value))) { int localPointer = bounds[0]; // literal int[] literalBounds = getBounds(oldT); copyTo(localPointer, literalBounds[0]); printer.print(newT); copyTo(literalBounds[1], bounds[1]); } else { copyTo(bounds[0], bounds[1]); } return bounds[1]; }
/** * field definitions: replace initializers with 0, 0.0, false etc * when possible -- i.e. leave public, protected initializers alone */ @Override public void visitVarDef(JCVariableDecl tree) { tree.mods = translate(tree.mods); tree.vartype = translate(tree.vartype); if (tree.init != null) { if ((tree.mods.flags & (Flags.PUBLIC | Flags.PROTECTED)) != 0) tree.init = translate(tree.init); else { String t = tree.vartype.toString(); if (t.equals("boolean")) tree.init = new JCLiteral(TypeTag.BOOLEAN, 0) { }; else if (t.equals("byte")) tree.init = new JCLiteral(TypeTag.BYTE, 0) { }; else if (t.equals("char")) tree.init = new JCLiteral(TypeTag.CHAR, 0) { }; else if (t.equals("double")) tree.init = new JCLiteral(TypeTag.DOUBLE, 0.d) { }; else if (t.equals("float")) tree.init = new JCLiteral(TypeTag.FLOAT, 0.f) { }; else if (t.equals("int")) tree.init = new JCLiteral(TypeTag.INT, 0) { }; else if (t.equals("long")) tree.init = new JCLiteral(TypeTag.LONG, 0) { }; else if (t.equals("short")) tree.init = new JCLiteral(TypeTag.SHORT, 0) { }; else tree.init = new JCLiteral(TypeTag.BOT, null) { }; } } result = tree; }
@Override public void visitLiteral(JCLiteral tree) { TypeTag typeTag = typeTag(tree); if (CTC_INT.equals(typeTag)) print("" + tree.value); else if (CTC_LONG.equals(typeTag)) print(tree.value + "L"); else if (CTC_FLOAT.equals(typeTag)) print(tree.value + "F"); else if (CTC_DOUBLE.equals(typeTag)) print("" + tree.value); else if (CTC_CHAR.equals(typeTag)) { print("\'" + quoteChar((char)((Number)tree.value).intValue()) + "\'"); } else if (CTC_BOOLEAN.equals(typeTag)) print(((Number)tree.value).intValue() == 1 ? "true" : "false"); else if (CTC_BOT.equals(typeTag)) print("null"); else print("\"" + quoteChars(tree.value.toString()) + "\""); }
/** * Checks if the statement is of the form 'if (x == null) {throw WHATEVER;}, * where the block braces are optional. If it is of this form, returns "x". * If it is not of this form, returns null. */ public String returnVarNameIfNullCheck(JCStatement stat) { if (!(stat instanceof JCIf)) return null; /* Check that the if's statement is a throw statement, possibly in a block. */ { JCStatement then = ((JCIf) stat).thenpart; if (then instanceof JCBlock) { List<JCStatement> stats = ((JCBlock) then).stats; if (stats.length() == 0) return null; then = stats.get(0); } if (!(then instanceof JCThrow)) return null; } /* Check that the if's conditional is like 'x == null'. Return from this method (don't generate a nullcheck) if 'x' is equal to our own variable's name: There's already a nullcheck here. */ { JCExpression cond = ((JCIf) stat).cond; while (cond instanceof JCParens) cond = ((JCParens) cond).expr; if (!(cond instanceof JCBinary)) return null; JCBinary bin = (JCBinary) cond; if (!CTC_EQUAL.equals(treeTag(bin))) return null; if (!(bin.lhs instanceof JCIdent)) return null; if (!(bin.rhs instanceof JCLiteral)) return null; if (!CTC_BOT.equals(typeTag(bin.rhs))) return null; return ((JCIdent) bin.lhs).name.toString(); } }
void test(Object value, TypeTag tag, Type type, Object constValue) { JCLiteral l = maker.Literal(value); if (!l.type.hasTag(tag)) error("unexpected tag: " + l.getTag() + ": expected: " + tag); if (!types.isSameType(l.type, type)) error("unexpected type: " + l.type + ": expected: " + type); if (l.type.constValue().getClass() != constValue.getClass() || !constValue.equals(l.type.constValue())) { error("unexpected const value: " + l.type.constValue().getClass() + " " + l.type.constValue() + ": expected:" + constValue.getClass() + " " + constValue); } }
public void visitLiteral(JCLiteral that) { try { print("JCLiteral:"); } catch (Exception e) { } super.visitLiteral(that); }
@Override public boolean visitUnaryExpression(UnaryExpression node) { Expression operand = node.astOperand(); UnaryOperator operator = node.astOperator(); if (operator == UnaryOperator.UNARY_MINUS && operand instanceof IntegralLiteral) { JCLiteral result = (JCLiteral) toTree(operand); result.value = negative(result.value); return set(node, setPos(operand, result)); } int start = node.getPosition().getStart(); int end = node.getPosition().getEnd(); /* * The pos of "++x" is the entire thing, but the pos of "x++" is only the symbol. * I guess the javac guys think consistency is overrated :( */ if (hasSourceStructures()) { switch (operator) { case POSTFIX_DECREMENT: case POSTFIX_INCREMENT: start = posOfStructure(node, node.astOperator().getSymbol(), true); end = posOfStructure(node, node.astOperator().getSymbol(), false); } } return set(node, setPos(start, end, treeMaker.Unary(UNARY_OPERATORS.get(operator), toExpression(operand)))); }
/** * Extracts the long literal corresponding to a given {@link LiteralTree} node from the source * code as a string. Returns null if the source code is not available. */ private static String getLongLiteral(LiteralTree literalTree, VisitorState state) { JCLiteral longLiteral = (JCLiteral) literalTree; CharSequence sourceFile = state.getSourceCode(); if (sourceFile == null) { return null; } int start = longLiteral.getStartPosition(); java.util.regex.Matcher matcher = LONG_LITERAL_PATTERN.matcher(sourceFile.subSequence(start, sourceFile.length())); if (matcher.lookingAt()) { return matcher.group(); } return null; }
private Matcher<LiteralTree> literalHasStartPosition(final int startPosition) { return new Matcher<LiteralTree>() { @Override public boolean matches(LiteralTree tree, VisitorState state) { JCLiteral literal = (JCLiteral) tree; return literal.getStartPosition() == startPosition; } }; }
/** * field definitions: replace initializers with 0, 0.0, false etc * when possible -- i.e. leave public, protected initializers alone */ @Override public void visitVarDef(JCVariableDecl tree) { tree.mods = translate(tree.mods); tree.vartype = translate(tree.vartype); if (tree.init != null) { if ((tree.mods.flags & (Flags.PUBLIC | Flags.PROTECTED)) != 0) tree.init = translate(tree.init); else { String t = tree.vartype.toString(); if (t.equals("boolean")) tree.init = new JCLiteral(TypeTags.BOOLEAN, 0) { }; else if (t.equals("byte")) tree.init = new JCLiteral(TypeTags.BYTE, 0) { }; else if (t.equals("char")) tree.init = new JCLiteral(TypeTags.CHAR, 0) { }; else if (t.equals("double")) tree.init = new JCLiteral(TypeTags.DOUBLE, 0.d) { }; else if (t.equals("float")) tree.init = new JCLiteral(TypeTags.FLOAT, 0.f) { }; else if (t.equals("int")) tree.init = new JCLiteral(TypeTags.INT, 0) { }; else if (t.equals("long")) tree.init = new JCLiteral(TypeTags.LONG, 0) { }; else if (t.equals("short")) tree.init = new JCLiteral(TypeTags.SHORT, 0) { }; else tree.init = new JCLiteral(TypeTags.BOT, null) { }; } } result = tree; }
void test(Object value, int tag, Type type, Object constValue) { JCLiteral l = maker.Literal(value); if (l.type.tag != tag) error("unexpected tag: " + l.getTag() + ": expected: " + tag); if (!types.isSameType(l.type, type)) error("unexpected type: " + l.type + ": expected: " + type); if (l.type.constValue().getClass() != constValue.getClass() || !constValue.equals(l.type.constValue())) { error("unexpected const value: " + l.type.constValue().getClass() + " " + l.type.constValue() + ": expected:" + constValue.getClass() + " " + constValue); } }
public void visitLiteral(JCLiteral tree) { try { switch (tree.typetag) { case TypeTags.INT: print(tree.value.toString()); break; case TypeTags.LONG: print(tree.value + "L"); break; case TypeTags.FLOAT: print(tree.value + "F"); break; case TypeTags.DOUBLE: print(tree.value.toString()); break; case TypeTags.CHAR: print("\'" + Convert.quote( String.valueOf((char)((Number)tree.value).intValue())) + "\'"); break; case TypeTags.BOOLEAN: print(((Number)tree.value).intValue() == 1 ? "true" : "false"); break; case TypeTags.BOT: print("null"); break; default: print("\"" + Convert.quote(tree.value.toString()) + "\""); break; } } catch (IOException e) { throw new UncheckedIOException(e); } }
/** * Extracts the long literal corresponding to a given {@link LiteralTree} node from the source * code as a string. Returns null if the source code is not available. */ private static String getLongLiteral(LiteralTree literalTree, VisitorState state) { JCLiteral longLiteral = (JCLiteral) literalTree; CharSequence sourceFile = state.getSourceCode(); if (sourceFile == null) { return null; } int start = longLiteral.getStartPosition(); java.util.regex.Matcher matcher = LONG_LITERAL_PATTERN.matcher( sourceFile.subSequence(start, sourceFile.length())); if (matcher.lookingAt()) { return matcher.group(); } return null; }