private static boolean createField(LoggingFramework framework, JavacNode typeNode, JCFieldAccess loggingType, JCTree source, String logFieldName, boolean useStatic, String loggerTopic) { JavacTreeMaker maker = typeNode.getTreeMaker(); // private static final <loggerType> log = <factoryMethod>(<parameter>); JCExpression loggerType = chainDotsString(typeNode, framework.getLoggerTypeName()); JCExpression factoryMethod = chainDotsString(typeNode, framework.getLoggerFactoryMethodName()); JCExpression loggerName; if (loggerTopic == null || loggerTopic.trim().length() == 0) { loggerName = framework.createFactoryParameter(typeNode, loggingType); } else { loggerName = maker.Literal(loggerTopic); } JCMethodInvocation factoryMethodCall = maker.Apply(List.<JCExpression>nil(), factoryMethod, List.<JCExpression>of(loggerName)); JCVariableDecl fieldDecl = recursiveSetGeneratedBy(maker.VarDef( maker.Modifiers(Flags.PRIVATE | Flags.FINAL | (useStatic ? Flags.STATIC : 0)), typeNode.toName(logFieldName), loggerType, factoryMethodCall), source, typeNode.getContext()); injectFieldAndMarkGenerated(typeNode, fieldDecl); return true; }
/** * 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; }
@Override public void visitApply(JCMethodInvocation tree) { if (tree.typeargs.nonEmpty()) { if (tree.meth instanceof JCFieldAccess) { JCFieldAccess fa = (JCFieldAccess) tree.meth; print(fa.selected); print(".<"); print(tree.typeargs, ", "); print(">"); print(fa.name); } else { print("<"); print(tree.typeargs, ", "); print(">"); print(tree.meth); } } else { print(tree.meth); } print("("); print(tree.args, ", "); print(")"); }
public static boolean isConstructorCall(final JCStatement statement) { if (!(statement instanceof JCExpressionStatement)) return false; JCExpression expr = ((JCExpressionStatement) statement).expr; if (!(expr instanceof JCMethodInvocation)) return false; JCExpression invocation = ((JCMethodInvocation) expr).meth; String name; if (invocation instanceof JCFieldAccess) { name = ((JCFieldAccess) invocation).name.toString(); } else if (invocation instanceof JCIdent) { name = ((JCIdent) invocation).name.toString(); } else { name = ""; } return "super".equals(name) || "this".equals(name); }
private static void unpack(StringBuilder sb, JCExpression expr) { if (expr instanceof JCIdent) { sb.append(((JCIdent) expr).name.toString()); return; } if (expr instanceof JCFieldAccess) { JCFieldAccess jcfa = (JCFieldAccess) expr; unpack(sb, jcfa.selected); sb.append(".").append(jcfa.name.toString()); return; } if (expr instanceof JCTypeApply) { sb.setLength(0); sb.append("ERR:"); sb.append("@Builder(toBuilder=true) is not supported if returning a type with generics applied to an intermediate."); sb.append("__ERR__"); return; } sb.setLength(0); sb.append("ERR:"); sb.append("Expected a type of some sort, not a " + expr.getClass().getName()); sb.append("__ERR__"); }
@Override public JCTree visit(final PackageDeclaration n, final Object arg) { //ARG0: JCExpression // It returns a full qualified name JCExpression arg0 = (JCExpression) n.getName().accept(this, arg); /* TODO - Not supporting annotations if (n.getAnnotations() != null) { for (final AnnotationExpr a : n.getAnnotations()) { JCTree result = a.accept(this, arg); } } */ if (arg0 instanceof JCIdent) { return new AJCIdent((JCIdent) arg0, ((n.getComment() != null) ? n.getComment().getContent() : null)); } return new AJCFieldAccess((JCFieldAccess) arg0, ((n.getComment() != null) ? n.getComment().getContent() : null)); }
public void visitApply(JCMethodInvocation tree) { try { if (!tree.typeargs.isEmpty()) { if (SELECT.equals(treeTag(tree.meth))) { JCFieldAccess left = (JCFieldAccess)tree.meth; printExpr(left.selected); print(".<"); printExprs(tree.typeargs); print(">" + left.name); } else { print("<"); printExprs(tree.typeargs); print(">"); printExpr(tree.meth); } } else { printExpr(tree.meth); } print("("); printExprs(tree.args); print(")"); } catch (IOException e) { throw new UncheckedIOException(e); } }
@Override public Pair<ASTRecord, Integer> visitNewClass(NewClassTree node, Insertion ins) { JCNewClass na = (JCNewClass) node; JCExpression className = na.clazz; // System.out.printf("classname %s (%s)%n", className, className.getClass()); while (! (className.getKind() == Tree.Kind.IDENTIFIER)) { // IdentifierTree if (className instanceof JCAnnotatedType) { className = ((JCAnnotatedType) className).underlyingType; } else if (className instanceof JCTypeApply) { className = ((JCTypeApply) className).clazz; } else if (className instanceof JCFieldAccess) { // This occurs for fully qualified names, e.g. "new java.lang.Object()". // I'm not quite sure why the field "selected" is taken, but "name" would // be a type mismatch. It seems to work, see NewPackage test case. className = ((JCFieldAccess) className).selected; } else { throw new Error(String.format("unrecognized JCNewClass.clazz (%s): %s%n" + " surrounding new class tree: %s%n", className.getClass(), className, node)); } // System.out.printf("classname %s (%s)%n", className, className.getClass()); } return visitIdentifier((IdentifierTree) className, ins); }
/** * Matches when the receiver of an instance method is the same reference as a particular argument * to the method. For example, receiverSameAsArgument(1) would match {@code obj.method("", obj)} * * @param argNum The number of the argument to compare against (zero-based. */ public static Matcher<? super MethodInvocationTree> receiverSameAsArgument(final int argNum) { return new Matcher<MethodInvocationTree>() { @Override public boolean matches(MethodInvocationTree t, VisitorState state) { List<? extends ExpressionTree> args = t.getArguments(); if (args.size() <= argNum) { return false; } ExpressionTree arg = args.get(argNum); JCExpression methodSelect = (JCExpression) t.getMethodSelect(); if (methodSelect instanceof JCFieldAccess) { JCFieldAccess fieldAccess = (JCFieldAccess) methodSelect; return ASTHelpers.sameVariable(fieldAccess.getExpression(), arg); } else if (methodSelect instanceof JCIdent) { // A bare method call: "equals(foo)". Receiver is implicitly "this". return "this".equals(arg.toString()); } return false; } }; }
/** * Matches the boolean constant ({@link Boolean#TRUE} or {@link Boolean#FALSE}) corresponding to * the given value. */ public static Matcher<ExpressionTree> booleanConstant(final boolean value) { return new Matcher<ExpressionTree>() { @Override public boolean matches(ExpressionTree expressionTree, VisitorState state) { if (expressionTree instanceof JCFieldAccess) { Symbol symbol = ASTHelpers.getSymbol(expressionTree); if (symbol.isStatic() && state.getTypes().unboxedTypeOrType(symbol.type).getTag() == TypeTag.BOOLEAN) { return ((value && symbol.getSimpleName().contentEquals("TRUE")) || symbol.getSimpleName().contentEquals("FALSE")); } } return false; } }; }
/** * Returns true if the expression is a member access on an instance, rather than a static type. * Supports member method invocations and field accesses. */ public static Matcher<ExpressionTree> selectedIsInstance() { return new Matcher<ExpressionTree>() { @Override public boolean matches(ExpressionTree expr, VisitorState state) { if (!(expr instanceof JCFieldAccess)) { // TODO(cushon): throw IllegalArgumentException? return false; } JCExpression selected = ((JCFieldAccess) expr).getExpression(); if (selected instanceof JCNewClass) { return true; } Symbol sym = ASTHelpers.getSymbol(selected); return sym instanceof VarSymbol; } }; }
/** * Gets the symbol for a tree. Returns null if this tree does not have a symbol because it is of * the wrong type, if {@code tree} is null, or if the symbol cannot be found due to a compilation * error. */ // TODO(eaftan): refactor other code that accesses symbols to use this method public static Symbol getSymbol(Tree tree) { if (tree instanceof JCFieldAccess) { return ((JCFieldAccess) tree).sym; } if (tree instanceof JCIdent) { return ((JCIdent) tree).sym; } if (tree instanceof JCMethodInvocation) { return ASTHelpers.getSymbol((MethodInvocationTree) tree); } if (tree instanceof JCNewClass) { return ASTHelpers.getSymbol((NewClassTree) tree); } if (tree instanceof MemberReferenceTree) { return ((JCMemberReference) tree).sym; } if (tree instanceof JCAnnotatedType) { return getSymbol(((JCAnnotatedType) tree).underlyingType); } return getDeclaredSymbol(tree); }
/** * Returns the type of a receiver of a method call expression. Precondition: the expressionTree * corresponds to a method call. * * <p>Examples: * * <pre>{@code * a.b.foo() ==> type of a.b * a.bar().foo() ==> type of a.bar() * this.foo() ==> type of this * foo() ==> type of this * TheClass.aStaticMethod() ==> TheClass * aStaticMethod() ==> type of class in which method is defined * }</pre> */ public static Type getReceiverType(ExpressionTree expressionTree) { if (expressionTree instanceof JCFieldAccess) { JCFieldAccess methodSelectFieldAccess = (JCFieldAccess) expressionTree; return methodSelectFieldAccess.selected.type; } else if (expressionTree instanceof JCIdent) { JCIdent methodCall = (JCIdent) expressionTree; return methodCall.sym.owner.type; } else if (expressionTree instanceof JCMethodInvocation) { return getReceiverType(((JCMethodInvocation) expressionTree).getMethodSelect()); } else if (expressionTree instanceof JCMemberReference) { return ((JCMemberReference) expressionTree).getQualifierExpression().type; } throw new IllegalArgumentException( "Expected a JCFieldAccess or JCIdent from expression " + expressionTree); }
private static boolean isGetListMethodInvocation(ExpressionTree tree, VisitorState state) { if (tree.getKind() == Tree.Kind.METHOD_INVOCATION) { MethodInvocationTree method = (MethodInvocationTree) tree; if (!method.getArguments().isEmpty()) { return false; } if (!returnsListMatcher.matches(method, state)) { return false; } ExpressionTree expressionTree = method.getMethodSelect(); if (expressionTree instanceof JCFieldAccess) { JCFieldAccess access = (JCFieldAccess) expressionTree; String methodName = access.sym.getQualifiedName().toString(); return isFieldGetMethod(methodName); } return true; } return false; }
private static boolean isGetMethodInvocation(ExpressionTree tree, VisitorState state) { if (tree.getKind() == Tree.Kind.METHOD_INVOCATION) { MethodInvocationTree method = (MethodInvocationTree) tree; if (!method.getArguments().isEmpty()) { return false; } if (returnsListMatcher.matches(method, state)) { return false; } ExpressionTree expressionTree = method.getMethodSelect(); if (expressionTree instanceof JCFieldAccess) { JCFieldAccess access = (JCFieldAccess) expressionTree; String methodName = access.sym.getQualifiedName().toString(); return isFieldGetMethod(methodName); } return true; } return false; }
/** * Suggests replacing with Arrays.equals(a, b). Also adds the necessary import statement for * java.util.Arrays. */ @Override public Description matchMethodInvocation(MethodInvocationTree t, VisitorState state) { String arg1; String arg2; if (instanceEqualsMatcher.matches(t, state)) { arg1 = ((JCFieldAccess) t.getMethodSelect()).getExpression().toString(); arg2 = t.getArguments().get(0).toString(); } else if (staticEqualsMatcher.matches(t, state)) { arg1 = t.getArguments().get(0).toString(); arg2 = t.getArguments().get(1).toString(); } else { return NO_MATCH; } Fix fix = SuggestedFix.builder() .replace(t, "Arrays.equals(" + arg1 + ", " + arg2 + ")") .addImport("java.util.Arrays") .build(); return describeMatch(t, fix); }
public void visitApply(JCMethodInvocation tree) { try { if (!tree.typeargs.isEmpty()) { if (tree.meth.getTag() == JCTree.SELECT) { JCFieldAccess left = (JCFieldAccess)tree.meth; printExpr(left.selected); print(".<"); printExprs(tree.typeargs); print(">" + left.name); } else { print("<"); printExprs(tree.typeargs); print(">"); printExpr(tree.meth); } } else { printExpr(tree.meth); } print("("); printExprs(tree.args); print(")"); } catch (IOException e) { throw new UncheckedIOException(e); } }
@Override public void visitSelect(JCFieldAccess tree) { if (tree.type.tag != ERROR) { result = tree.type; } else { Type selectedType; boolean prev = interfaceExpected; try { interfaceExpected = false; selectedType = visit(tree.selected); } finally { interfaceExpected = prev; } ClassSymbol c = synthesizeClass(tree.name, selectedType.tsym); result = c.type; } }
/** * Matches when the receiver of an instance method is the same reference as a particular argument to the method. * For example, receiverSameAsArgument(1) would match {@code obj.method("", obj)} * * @param argNum The number of the argument to compare against (zero-based. */ public static Matcher<? super MethodInvocationTree> receiverSameAsArgument(final int argNum) { return new Matcher<MethodInvocationTree>() { @Override public boolean matches(MethodInvocationTree t, VisitorState state) { List<? extends ExpressionTree> args = t.getArguments(); if (args.size() <= argNum) { return false; } ExpressionTree arg = args.get(argNum); JCExpression methodSelect = (JCExpression) t.getMethodSelect(); if (methodSelect instanceof JCFieldAccess) { JCFieldAccess fieldAccess = (JCFieldAccess) methodSelect; return ASTHelpers.sameVariable(fieldAccess.getExpression(), arg); } else if (methodSelect instanceof JCIdent) { // A bare method call: "equals(foo)". Receiver is implicitly "this". return "this".equals(arg.toString()); } return false; } }; }
/** * Substitutes Arrays.hashCode() for any of the incorrect hashcode invocation patterns above. */ @Override public Description matchMethodInvocation(MethodInvocationTree t, VisitorState state) { String arrayArg = null; if (varargsHashCodeMethodMatcher.matches(t, state) || jdk7HashCodeMethodMatcher.matches(t, state)) { arrayArg = t.getArguments().get(0).toString(); } else if (instanceHashCodeMethodMatcher.matches(t, state)) { arrayArg = ((JCFieldAccess) t.getMethodSelect()).getExpression().toString(); } if (arrayArg == null) { return NO_MATCH; } Fix fix = new SuggestedFix() .replace(t, "Arrays.hashCode(" + arrayArg + ")") .addImport("java.util.Arrays"); return describeMatch(t, fix); }
/** * Suggests replacing with Arrays.equals(a, b). Also adds the necessary import statement for * java.util.Arrays. */ @Override public Description matchMethodInvocation(MethodInvocationTree t, VisitorState state) { String arg1; String arg2; if (instanceEqualsMatcher.matches(t, state)) { arg1 = ((JCFieldAccess) t.getMethodSelect()).getExpression().toString(); arg2 = t.getArguments().get(0).toString(); } else if (staticEqualsMatcher.matches(t, state)) { arg1 = t.getArguments().get(0).toString(); arg2 = t.getArguments().get(1).toString(); } else { return NO_MATCH; } Fix fix = new SuggestedFix() .replace(t, "Arrays.equals(" + arg1 + ", " + arg2 + ")") .addImport("java.util.Arrays"); return describeMatch(t, fix); }
private static boolean delegatingConstructor(List<JCStatement> stats) { if (stats.isEmpty()) { return false; } JCStatement stat = stats.get(0); if (stat.getKind() != Kind.EXPRESSION_STATEMENT) { return false; } JCExpression expr = ((JCExpressionStatement) stat).getExpression(); if (expr.getKind() != Kind.METHOD_INVOCATION) { return false; } JCExpression method = ((JCMethodInvocation) expr).getMethodSelect(); Name name; switch (method.getKind()) { case IDENTIFIER: name = ((JCIdent) method).getName(); break; case MEMBER_SELECT: name = ((JCFieldAccess) method).getIdentifier(); break; default: return false; } return name.contentEquals("this") || name.contentEquals("super"); }
/** * 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 visitApply(JCMethodInvocation tree) { try { if (!tree.typeargs.isEmpty()) { if (getTag(tree.meth) == SELECT) { JCFieldAccess left = (JCFieldAccess)tree.meth; printExpr(left.selected); print(".<"); printExprs(tree.typeargs); print(">" + left.name); } else { print("<"); printExprs(tree.typeargs); print(">"); printExpr(tree.meth); } } else { printExpr(tree.meth); } print("("); printExprs(tree.args); print(")"); } catch (IOException e) { throw new UncheckedIOException(e); } }
public static void processAnnotation(LoggingFramework framework, AnnotationValues<?> annotation, JavacNode annotationNode) { deleteAnnotationIfNeccessary(annotationNode, framework.getAnnotationClass()); JavacNode typeNode = annotationNode.up(); switch (typeNode.getKind()) { case TYPE: if ((((JCClassDecl)typeNode.get()).mods.flags & Flags.INTERFACE)!= 0) { annotationNode.addError("@Log is legal only on classes and enums."); return; } if (fieldExists("log", typeNode)!= MemberExistsResult.NOT_EXISTS) { annotationNode.addWarning("Field 'log' already exists."); return; } JCFieldAccess loggingType = selfType(typeNode); createField(framework, typeNode, loggingType, annotationNode.get()); break; default: annotationNode.addError("@Log is legal only on types."); break; } }
private static boolean createField(LoggingFramework framework, JavacNode typeNode, JCFieldAccess loggingType, JCTree source) { TreeMaker maker = typeNode.getTreeMaker(); // private static final <loggerType> log = <factoryMethod>(<parameter>); JCExpression loggerType = chainDotsString(typeNode, framework.getLoggerTypeName()); JCExpression factoryMethod = chainDotsString(typeNode, framework.getLoggerFactoryMethodName()); JCExpression loggerName = framework.createFactoryParameter(typeNode, loggingType); JCMethodInvocation factoryMethodCall = maker.Apply(List.<JCExpression>nil(), factoryMethod, List.<JCExpression>of(loggerName)); JCVariableDecl fieldDecl = recursiveSetGeneratedBy(maker.VarDef( maker.Modifiers(Flags.PRIVATE | Flags.FINAL | Flags.STATIC), typeNode.toName("log"), loggerType, factoryMethodCall), source); injectField(typeNode, fieldDecl); return true; }
@Override public boolean hasStarImport(String packageName) { if (pkg != null && pkg.toString().equals(packageName)) return true; if ("java.lang".equals(packageName)) return true; for (JCTree def : defs) { if (!(def instanceof JCImport)) continue; if (((JCImport) def).staticImport) continue; JCTree qual = ((JCImport) def).qualid; if (!(qual instanceof JCFieldAccess)) continue; String simpleName = ((JCFieldAccess) qual).name.toString(); if (!"*".equals(simpleName)) continue; if (packageName.equals(((JCFieldAccess) qual).selected.toString())) return true; } return false; }
@Override public void visitSelect(JCFieldAccess arg0) { if (resolved.contains(arg0)) { // This is something we have resolved here. This can happen // if // we resolve something that comes from // AnyExpressionWrapper, // since that is one of two cases where we simply use the // target // directly from the wrapper rather than generating // something. result = arg0; } else { super.visitSelect(arg0); } }
protected int diffApply(JCMethodInvocation oldT, JCMethodInvocation newT, int[] bounds) { int localPointer = bounds[0]; int[] methBounds = getBounds(oldT.meth); if (Kind.MEMBER_SELECT == oldT.meth.getKind() && oldT.meth.getKind() == newT.meth.getKind()) { localPointer = diffSelect((JCFieldAccess) oldT.meth, (JCFieldAccess) newT.meth, methBounds, oldT.typeargs, newT.typeargs); } else if (oldT.typeargs.isEmpty() && newT.typeargs.isEmpty()) { localPointer = diffTree(oldT.meth, newT.meth, methBounds); } else { copyTo(localPointer, methBounds[0]); printer.printMethodSelect(newT); localPointer = methBounds[1]; } if (!listsMatch(oldT.args, newT.args)) { if (oldT.args.nonEmpty()) { int startArg1 = getCommentCorrectedOldPos(oldT.args.head); tokenSequence.move(startArg1); moveToSrcRelevant(tokenSequence, Direction.BACKWARD); tokenSequence.moveNext(); copyTo(localPointer, localPointer = tokenSequence.offset()); } else { copyTo(localPointer, localPointer = methBounds[1]); tokenSequence.move(localPointer); moveToSrcRelevant(tokenSequence, Direction.FORWARD); tokenSequence.moveNext(); copyTo(localPointer, localPointer = tokenSequence.offset()); } localPointer = diffParameterList(oldT.args, newT.args, null, localPointer, Measure.ARGUMENT); } copyTo(localPointer, bounds[1]); return bounds[1]; }
@Override public String next() { Name name; if (next instanceof JCIdent) { name = ((JCIdent) next).name; next = null; } else { JCFieldAccess fa = (JCFieldAccess) next; name = fa.name; next = fa.selected; } return name.toString(); }
@Override public void visitSelect(final JCFieldAccess node) { // Attempt to resolve the entire selection expression final Optional<TypeName> maybeType = substitutionInventory .tryResolveClassByIdentifier(node.toString()) .map(type -> substitutionInventory.applyTypeSubstitution(type)); if (maybeType.isPresent()) { print(maybeType.get()); return;// We substituted the expression in its entirety; nothing more to output. } else if (node.selected instanceof JCIdent) { // If "selected" is an identifier, visitIdent won't attempt type resolution // so we do it here. final Optional<TypeName> maybeSelectedType = substitutionInventory .tryResolveClassByIdentifier(node.selected.toString()) .map(type -> substitutionInventory.applyTypeSubstitution(type)); if (maybeSelectedType.isPresent()) { print(maybeSelectedType.get()); } else { printExpr(node.selected, TreeInfo.postfixPrec); } } else { printExpr(node.selected, TreeInfo.postfixPrec); } print("."); final String selectionTarget = node.name.toString(); print(currentSubstitution() .filter(field -> substitutionInventory.isSubstitutableFieldName(selectionTarget)) .orElse(selectionTarget)); }