List<PreContract> (final List<ValueConstraint[]> states, @Nullable LighterASTNode expr) { if (expr == null) return emptyList(); if (states.isEmpty()) return emptyList(); if (states.size() > 300) return emptyList(); // too complex IElementType type = expr.getTokenType(); if (type == POLYADIC_EXPRESSION || type == BINARY_EXPRESSION) { return visitPolyadic(states, expr); } if (type == CONDITIONAL_EXPRESSION) { List<LighterASTNode> children = getExpressionChildren(myTree, expr); if (children.size() != 3) return emptyList(); List<PreContract> conditionResults = visitExpression(states, children.get(0)); return ContainerUtil.concat( visitExpression(antecedentsReturning(conditionResults, returnTrue()), children.get(1)), visitExpression(antecedentsReturning(conditionResults, returnFalse()), children.get(2))); } if (type == PARENTH_EXPRESSION) { return visitExpression(states, findExpressionChild(myTree, expr)); } if (type == TYPE_CAST_EXPRESSION && !isPrimitiveCast(myTree, expr)) { return visitExpression(states, findExpressionChild(myTree, expr)); } if (isNegationExpression(expr)) { return ContainerUtil.mapNotNull(visitExpression(states, findExpressionChild(myTree, expr)), PreContract::negate); } if (type == INSTANCE_OF_EXPRESSION) { final int parameter = resolveParameter(findExpressionChild(myTree, expr)); if (parameter >= 0) { return asPreContracts(ContainerUtil.mapNotNull(states, state -> contractWithConstraint(state, parameter, NULL_VALUE, returnFalse()))); } } if (type == NEW_EXPRESSION) { return asPreContracts(toContracts(states, returnNew())); } if (type == THIS_EXPRESSION) { return asPreContracts(toContracts(states, returnThis())); } if (type == METHOD_CALL_EXPRESSION) { return singletonList(new MethodCallContract(ExpressionRange.create(expr, myBody.getStartOffset()), ContainerUtil.map(states, Arrays::asList))); } final ValueConstraint constraint = getLiteralConstraint(expr); if (constraint != null) { return asPreContracts(toContracts(states, constraint.asReturnValue())); } int paramIndex = resolveParameter(expr); if (paramIndex >= 0) { List<StandardMethodContract> result = new ArrayList<>(); for (ValueConstraint[] state : states) { if (state[paramIndex] == TRUE_VALUE || state[paramIndex] == FALSE_VALUE || state[paramIndex] == NULL_VALUE) { // like "if(x == null) return x": no need to refer to parameter result.add(new StandardMethodContract(state, state[paramIndex].asReturnValue())); } else if (JavaTokenType.BOOLEAN_KEYWORD == getPrimitiveParameterType(paramIndex)) { // if (boolValue) ... ContainerUtil.addIfNotNull(result, contractWithConstraint(state, paramIndex, TRUE_VALUE, returnTrue())); ContainerUtil.addIfNotNull(result, contractWithConstraint(state, paramIndex, FALSE_VALUE, returnFalse())); } else { result.add(new StandardMethodContract(state, returnParameter(paramIndex))); } } return asPreContracts(result); } return emptyList(); }