void run() throws Exception { Context context = new Context(); JavacFileManager.preRegister(context); final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); JavacTask ct = (JavacTask)tool.getTask(null, null, null, null, null, Arrays.asList(new JavaSource())); Iterable<? extends CompilationUnitTree> elements = ct.parse(); ct.analyze(); Assert.check(elements.iterator().hasNext()); JCTree topLevel = (JCTree)elements.iterator().next(); new TreeScanner() { @Override public void visitReference(JCMemberReference tree) { Assert.check(tree.getOverloadKind() != null); } }.scan(topLevel); }
/** * 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); }
@Override public Choice<State<JCMemberReference>> visitMemberReference( final MemberReferenceTree node, State<?> state) { return chooseSubtrees( state, s -> unifyExpression(node.getQualifierExpression(), s), expr -> maker() .Reference( node.getMode(), (Name) node.getName(), expr, List.convert( JCExpression.class, (List<? extends ExpressionTree>) node.getTypeArguments()))); }
/** * Detect member references that implement an interface that return Object, but resolve to a * method that returns Future. */ @Override public Description matchMemberReference(MemberReferenceTree tree, VisitorState state) { Description description = super.matchMemberReference(tree, state); if (Description.NO_MATCH == description) { if (allOf( (t, s) -> t.getMode() == ReferenceMode.INVOKE, FutureReturnValueIgnored::isObjectReturningMethodReferenceExpression, not((t, s) -> isWhitelistedInterfaceType(((JCMemberReference) t).type, s)), not((t, s) -> isThrowingFunctionalInterface(s, ((JCMemberReference) t).type)), specializedMatcher()) .matches(tree, state)) { return describeMatch(tree); } } return description; }
@Override public Description matchMemberReference(MemberReferenceTree tree, VisitorState state) { if (allOf( (t, s) -> t.getMode() == ReferenceMode.INVOKE, AbstractReturnValueIgnored::isVoidReturningMethodReferenceExpression, // Skip cases where the method we're referencing really does return void. We're only // looking for cases where the referenced method does not return void, but it's being // used on a void-returning functional interface. not((t, s) -> ASTHelpers.isVoidType(ASTHelpers.getSymbol(tree).getReturnType(), s)), not((t, s) -> isThrowingFunctionalInterface(s, ((JCMemberReference) t).type)), specializedMatcher()) .matches(tree, state)) { return describeMatch(tree); } return Description.NO_MATCH; }
@Override public void visitReference(JCMemberReference tree) { //perform arity-based check Env<AttrContext> localEnv = env.dup(tree); JCExpression exprTree = (JCExpression)deferredAttr.attribSpeculative(tree.getQualifierExpression(), localEnv, attr.memberReferenceQualifierResult(tree)); JCMemberReference mref2 = new TreeCopier<Void>(attr.make).copy(tree); mref2.expr = exprTree; Symbol lhsSym = TreeInfo.symbol(exprTree); localEnv.info.selectSuper = lhsSym != null && lhsSym.name == lhsSym.name.table.names._super; Symbol res = attr.rs.getMemberReference(tree, localEnv, mref2, exprTree.type, tree.name); if (!res.kind.isResolutionError()) { tree.sym = res; } if (res.kind.isResolutionTargetError() || res.type != null && res.type.hasTag(FORALL) || (res.flags() & Flags.VARARGS) != 0 || (TreeInfo.isStaticSelector(exprTree, tree.name.table.names) && exprTree.type.isRaw() && !exprTree.type.hasTag(ARRAY))) { tree.overloadKind = JCMemberReference.OverloadKind.OVERLOADED; } else { tree.overloadKind = JCMemberReference.OverloadKind.UNOVERLOADED; } //return a plain old deferred type for this setResult(tree, deferredAttr.new DeferredType(tree, env)); }
@Override public JCMemberReference inline(Inliner inliner) throws CouldNotResolveImportException { return inliner .maker() .Reference( getMode(), getName().inline(inliner), getQualifierExpression().inline(inliner), (getTypeArguments() == null) ? null : inliner.inlineList(getTypeArguments())); }
@Override public void visitReference(JCMemberReference tree) { super.visitReference(tree); if (tree.getMode() != ReferenceMode.NEW) { return; } if (memberOfEnclosing(owner, state, tree.expr.type.tsym)) { referencesOuter = true; } }
protected int diffMemberReference(JCMemberReference oldT, JCMemberReference newT, int[] bounds) { int localPointer = bounds[0]; int[] exprBounds = getBounds(oldT.expr); copyTo(localPointer, exprBounds[0]); localPointer = diffTree(oldT.expr, newT.expr, exprBounds); tokenSequence.move(exprBounds[1]); moveToSrcRelevant(tokenSequence, Direction.FORWARD); if (tokenSequence.token() != null && tokenSequence.token().id() == JavaTokenId.COLONCOLON) { moveToSrcRelevant(tokenSequence, Direction.FORWARD); copyTo(localPointer, localPointer = tokenSequence.offset()); } com.sun.tools.javac.util.List<JCExpression> oldTypePar = oldT.typeargs != null ? oldT.typeargs : com.sun.tools.javac.util.List.<JCExpression>nil(); com.sun.tools.javac.util.List<JCExpression> newTypePar = newT.typeargs != null ? newT.typeargs : com.sun.tools.javac.util.List.<JCExpression>nil(); if (!listsMatch(oldTypePar, newTypePar)) { int insertHint; if (oldTypePar.nonEmpty() && newTypePar.nonEmpty()) { insertHint = oldTypePar.head.pos; } else { insertHint = localPointer; } copyTo(localPointer, localPointer = insertHint); boolean parens = oldTypePar.isEmpty() && newTypePar.nonEmpty(); localPointer = diffParameterList(oldTypePar, newTypePar, parens ? new JavaTokenId[] { JavaTokenId.LT, JavaTokenId.GT } : null, localPointer, Measure.ARGUMENT); if (oldTypePar.nonEmpty()) { tokenSequence.move(endPos(oldTypePar.last())); moveToSrcRelevant(tokenSequence, Direction.FORWARD); moveToSrcRelevant(tokenSequence, Direction.FORWARD);//skips > and any subsequent unimportant tokens int end = tokenSequence.offset(); if (newTypePar.nonEmpty()) copyTo(localPointer, end); localPointer = end; } } if (nameChanged(oldT.name, newT.name)) { printer.print(newT.name); diffInfo.put(localPointer, NbBundle.getMessage(CasualDiff.class,"TXT_UpdateReferenceTo",oldT.name)); localPointer = localPointer + oldT.name.length(); } copyTo(localPointer, bounds[1]); return bounds[1]; }
private boolean matchReference(JCMemberReference t1, JCMemberReference t2) { return treesMatch(t1.expr, t2.expr) && t1.name == t2.name; }
/** Gets the symbol for a member reference. */ public static MethodSymbol getSymbol(MemberReferenceTree tree) { Symbol sym = ((JCMemberReference) tree).sym; return sym instanceof MethodSymbol ? (MethodSymbol) sym : null; }
@Override public Description matchMemberReference(MemberReferenceTree tree, VisitorState state) { return checkInvocation( tree, ((JCMemberReference) tree).referentType, state, ASTHelpers.getSymbol(tree)); }
private static boolean isObjectReturningMethodReferenceExpression( MemberReferenceTree tree, VisitorState state) { return functionalInterfaceReturnsObject(((JCMemberReference) tree).type, state); }
private static boolean isVoidReturningMethodReferenceExpression( MemberReferenceTree tree, VisitorState state) { return functionalInterfaceReturnsExactlyVoid(((JCMemberReference) tree).type, state); }
/** * Gets the {@link Element} ("symbol") for the given Tree API node. * * @param tree the {@link Tree} node to get the symbol for * @throws IllegalArgumentException if {@code tree} is null or is not a valid javac-internal * tree (JCTree) * @return the {@link Symbol} for the given tree, or null if one could not be found */ public static /*@Nullable*/ Element symbol(Tree tree) { if (tree == null) { ErrorReporter.errorAbort("InternalUtils.symbol: tree is null"); return null; // dead code } if (!(tree instanceof JCTree)) { ErrorReporter.errorAbort("InternalUtils.symbol: tree is not a valid Javac tree"); return null; // dead code } if (TreeUtils.isExpressionTree(tree)) { tree = TreeUtils.skipParens((ExpressionTree) tree); } switch (tree.getKind()) { case VARIABLE: case METHOD: case CLASS: case ENUM: case INTERFACE: case ANNOTATION_TYPE: case TYPE_PARAMETER: return TreeInfo.symbolFor((JCTree) tree); // symbol() only works on MethodSelects, so we need to get it manually // for method invocations. case METHOD_INVOCATION: return TreeInfo.symbol(((JCMethodInvocation) tree).getMethodSelect()); case ASSIGNMENT: return TreeInfo.symbol((JCTree) ((AssignmentTree) tree).getVariable()); case ARRAY_ACCESS: return symbol(((ArrayAccessTree) tree).getExpression()); case NEW_CLASS: return ((JCNewClass) tree).constructor; case MEMBER_REFERENCE: // TreeInfo.symbol, which is used in the default case, didn't handle // member references until JDK8u20. So handle it here. return ((JCMemberReference) tree).sym; default: return TreeInfo.symbol((JCTree) tree); } }