public Boolean visitConditionalExpression(ConditionalExpressionTree node, TreePath p) { if (p == null) { super.visitConditionalExpression(node, p); return false; } ConditionalExpressionTree t = (ConditionalExpressionTree) p.getLeaf(); if (!scan(node.getCondition(), t.getCondition(), p)) return false; if (!scan(node.getFalseExpression(), t.getFalseExpression(), p)) return false; return scan(node.getTrueExpression(), t.getTrueExpression(), p); }
private static List<? extends TypeMirror> computeConditionalExpression(Set<ElementKind> types, CompilationInfo info, TreePath parent, Tree error, int offset) { ConditionalExpressionTree cet = (ConditionalExpressionTree) parent.getLeaf(); if (cet.getCondition() == error) { types.add(ElementKind.PARAMETER); types.add(ElementKind.LOCAL_VARIABLE); types.add(ElementKind.FIELD); return Collections.singletonList(info.getTypes().getPrimitiveType(TypeKind.BOOLEAN)); } if (cet.getTrueExpression() == error || cet.getFalseExpression() == error) { types.add(ElementKind.PARAMETER); types.add(ElementKind.LOCAL_VARIABLE); types.add(ElementKind.FIELD); return resolveType(types, info, parent.getParentPath(), cet, offset, null, null); } return null; }
@Override public Object visitConditionalExpression(ConditionalExpressionTree node, Void p) { Object condition = scan(node.getCondition(), p); if (condition == Boolean.TRUE) { return scan(node.getTrueExpression(), p); } else if (condition == Boolean.FALSE) { return scan(node.getFalseExpression(), p); } if (enhanceProcessing) { Object first = scan(node.getTrueExpression(), p); Object second = scan(node.getFalseExpression(), p); if (first == NULL && second == NULL) { return NULL; } else if (first != null && second != null) { return NOT_NULL; } } // indeterminate return null; }
@Override protected void performRewrite(TransformationContext ctx) throws Exception { TypeMirror resolvedTargetType = targetType.resolve(ctx.getWorkingCopy()); if (resolvedTargetType == null) { //cannot resolve anymore: return; } TreePath resolvedIdealTypeTree = idealTypeTree != null ? idealTypeTree.resolve(ctx.getWorkingCopy()) : null; TreeMaker make = ctx.getWorkingCopy().getTreeMaker(); ExpressionTree toCast = (ExpressionTree) ctx.getPath().getLeaf(); Class interf = toCast.getKind().asInterface(); boolean wrapWithBrackets = interf == BinaryTree.class || interf == ConditionalExpressionTree.class; if (/*TODO: replace with JavaFixUtilities.requiresparenthesis*/wrapWithBrackets) { toCast = make.Parenthesized(toCast); } ExpressionTree cast = make.TypeCast(resolvedIdealTypeTree != null ? resolvedIdealTypeTree.getLeaf() : make.Type(resolvedTargetType), toCast); ctx.getWorkingCopy().rewrite(ctx.getPath().getLeaf(), cast); }
@Override public Void visitConditionalExpression(ConditionalExpressionTree node, Void unused) { sync(node); builder.open(plusFour); scan(node.getCondition(), null); builder.breakOp(" "); token("?"); builder.space(); scan(node.getTrueExpression(), null); builder.breakOp(" "); token(":"); builder.space(); scan(node.getFalseExpression(), null); builder.close(); return null; }
@Override public boolean matches(ExpressionTree t, VisitorState state) { return firstNonNull( t.accept( new SimpleTreeVisitor<Boolean, Void>() { @Override public Boolean visitConditionalExpression( ConditionalExpressionTree tree, Void unused) { return reduce( tree.getTrueExpression().accept(this, null), tree.getFalseExpression().accept(this, null)); } @Override protected Boolean defaultAction(Tree node, Void aVoid) { Object constValue = ASTHelpers.constValue(node); return constValue != null; } public Boolean reduce(Boolean lhs, Boolean rhs) { return firstNonNull(lhs, false) && firstNonNull(rhs, false); } }, null), false); }
/** * If the computation of the type of the ConditionalExpressionTree in * org.checkerframework.framework.type.TypeFromTree.TypeFromExpression.visitConditionalExpression(ConditionalExpressionTree, AnnotatedTypeFactory) * is correct, the following checks are redundant. * However, let's add another failsafe guard and do the checks. */ @Override public Void visitConditionalExpression(ConditionalExpressionTree node, Void p) { AnnotatedTypeMirror cond = atypeFactory.getAnnotatedType(node); Pair<Tree, AnnotatedTypeMirror> ctx = visitorState.getAssignmentContext(); Tree assignmentContext = ctx == null ? null : ctx.first; boolean isLocalVariableAssignment = false; if (assignmentContext != null) { if (assignmentContext instanceof VariableTree) { isLocalVariableAssignment = assignmentContext instanceof IdentifierTree && !TreeUtils.isFieldAccess(assignmentContext); } if (assignmentContext instanceof VariableTree) { isLocalVariableAssignment = TreeUtils .enclosingMethod(getCurrentPath()) != null; } } this.commonAssignmentCheck(cond, node.getTrueExpression(), "conditional.type.incompatible", isLocalVariableAssignment); this.commonAssignmentCheck(cond, node.getFalseExpression(), "conditional.type.incompatible", isLocalVariableAssignment); return super.visitConditionalExpression(node, p); }
@Override public Tree visitConditionalExpression(ConditionalExpressionTree tree, Void p) { ConditionalExpressionTree n = make.ConditionalExpression(tree.getCondition(), tree.getTrueExpression(), tree.getFalseExpression()); model.setType(n, model.getType(tree)); comments.copyComments(tree, n); model.setPos(n, model.getPos(tree)); return n; }
@Override public Object visitConditionalExpression(ConditionalExpressionTree node, Object p) { depth++; Object o = super.visitConditionalExpression(node, p); depth--; return o; }
@Override public Void visitConditionalExpression(ConditionalExpressionTree tree, List<Node> d) { List<Node> below = new ArrayList<Node>(); addCorrespondingType(below); addCorrespondingComments(below); super.visitConditionalExpression(tree, below); d.add(new TreeNode(info, getCurrentPath(), below)); return null; }
private ExpressionTree makeParenthesis(ExpressionTree arg) { Class c = arg.getKind().asInterface(); // if the original append argument was an expression, surround it in parenthesis, to get the same toString effect if (c == BinaryTree.class || c == UnaryTree.class || c == CompoundAssignmentTree.class || c == AssignmentTree.class || c == ConditionalExpressionTree.class) { return mk.Parenthesized(arg); } else { return arg; } }
@Override public Boolean visitConditionalExpression(ConditionalExpressionTree node, ConstructorData p) { Boolean result = scan(node.getCondition(), p); if (result != null) { if (result) { scan(node.getTrueExpression(), null); } else { scan(node.getFalseExpression(), null); } return null; } Map<Element, State> oldVariable2State = variable2State; variable2State = new HashMap<Element, Flow.State>(oldVariable2State); scan(node.getTrueExpression(), null); if (node.getFalseExpression() != null) { Map<Element, State> variableStatesAfterThen = new HashMap<Element, Flow.State>(variable2State); variable2State = new HashMap<Element, Flow.State>(oldVariable2State); scan(node.getFalseExpression(), null); variable2State = mergeOr(variable2State, variableStatesAfterThen); } else { variable2State = mergeOr(variable2State, oldVariable2State); } return null; }
@Override public List<Tree> visitConditionalExpression(ConditionalExpressionTree node, ExpressionScanner.ExpressionsInfo p) { ExpressionTree condition = node.getCondition(); List<Tree> cond = scan(condition, p); Tree lastCond = null; Boolean resolvedCondition = null; if (cond != null) { lastCond = cond.get(cond.size() - 1); } else { if (condition.getKind() == Tree.Kind.BOOLEAN_LITERAL) { resolvedCondition = Boolean.parseBoolean(condition.toString()); } } List<Tree> rT; List<Tree> rF; if (resolvedCondition != null) { if (resolvedCondition) { rT = scan(node.getTrueExpression(), p); rF = null; } else { rT = null; rF = scan(node.getFalseExpression(), p); } } else { rT = scan(node.getTrueExpression(), p); rF = scan(node.getFalseExpression(), p); } if (lastCond != null) { if (rT != null) { p.addNextExpression(lastCond, rT.get(0)); } if (rF != null) { p.addNextExpression(lastCond, rF.get(0)); } } return reduce(reduce(cond, rT), rF); }
@Override public Mirror visitConditionalExpression(ConditionalExpressionTree arg0, EvaluationContext evaluationContext) { boolean isTrue = evaluateCondition(arg0, evaluationContext, arg0.getCondition()); if (isTrue) { return arg0.getTrueExpression().accept(this, evaluationContext); } else { return arg0.getFalseExpression().accept(this, evaluationContext); } }
private Type pathToType(TreePath tp, Tree tree) { if (tree instanceof ConditionalExpressionTree) { // Conditionals always wind up as Object -- this corrects ConditionalExpressionTree cet = (ConditionalExpressionTree) tree; Type tmt = pathToType(new TreePath(tp, cet.getTrueExpression())); Type tmf = pathToType(new TreePath(tp, cet.getFalseExpression())); if (!tmt.isPrimitive() && !tmf.isPrimitive()) { Type lub = types.lub(tmt, tmf); // System.err.printf("cond ? %s : %s -- lub = %s\n", // varTypeName(tmt), varTypeName(tmf), varTypeName(lub)); return lub; } } return pathToType(tp); }
@Override public UExpression visitConditionalExpression(ConditionalExpressionTree tree, Void v) { UConditional result = UConditional.create(template(tree.getCondition()), template(tree.getTrueExpression()), template(tree.getFalseExpression())); if (context.get(AlsoReverseTernary.class) != null) { return UAnyOf.create(result, result.reverse()); } else { return result; } }
@Override @Nullable public Unifier visitConditionalExpression( ConditionalExpressionTree conditional, Unifier unifier) { unifier = getCondition().unify(conditional.getCondition(), unifier); unifier = getTrueExpression().unify(conditional.getTrueExpression(), unifier); return getFalseExpression().unify(conditional.getFalseExpression(), unifier); }
@Override public Void visitConditionalExpression( ConditionalExpressionTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (ConditionalExpressionTreeMatcher matcher : conditionalExpressionMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchConditionalExpression(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitConditionalExpression(tree, state); }
@Override public UExpression visitConditionalExpression(ConditionalExpressionTree tree, Void v) { return UConditional.create( template(tree.getCondition()), template(tree.getTrueExpression()), template(tree.getFalseExpression())); }
@Override @Nullable public Choice<Unifier> visitConditionalExpression( ConditionalExpressionTree conditional, Unifier unifier) { return getCondition() .unify(conditional.getCondition(), unifier.fork()) .thenChoose(unifications(getTrueExpression(), conditional.getTrueExpression())) .thenChoose(unifications(getFalseExpression(), conditional.getFalseExpression())) .or( getCondition() .negate() .unify(conditional.getCondition(), unifier.fork()) .thenChoose(unifications(getFalseExpression(), conditional.getTrueExpression())) .thenChoose(unifications(getTrueExpression(), conditional.getFalseExpression()))); }
@Override public Choice<State<JCConditional>> visitConditionalExpression( final ConditionalExpressionTree node, State<?> state) { return chooseSubtrees( state, s -> unifyExpression(node.getCondition(), s), s -> unifyExpression(node.getTrueExpression(), s), s -> unifyExpression(node.getFalseExpression(), s), maker()::Conditional); }
@Override public Description matchConditionalExpression( ConditionalExpressionTree conditionalExpression, VisitorState state) { if (conditionalExpression.getFalseExpression().getKind() != Kind.NULL_LITERAL && conditionalExpression.getTrueExpression().getKind() != Kind.NULL_LITERAL) { return NO_MATCH; } ASTHelpers.TargetType targetType = ASTHelpers.targetType(state); if (targetType == null || !targetType.type().isPrimitive()) { return NO_MATCH; } return describeMatch(conditionalExpression); }
@Override public Number visitConditionalExpression(ConditionalExpressionTree node, Void p) { Number ifTrue = node.getTrueExpression().accept(this, null); Number ifFalse = node.getFalseExpression().accept(this, null); Boolean condition = ASTHelpers.constValue(node.getCondition(), Boolean.class); if (condition == null) { return null; } return condition ? ifTrue : ifFalse; }
@Override public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { MethodSymbol sym = ASTHelpers.getSymbol(tree); if (!sym.isVarArgs()) { return NO_MATCH; } if (tree.getArguments().size() != sym.getParameters().size()) { // explicit varargs call with more actuals than formals return NO_MATCH; } Tree arg = getLast(tree.getArguments()); if (!(arg instanceof ConditionalExpressionTree)) { return NO_MATCH; } Types types = state.getTypes(); if (types.isArray(getType(arg))) { return NO_MATCH; } ConditionalExpressionTree cond = (ConditionalExpressionTree) arg; boolean trueIsArray = types.isArray(getType(cond.getTrueExpression())); if (!(trueIsArray ^ types.isArray(getType(cond.getFalseExpression())))) { return NO_MATCH; } SuggestedFix.Builder fix = SuggestedFix.builder(); String qualified = SuggestedFixes.qualifyType( state, fix, types.elemtype(getLast(sym.getParameters()).asType())); Tree toFix = !trueIsArray ? cond.getTrueExpression() : cond.getFalseExpression(); fix.prefixWith(toFix, String.format("new %s[] {", qualified)).postfixWith(toFix, "}"); return describeMatch(tree, fix.build()); }
@Override public Description matchMethodInvocation( MethodInvocationTree invocationTree, final VisitorState state) { if (!ARRAY_FILL_MATCHER.matches(invocationTree, state)) { return Description.NO_MATCH; } Type arrayComponentType = state.getTypes().elemtype(ASTHelpers.getType(invocationTree.getArguments().get(0))); Tree fillingArgument = Iterables.getLast(invocationTree.getArguments()); Type fillingObjectType = ASTHelpers.getType(fillingArgument); // You can put an Integer or an int into a Number[], but you can't put a Number into an // Integer[]. // (Note that you can assign Integer[] to Number[] and then try to put the Number into it, but // that's a hole provided by array covariance we can't plug here) if (isValidArrayFill(state, arrayComponentType, fillingObjectType)) { return Description.NO_MATCH; } // Due to some funky behavior, javac doesn't appear to fully expand the type of a ternary // when passed into an "Object" context. Let's explore both sides if (fillingArgument.getKind() == Kind.CONDITIONAL_EXPRESSION) { ConditionalExpressionTree cet = (ConditionalExpressionTree) fillingArgument; Type trueExpressionType = ASTHelpers.getType(cet.getTrueExpression()); if (!isValidArrayFill(state, arrayComponentType, trueExpressionType)) { return reportMismatch(invocationTree, arrayComponentType, trueExpressionType); } Type falseExpressionType = ASTHelpers.getType(cet.getFalseExpression()); if (!isValidArrayFill(state, arrayComponentType, falseExpressionType)) { return reportMismatch(invocationTree, arrayComponentType, falseExpressionType); } // Looks like we were able to find a ternary that would actually work return Description.NO_MATCH; } return reportMismatch(invocationTree, arrayComponentType, fillingObjectType); }
public TernaryExpressionNode(ConditionalExpressionTree tree, Node condition, Node thenOperand, Node elseOperand) { super(InternalUtils.typeOf(tree)); assert tree.getKind().equals(Kind.CONDITIONAL_EXPRESSION); this.tree = tree; this.condition = condition; this.thenOperand = thenOperand; this.elseOperand = elseOperand; }
@Override public Node visitConditionalExpression(ConditionalExpressionTree tree, Void p) { // see JLS 15.25 TypeMirror exprType = InternalUtils.typeOf(tree); Label trueStart = new Label(); Label falseStart = new Label(); Label merge = new Label(); Node condition = unbox(scan(tree.getCondition(), p)); ConditionalJump cjump = new ConditionalJump(trueStart, falseStart); extendWithExtendedNode(cjump); addLabelForNextNode(trueStart); Node trueExpr = scan(tree.getTrueExpression(), p); trueExpr = conditionalExprPromotion(trueExpr, exprType); extendWithExtendedNode(new UnconditionalJump(merge)); addLabelForNextNode(falseStart); Node falseExpr = scan(tree.getFalseExpression(), p); falseExpr = conditionalExprPromotion(falseExpr, exprType); addLabelForNextNode(merge); Node node = new TernaryExpressionNode(tree, condition, trueExpr, falseExpr); extendWithNode(node); return node; }
@Override public PurityResult visitConditionalExpression( ConditionalExpressionTree node, PurityResult p) { PurityResult r = scan(node.getCondition(), p); r = scan(node.getTrueExpression(), r); r = scan(node.getFalseExpression(), r); return r; }
@Override public CodeModel visitConditionalExpression(ConditionalExpressionTree node, VisitContext context) { ExpressionModel condition = scan(node.getCondition(), context); ExpressionModel trueExpression = scan(node.getTrueExpression(), context); ExpressionModel falseExpression = scan(node.getFalseExpression(), context); return context.builder.forConditionalExpression(condition, trueExpression, falseExpression); }
@Override public Boolean visitConditionalExpression(ConditionalExpressionTree node, Void p) { return reduce( node.getCondition().accept(this, null), node.getTrueExpression().accept(this, null), node.getFalseExpression().accept(this, null)); }
/** * Returns the tree with the assignment context for the treePath leaf node. (Does not handle * pseudo-assignment of an argument to a parameter or a receiver expression to a receiver.) * * <p>The assignment context for the {@code treePath} is the leaf of its parent, if the parent * is one of the following trees: * * <ul> * <li>AssignmentTree * <li>CompoundAssignmentTree * <li>MethodInvocationTree * <li>NewArrayTree * <li>NewClassTree * <li>ReturnTree * <li>VariableTree * </ul> * * If the parent is a ConditionalExpressionTree we need to distinguish two cases: If the leaf is * either the then or else branch of the ConditionalExpressionTree, then recurse on the parent. * If the leaf is the condition of the ConditionalExpressionTree, then return null to not * consider this assignment context. * * <p>If the leaf is a ParenthesizedTree, then recurse on the parent. * * <p>Otherwise, null is returned. * * @return the assignment context as described */ public static Tree getAssignmentContext(final TreePath treePath) { TreePath parentPath = treePath.getParentPath(); if (parentPath == null) { return null; } Tree parent = parentPath.getLeaf(); switch (parent.getKind()) { case PARENTHESIZED: return getAssignmentContext(parentPath); case CONDITIONAL_EXPRESSION: ConditionalExpressionTree cet = (ConditionalExpressionTree) parent; if (cet.getCondition() == treePath.getLeaf()) { // The assignment context for the condition is simply boolean. // No point in going on. return null; } // Otherwise use the context of the ConditionalExpressionTree. return getAssignmentContext(parentPath); case ASSIGNMENT: case METHOD_INVOCATION: case NEW_ARRAY: case NEW_CLASS: case RETURN: case VARIABLE: return parent; default: // 11 Tree.Kinds are CompoundAssignmentTrees, // so use instanceof rather than listing all 11. if (parent instanceof CompoundAssignmentTree) { return parent; } return null; } }
public TernaryExpressionNode( ConditionalExpressionTree tree, Node condition, Node thenOperand, Node elseOperand) { super(InternalUtils.typeOf(tree)); assert tree.getKind().equals(Kind.CONDITIONAL_EXPRESSION); this.tree = tree; this.condition = condition; this.thenOperand = thenOperand; this.elseOperand = elseOperand; }
@Override public Void visitConditionalExpression(ConditionalExpressionTree expected, Tree actual) { Optional<ConditionalExpressionTree> other = checkTypeAndCast(expected, actual); if (!other.isPresent()) { addTypeMismatch(expected, actual); return null; } scan(expected.getCondition(), other.get().getCondition()); scan(expected.getTrueExpression(), other.get().getTrueExpression()); scan(expected.getFalseExpression(), other.get().getFalseExpression()); return null; }
@Override public Void visitConditionalExpression(ConditionalExpressionTree node, EnumSet<UseTypes> p) { return super.visitConditionalExpression(node, EnumSet.of(UseTypes.READ)); }
@Override public Object visitConditionalExpression(ConditionalExpressionTree node, Object p) { complexity++; return super.visitConditionalExpression(node, p); }