@Override public Optional<String> extractTextFromElement(PsiElement element, boolean concatString, boolean stripWhitespace) { if (element instanceof PsiLiteralExpression) { // need the entire line so find the literal expression that would hold the entire string (java) PsiLiteralExpression literal = (PsiLiteralExpression) element; Object o = literal.getValue(); String text = o != null ? o.toString() : null; if (text == null) { return Optional.empty(); } if (concatString) { final PsiPolyadicExpression parentOfType = PsiTreeUtil.getParentOfType(element, PsiPolyadicExpression.class); if (parentOfType != null) { text = parentOfType.getText(); } } // unwrap literal string which can happen in java too if (stripWhitespace) { return Optional.ofNullable(getInnerText(text)); } return Optional.of(StringUtil.unquoteString(text.replace(QUOT, "\""))); } return Optional.empty(); }
/** * Extract the text value from the {@link PsiElement} from any of the support languages this plugin works with. * * @param element the element * @param fallBackToGeneric if could find any of the supported languages fallback to generic if true * @param concatString concatenated the string if it wrapped * @param stripWhitespace * @return the text or <tt>null</tt> if the element is not a text/literal kind. */ @Nullable public String extractTextFromElement(PsiElement element, boolean fallBackToGeneric, boolean concatString, boolean stripWhitespace) { return enabledExtensions.stream() .map(extension -> extension.extractTextFromElement(element, concatString, stripWhitespace)) .filter(Optional::isPresent) .map(Optional::get) .findFirst().orElseGet(() -> { if (fallBackToGeneric) { // fallback to generic String text = element.getText(); if (concatString) { final PsiPolyadicExpression parentOfType = PsiTreeUtil.getParentOfType(element, PsiPolyadicExpression.class); if (parentOfType != null) { text = parentOfType.getText(); } } // the text may be quoted so unwrap that if (stripWhitespace) { return getInnerText(text); } return StringUtil.unquoteString(text.replace(QUOT, "\"")); } return null; }); }
@Override public void visitPolyadicExpression(PsiPolyadicExpression expression) { super.visitPolyadicExpression(expression); final IElementType tokenType = expression.getOperationTokenType(); if (!tokenType.equals(JavaTokenType.AND) && !tokenType.equals(JavaTokenType.OR)) { return; } final PsiType type = expression.getType(); if (type == null) { return; } if (!type.equals(PsiType.BOOLEAN)) { return; } registerError(expression); }
@Override public void visitPolyadicExpression(PsiPolyadicExpression expression) { super.visitPolyadicExpression(expression); if (!ComparisonUtils.isEqualityComparison(expression)) { return; } final PsiElement parent = expression.getParent(); if (parent instanceof PsiExpression) { if (ComparisonUtils.isEqualityComparison((PsiExpression)parent)) { return; } } final PsiExpression[] operands = expression.getOperands(); if (operands.length >= 3) { registerError(expression); } else { for (PsiExpression operand : operands) { if (ComparisonUtils.isEqualityComparison(operand)) { registerError(expression); break; } } } }
@Override public void processIntention(@NotNull PsiElement element) { final PsiJavaToken token = (PsiJavaToken)element; final PsiElement parent = token.getParent(); if (!(parent instanceof PsiPolyadicExpression)) { return; } final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)parent; final PsiExpression[] operands = polyadicExpression.getOperands(); final StringBuilder newExpression = new StringBuilder(); String prevOperand = null; final String tokenText = token.getText() + ' '; // 2- -1 without the space is not legal for (PsiExpression operand : operands) { final PsiJavaToken token1 = polyadicExpression.getTokenBeforeOperand(operand); if (token == token1) { newExpression.append(operand.getText()).append(tokenText); continue; } if (prevOperand != null) { newExpression.append(prevOperand).append(tokenText); } prevOperand = operand.getText(); } newExpression.append(prevOperand); PsiReplacementUtil.replaceExpression(polyadicExpression, newExpression.toString()); }
public boolean satisfiedBy(PsiElement element) { if (!(element instanceof PsiJavaToken)) { return false; } final PsiElement parent = element.getParent(); if (!(parent instanceof PsiPolyadicExpression)) { return false; } final PsiPolyadicExpression expression = (PsiPolyadicExpression)parent; final PsiExpression[] operands = expression.getOperands(); if (operands.length < 2) { return false; } PsiExpression prevOperand = null; for (PsiExpression operand : operands) { final PsiJavaToken token = expression.getTokenBeforeOperand(operand); if (element == token) { if (prevOperand == null || operand.getText().equals(prevOperand.getText())) { return false; } break; } prevOperand = operand; } return !ComparisonUtils.isComparison(expression); }
@Override public void processIntention(@NotNull PsiElement element) { final PsiJavaToken token = (PsiJavaToken)element; final PsiElement parent = token.getParent(); if (!(parent instanceof PsiPolyadicExpression)) { return; } final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)parent; final PsiExpression[] operands = polyadicExpression.getOperands(); final StringBuilder newExpression = new StringBuilder(); String prevOperand = null; final String tokenText = token.getText() + ' '; // 2- -1 without the space is not legal for (PsiExpression operand : operands) { final PsiJavaToken token1 = polyadicExpression.getTokenBeforeOperand(operand); if (token == token1) { newExpression.append(operand.getText()).append(tokenText); continue; } if (prevOperand != null) { newExpression.append(prevOperand).append(tokenText); } prevOperand = operand.getText(); } newExpression.append(prevOperand); replaceExpression(newExpression.toString(), polyadicExpression); }
/** * Allows to check if given {@code AST} nodes refer to binary expressions which have the same priority. * * @param node1 node to check * @param node2 node to check * @return {@code true} if given nodes are binary expressions and have the same priority; * {@code false} otherwise */ public static boolean areSamePriorityBinaryExpressions(ASTNode node1, ASTNode node2) { if(node1 == null || node2 == null) { return false; } if(!(node1 instanceof PsiPolyadicExpression) || !(node2 instanceof PsiPolyadicExpression)) { return false; } PsiPolyadicExpression expression1 = (PsiPolyadicExpression) node1; PsiPolyadicExpression expression2 = (PsiPolyadicExpression) node2; return expression1.getOperationTokenType() == expression2.getOperationTokenType(); }
@Nullable static PsiPolyadicExpression getSubexpression(PsiPolyadicExpression expression, PsiJavaToken token) { final PsiExpression[] operands = expression.getOperands(); if (operands.length == 2) { return expression; } for (int i = 1; i < operands.length; i++) { final PsiExpression operand = operands[i]; final PsiJavaToken currentToken = expression.getTokenBeforeOperand(operand); if (currentToken == token) { final String binaryExpressionText = operands[i - 1].getText() + ' ' + token.getText() + ' ' + operand.getText(); final PsiElementFactory factory = JavaPsiFacade.getElementFactory(expression.getProject()); return (PsiPolyadicExpression)factory.createExpressionFromText(binaryExpressionText, expression); } } return null; }
private static boolean isPartOfLargerExpression(PsiPolyadicExpression expression) { if (expression.getOperands().length > 2) { return true; } final PsiElement containingElement = expression.getParent(); if (containingElement instanceof PsiExpression) { final PsiExpression containingExpression = (PsiExpression)containingElement; if (!PsiUtil.isConstantExpression(containingExpression)) { return false; } } else { return false; } return true; }
@Override protected void processIntention(@NotNull PsiElement element) throws IncorrectOperationException { if (!(element instanceof PsiPolyadicExpression)) { return; } PsiPolyadicExpression concatenationExpression = (PsiPolyadicExpression)element; final IElementType tokenType = concatenationExpression.getOperationTokenType(); if (tokenType != JavaTokenType.PLUS) { return; } final PsiType type = concatenationExpression.getType(); if (type == null || !type.equalsToText("java.lang.String")) { return; } final StringBuilder text = buildConcatenationText(concatenationExpression, new StringBuilder()); CopyPasteManager.getInstance().setContents(new StringSelection(text.toString())); }
private static StringBuilder buildConcatenationText(PsiPolyadicExpression polyadicExpression, StringBuilder out) { for (PsiElement element : polyadicExpression.getChildren()) { if (element instanceof PsiExpression) { final PsiExpression expression = (PsiExpression)element; final Object value = ExpressionUtils.computeConstantExpression(expression); if (value == null) { out.append('?'); } else { out.append(value.toString()); } } else if (element instanceof PsiWhiteSpace && element.getText().contains("\n") && (out.length() == 0 || out.charAt(out.length() - 1) != '\n')) { out.append('\n'); } } return out; }
@Override public void doFix(@NotNull Project project, ProblemDescriptor descriptor) throws IncorrectOperationException { final PsiElement element = descriptor.getPsiElement(); if (!(element instanceof PsiAssignmentExpression)) { return; } final PsiAssignmentExpression expression = (PsiAssignmentExpression)element; final PsiExpression lhs = expression.getLExpression(); PsiExpression rhs = ParenthesesUtils.stripParentheses(expression.getRExpression()); if (rhs instanceof PsiTypeCastExpression) { final PsiTypeCastExpression typeCastExpression = (PsiTypeCastExpression)rhs; final PsiType castType = typeCastExpression.getType(); if (castType == null || !castType.equals(lhs.getType())) { return; } rhs = ParenthesesUtils.stripParentheses(typeCastExpression.getOperand()); } if (!(rhs instanceof PsiPolyadicExpression)) { return; } final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)rhs; final String newExpression = calculateReplacementExpression(lhs, polyadicExpression); replaceExpression(expression, newExpression); }
private static void collectConditions(PsiExpression condition, Set<PsiExpression> conditions, IElementType tokenType) { if (condition == null) { return; } if (condition instanceof PsiParenthesizedExpression) { final PsiParenthesizedExpression parenthesizedExpression = (PsiParenthesizedExpression)condition; final PsiExpression contents = parenthesizedExpression.getExpression(); collectConditions(contents, conditions, tokenType); return; } if (condition instanceof PsiPolyadicExpression) { final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)condition; final IElementType testTokeType = polyadicExpression.getOperationTokenType(); if (testTokeType.equals(tokenType)) { final PsiExpression[] operands = polyadicExpression.getOperands(); for (PsiExpression operand : operands) { collectConditions(operand, conditions, tokenType); } return; } } conditions.add(condition); }
private void collectConditionsForExpression(PsiExpression condition, Set<PsiExpression> conditions) { if (condition == null) { return; } if (condition instanceof PsiParenthesizedExpression) { final PsiParenthesizedExpression parenthesizedExpression = (PsiParenthesizedExpression)condition; final PsiExpression contents = parenthesizedExpression.getExpression(); collectConditionsForExpression(contents, conditions); return; } if (condition instanceof PsiPolyadicExpression) { final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)condition; final IElementType tokenType = polyadicExpression.getOperationTokenType(); if (JavaTokenType.OROR.equals(tokenType)) { final PsiExpression[] operands = polyadicExpression.getOperands(); for (PsiExpression operand : operands) { collectConditionsForExpression(operand, conditions); } return; } } conditions.add(condition); }
/** * Returns the first operand from a {@link PsiPolyadicExpression} * * @param psiLiteralExpression the {@link PsiLiteralExpression} that is part of a {@link PsiPolyadicExpression} * @return the first {@link PsiExpression} if the given {@link PsiLiteralExpression} is part of a {@link PsiPolyadicExpression}, null otherwise */ @Nullable private static PsiExpression getFirstExpressionFromPolyadicExpression(PsiLiteralExpression psiLiteralExpression) { if (isPartOfPolyadicExpression(psiLiteralExpression)) { PsiPolyadicExpression psiPolyadicExpression = PsiTreeUtil.getParentOfType(psiLiteralExpression, PsiPolyadicExpression.class); if (psiPolyadicExpression != null) { return psiPolyadicExpression.getOperands()[0]; } } return null; }
@Override public boolean isApplicableTo(PsiElement e) { if (!(e.getParent() instanceof PsiPolyadicExpression)) { return false; } final PsiPolyadicExpression expression = (PsiPolyadicExpression)e.getParent(); final PsiExpression operand = findOperand(e, expression); return operand != null; }
@Override protected void doUnwrap(PsiElement element, Context context) throws IncorrectOperationException { final PsiPolyadicExpression parent = (PsiPolyadicExpression)element.getParent(); final PsiExpression operand = findOperand(element, parent); if (operand == null) { return; } context.extractElement(operand, parent); context.delete(parent); }
@Nullable private static PsiExpression findOperand(@NotNull PsiElement e, @NotNull PsiPolyadicExpression expression) { final TextRange elementTextRange = e.getTextRange(); for (PsiExpression operand : expression.getOperands()) { final TextRange operandTextRange = operand.getTextRange(); if (operandTextRange != null && operandTextRange.contains(elementTextRange)) { return operand; } } return null; }
/** * Allows to check if given <code>AST</code> nodes refer to binary expressions which have the same priority. * * @param node1 node to check * @param node2 node to check * @return <code>true</code> if given nodes are binary expressions and have the same priority; * <code>false</code> otherwise */ public static boolean areSamePriorityBinaryExpressions(ASTNode node1, ASTNode node2) { if (node1 == null || node2 == null) { return false; } if (!(node1 instanceof PsiPolyadicExpression) || !(node2 instanceof PsiPolyadicExpression)) { return false; } PsiPolyadicExpression expression1 = (PsiPolyadicExpression)node1; PsiPolyadicExpression expression2 = (PsiPolyadicExpression)node2; return expression1.getOperationTokenType() == expression2.getOperationTokenType(); }
@NotNull @Override protected InspectionGadgetsFix[] buildFixes(Object... infos) { final InspectionGadgetsFix[] fixes = super.buildFixes(infos); final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)infos[0]; final SuppressForTestsScopeFix suppressFix = SuppressForTestsScopeFix.build(this, polyadicExpression); if (suppressFix == null) { return fixes; } final InspectionGadgetsFix[] newFixes = Arrays.copyOf(fixes, fixes.length + 1); newFixes[fixes.length] = suppressFix; return newFixes; }
@Override public void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException { final PsiPolyadicExpression expression = (PsiPolyadicExpression)descriptor.getPsiElement(); final IElementType tokenType = expression.getOperationTokenType(); final String operandText = getShortCircuitOperand(tokenType); final PsiExpression[] operands = expression.getOperands(); final StringBuilder newExpression = new StringBuilder(); for (PsiExpression operand : operands) { if (newExpression.length() != 0) { newExpression.append(operandText); } newExpression.append(operand.getText()); } PsiReplacementUtil.replaceExpression(expression, newExpression.toString()); }
public static boolean isComparison(@Nullable PsiExpression expression) { if (!(expression instanceof PsiPolyadicExpression)) { return false; } final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)expression; final IElementType tokenType = polyadicExpression.getOperationTokenType(); return isComparisonOperation(tokenType); }
public static boolean isEqualityComparison(@NotNull PsiExpression expression) { if (!(expression instanceof PsiPolyadicExpression)) { return false; } final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)expression; final IElementType tokenType = polyadicExpression.getOperationTokenType(); return tokenType.equals(JavaTokenType.EQEQ) || tokenType.equals(JavaTokenType.NE); }
public boolean satisfiedBy(PsiElement element) { if (!(element instanceof PsiPolyadicExpression)) { return false; } final PsiPolyadicExpression expression = (PsiPolyadicExpression)element; final IElementType tokenType = expression.getOperationTokenType(); if (!tokenType.equals(JavaTokenType.ANDAND) && !tokenType.equals(JavaTokenType.OROR)) { return false; } return !ErrorUtil.containsError(element); }
@Override public String getTextForElement(PsiElement element) { final PsiPolyadicExpression expression = (PsiPolyadicExpression)element.getParent(); final PsiExpression[] operands = expression.getOperands(); final PsiJavaToken sign = expression.getTokenBeforeOperand(operands[1]); final String operatorText = sign == null ? "" : sign.getText(); final IElementType tokenType = expression.getOperationTokenType(); final boolean commutative = ParenthesesUtils.isCommutativeOperator(tokenType); if (commutative && !ExpressionUtils.isConcatenation(expression)) { return IntentionPowerPackBundle.message("flip.smth.intention.name", operatorText); } else { return IntentionPowerPackBundle.message("flip.smth.intention.name1", operatorText); } }
@Override public void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException { final PsiPolyadicExpression expression = (PsiPolyadicExpression)descriptor.getPsiElement(); final IElementType tokenType = expression.getOperationTokenType(); final String operandText = getShortCircuitOperand(tokenType); final PsiExpression[] operands = expression.getOperands(); final StringBuilder newExpression = new StringBuilder(); for (PsiExpression operand : operands) { if (newExpression.length() != 0) { newExpression.append(operandText); } newExpression.append(operand.getText()); } replaceExpression(expression, newExpression.toString()); }
public static boolean isComparison(@Nullable PsiExpression expression) { if (!(expression instanceof PsiPolyadicExpression)) { return false; } final PsiPolyadicExpression binaryExpression = (PsiPolyadicExpression)expression; final IElementType tokenType = binaryExpression.getOperationTokenType(); return isComparisonOperation(tokenType); }
@Override public String getTextForElement(PsiElement element) { final PsiPolyadicExpression expression = (PsiPolyadicExpression)element.getParent(); final PsiExpression[] operands = expression.getOperands(); final PsiJavaToken sign = expression.getTokenBeforeOperand(operands[1]); final String operatorText = sign == null ? "" : sign.getText(); final IElementType tokenType = expression.getOperationTokenType(); final boolean commutative = ParenthesesUtils.isCommutativeOperator(tokenType); if (commutative && !ConcatenationUtils.isConcatenation(expression)) { return IntentionPowerPackBundle.message("flip.smth.intention.name", operatorText); } else { return IntentionPowerPackBundle.message("flip.smth.intention.name1", operatorText); } }