ThreeState (@NotNull PsiExpression ancestor, @NotNull PsiExpression expression) { if (expression == ancestor) return ThreeState.YES; if (PsiUtil.isConstantExpression(expression)) return ThreeState.YES; for (PsiVariable variable : VariableAccessUtils.collectUsedVariables(expression)) { if (variable instanceof PsiPatternVariable && PsiTreeUtil.isAncestor(ancestor, variable, true) && !PsiTreeUtil.isAncestor(expression, variable, true)) { // Pattern variable is used which is declared inside ancestor; cannot reorder return ThreeState.NO; } } PsiElement parent = expression.getParent(); if (parent instanceof PsiExpressionList) { PsiExpression gParent = ObjectUtils.tryCast(parent.getParent(), PsiCallExpression.class); if (gParent != null) { PsiExpression[] args = ((PsiExpressionList)parent).getExpressions(); int index = ArrayUtil.indexOf(args, expression); ThreeState result = ThreeState.YES; for (int i=0; i<index; i++) { if (SideEffectChecker.mayHaveSideEffects(args[i])) { result = ThreeState.UNSURE; break; } } return and(result, () -> canExtract(ancestor, gParent)); } } PsiExpression expressionParent = ObjectUtils.tryCast(parent, PsiExpression.class); if (expressionParent == null) { if (PsiTreeUtil.isAncestor(ancestor, expression, true)) { return ThreeState.UNSURE; } throw new IllegalArgumentException("Should be an ancestor"); } if (expressionParent instanceof PsiParenthesizedExpression || expressionParent instanceof PsiInstanceOfExpression || expressionParent instanceof PsiTypeCastExpression) { return canExtract(ancestor, expressionParent); } if (expressionParent instanceof PsiReferenceExpression) { if (((PsiReferenceExpression)expressionParent).getQualifierExpression() == expression) { return canExtract(ancestor, expressionParent); } } if (expressionParent instanceof PsiConditionalExpression ternary) { PsiExpression condition = ternary.getCondition(); if (condition == expression) { return canExtract(ancestor, expressionParent); } ThreeState result; if (isSideEffectFree(condition, false) && isSideEffectFree(expression, false)) { result = ThreeState.YES; } else { boolean isNecessary = areConditionsNecessaryFor(new PsiExpression[]{condition}, expression, ternary.getElseExpression() == expression); result = isNecessary ? ThreeState.NO : ThreeState.UNSURE; } return and(result, () -> canExtract(ancestor, expressionParent)); } if (expressionParent instanceof PsiLambdaExpression) { return ThreeState.NO; } if (expressionParent instanceof PsiUnaryExpression) { if (PsiUtil.isIncrementDecrementOperation(expressionParent)) return ThreeState.NO; return canExtract(ancestor, expressionParent); } if (expressionParent instanceof PsiPolyadicExpression polyadic) { PsiExpression[] operands = polyadic.getOperands(); int index = ArrayUtil.indexOf(operands, expression); if (index == 0) { return canExtract(ancestor, expressionParent); } IElementType tokenType = polyadic.getOperationTokenType(); if (tokenType.equals(JavaTokenType.ANDAND) || tokenType.equals(JavaTokenType.OROR)) { return and(canMoveToStart(polyadic, index), () -> canExtract(ancestor, expressionParent)); } ThreeState result = ThreeState.YES; for (int i=0; i<index; i++) { if (SideEffectChecker.mayHaveSideEffects(operands[i])) { result = ThreeState.UNSURE; break; } } return and(result, () -> canExtract(ancestor, expressionParent)); } if (expressionParent instanceof PsiAssignmentExpression) { if (expression == ((PsiAssignmentExpression)expressionParent).getLExpression()) return ThreeState.NO; return canExtract(ancestor, expressionParent); } return and(ThreeState.UNSURE, () -> canExtract(ancestor, expressionParent)); }