Search in sources :

Example 1 with BinaryExpression

use of com.jetbrains.php.lang.psi.elements.BinaryExpression in project phpinspectionsea by kalessil.

the class IssetAndNullComparisonStrategy method apply.

public static boolean apply(@NotNull List<PsiElement> conditions, @NotNull ProblemsHolder holder) {
    /* first ensure that we have null identity checks at all */
    final Map<PsiElement, PsiElement> nullTestSubjects = new HashMap<>();
    for (final PsiElement oneCondition : conditions) {
        if (oneCondition instanceof BinaryExpression) {
            final BinaryExpression expression = (BinaryExpression) oneCondition;
            /* we need only !== and === operations */
            final IElementType operator = expression.getOperationType();
            if (operator != PhpTokenTypes.opIDENTICAL && operator != PhpTokenTypes.opNOT_IDENTICAL) {
                continue;
            }
            /* quickly check if any operands is a constant */
            final PsiElement left = expression.getLeftOperand();
            final PsiElement right = expression.getRightOperand();
            if (!(left instanceof ConstantReference) && !(right instanceof ConstantReference)) {
                continue;
            }
            /* store null test subjects */
            if (PhpLanguageUtil.isNull(right)) {
                if (null != left) {
                    nullTestSubjects.put(expression, left);
                }
                continue;
            }
            if (PhpLanguageUtil.isNull(left)) {
                if (null != right) {
                    nullTestSubjects.put(expression, right);
                }
            // continue;
            }
        }
    }
    if (0 == nullTestSubjects.size()) {
        return false;
    }
    boolean hasReportedExpressions = false;
    for (final PsiElement oneCondition : conditions) {
        /* do not process null identity checks */
        if (nullTestSubjects.containsKey(oneCondition)) {
            continue;
        }
        /* unwrap ! and () */
        PsiElement issetCandidate = oneCondition;
        if (issetCandidate instanceof UnaryExpression) {
            final PsiElement notOperatorCandidate = ((UnaryExpression) issetCandidate).getOperation();
            if (null != notOperatorCandidate && notOperatorCandidate.getNode().getElementType() == PhpTokenTypes.opNOT) {
                PsiElement invertedValue = ((UnaryExpression) issetCandidate).getValue();
                invertedValue = ExpressionSemanticUtil.getExpressionTroughParenthesis(invertedValue);
                if (null == invertedValue) {
                    continue;
                }
                issetCandidate = invertedValue;
            }
        }
        if (!(issetCandidate instanceof PhpIsset) || 0 == ((PhpIsset) issetCandidate).getVariables().length) {
            continue;
        }
        /* process isset constructions */
        for (final PsiElement issetArgument : ((PhpIsset) issetCandidate).getVariables()) {
            /* compare with know null identity checked subjects */
            for (final Map.Entry<PsiElement, PsiElement> nullTestPair : nullTestSubjects.entrySet()) {
                if (!OpeanapiEquivalenceUtil.areEqual(nullTestPair.getValue(), issetArgument)) {
                    continue;
                }
                hasReportedExpressions = true;
                final PsiElement nullTestExpression = nullTestPair.getKey();
                final String message = messagePattern.replace("%e%", nullTestExpression.getText());
                holder.registerProblem(nullTestExpression, message, ProblemHighlightType.WEAK_WARNING);
            }
        }
    }
    nullTestSubjects.clear();
    return hasReportedExpressions;
}
Also used : IElementType(com.intellij.psi.tree.IElementType) ConstantReference(com.jetbrains.php.lang.psi.elements.ConstantReference) BinaryExpression(com.jetbrains.php.lang.psi.elements.BinaryExpression) HashMap(java.util.HashMap) UnaryExpression(com.jetbrains.php.lang.psi.elements.UnaryExpression) HashMap(java.util.HashMap) Map(java.util.Map) PsiElement(com.intellij.psi.PsiElement) PhpIsset(com.jetbrains.php.lang.psi.elements.PhpIsset)

Example 2 with BinaryExpression

use of com.jetbrains.php.lang.psi.elements.BinaryExpression in project phpinspectionsea by kalessil.

the class AdditionOperationOnArraysInspection method buildVisitor.

@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
    return new BasePhpElementVisitor() {

        @Override
        public void visitPhpBinaryExpression(@NotNull BinaryExpression expression) {
            final PsiElement operation = expression.getOperation();
            if (OpenapiTypesUtil.is(operation, PhpTokenTypes.opPLUS)) {
                /* do not check nested operations */
                final boolean isNestedBinary = expression.getParent() instanceof BinaryExpression;
                if (!isNestedBinary) {
                    /* do not report ' ... + []' and '[] + ...' */
                    final PsiElement right = expression.getRightOperand();
                    PsiElement left = expression.getLeftOperand();
                    while (left instanceof BinaryExpression) {
                        left = ((BinaryExpression) left).getLeftOperand();
                    }
                    if (left != null && right != null) {
                        final boolean addsImplicitArray = left instanceof ArrayCreationExpression || right instanceof ArrayCreationExpression;
                        if (!addsImplicitArray) {
                            this.inspectExpression(operation, expression);
                        }
                    }
                }
            }
        }

        @Override
        public void visitPhpSelfAssignmentExpression(@NotNull SelfAssignmentExpression expression) {
            final PsiElement operation = expression.getOperation();
            if (OpenapiTypesUtil.is(operation, PhpTokenTypes.opPLUS_ASGN)) {
                /* do not report '... += []' */
                final boolean addsImplicitArray = expression.getValue() instanceof ArrayCreationExpression;
                if (!addsImplicitArray) {
                    this.inspectExpression(operation, expression);
                }
            }
        }

        /* inspection itself */
        private void inspectExpression(@NotNull PsiElement operation, @NotNull PsiElement expression) {
            if (expression instanceof PhpTypedElement) {
                final Set<String> types = new HashSet<>();
                final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) expression, holder.getProject());
                if (resolved != null) {
                    resolved.filterUnknown().getTypes().forEach(t -> types.add(Types.getType(t)));
                }
                if (types.size() == 1 && types.contains(Types.strArray)) {
                    holder.registerProblem(operation, message);
                }
                types.clear();
            }
        }
    };
}
Also used : SelfAssignmentExpression(com.jetbrains.php.lang.psi.elements.SelfAssignmentExpression) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) BinaryExpression(com.jetbrains.php.lang.psi.elements.BinaryExpression) ArrayCreationExpression(com.jetbrains.php.lang.psi.elements.ArrayCreationExpression) PhpTypedElement(com.jetbrains.php.lang.psi.elements.PhpTypedElement) NotNull(org.jetbrains.annotations.NotNull) PsiElement(com.intellij.psi.PsiElement) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) HashSet(java.util.HashSet) NotNull(org.jetbrains.annotations.NotNull)

Example 3 with BinaryExpression

use of com.jetbrains.php.lang.psi.elements.BinaryExpression in project phpinspectionsea by kalessil.

the class IsIterableCanBeUsedInspector method buildVisitor.

@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
    return new BasePhpElementVisitor() {

        @Override
        public void visitPhpFunctionCall(@NotNull FunctionReference reference) {
            final String functionName = reference.getName();
            if (functionName != null && functionName.equals("is_array")) {
                final boolean isTargetVersion = PhpLanguageLevel.get(holder.getProject()).atLeast(PhpLanguageLevel.PHP710);
                if (isTargetVersion) {
                    final PsiElement[] arguments = reference.getParameters();
                    final PsiElement parent = reference.getParent();
                    if (parent instanceof BinaryExpression && arguments.length == 1) {
                        final BinaryExpression binary = (BinaryExpression) parent;
                        final IElementType operation = binary.getOperationType();
                        if (operation == PhpTokenTypes.opOR) {
                            /* find the high-level binary expression */
                            BinaryExpression context = binary;
                            while (context instanceof BinaryExpression) {
                                PsiElement up = context.getParent();
                                while (up instanceof ParenthesizedExpression) {
                                    up = up.getParent();
                                }
                                if (up instanceof BinaryExpression && ((BinaryExpression) up).getOperationType() == PhpTokenTypes.opOR) {
                                    context = (BinaryExpression) up;
                                } else {
                                    break;
                                }
                            }
                            /* check the pattern */
                            final List<PsiElement> fragments = this.extract(context, PhpTokenTypes.opOR);
                            if (!fragments.isEmpty()) {
                                if (fragments.size() > 1) {
                                    for (final PsiElement fragment : fragments) {
                                        if (fragment != reference && fragment instanceof BinaryExpression) {
                                            final BinaryExpression candidate = (BinaryExpression) fragment;
                                            if (candidate.getOperationType() == PhpTokenTypes.kwINSTANCEOF) {
                                                final PsiElement clazz = candidate.getRightOperand();
                                                if (clazz instanceof ClassReference && "Traversable".equals(((ClassReference) clazz).getName())) {
                                                    final PsiElement subject = candidate.getLeftOperand();
                                                    if (subject != null && OpenapiEquivalenceUtil.areEqual(subject, arguments[0])) {
                                                        final String argument = subject.getText();
                                                        holder.registerProblem(reference, String.format(MessagesPresentationUtil.prefixWithEa(message), argument, argument, argument));
                                                        break;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                                fragments.clear();
                            }
                        }
                    }
                }
            }
        }

        @NotNull
        private List<PsiElement> extract(@NotNull BinaryExpression binary, @Nullable IElementType operator) {
            final List<PsiElement> result = new ArrayList<>();
            if (binary.getOperationType() == operator) {
                Stream.of(binary.getLeftOperand(), binary.getRightOperand()).filter(Objects::nonNull).map(ExpressionSemanticUtil::getExpressionTroughParenthesis).forEach(expression -> {
                    if (expression instanceof BinaryExpression) {
                        result.addAll(this.extract((BinaryExpression) expression, operator));
                    } else {
                        result.add(expression);
                    }
                });
            } else {
                result.add(binary);
            }
            return result;
        }
    };
}
Also used : ParenthesizedExpression(com.jetbrains.php.lang.psi.elements.ParenthesizedExpression) ArrayList(java.util.ArrayList) NotNull(org.jetbrains.annotations.NotNull) IElementType(com.intellij.psi.tree.IElementType) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) BinaryExpression(com.jetbrains.php.lang.psi.elements.BinaryExpression) Objects(java.util.Objects) FunctionReference(com.jetbrains.php.lang.psi.elements.FunctionReference) ClassReference(com.jetbrains.php.lang.psi.elements.ClassReference) PsiElement(com.intellij.psi.PsiElement) Nullable(org.jetbrains.annotations.Nullable) NotNull(org.jetbrains.annotations.NotNull)

Example 4 with BinaryExpression

use of com.jetbrains.php.lang.psi.elements.BinaryExpression in project phpinspectionsea by kalessil.

the class SubStrShortHandUsageInspector method buildVisitor.

@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
    return new BasePhpElementVisitor() {

        @Override
        public void visitPhpFunctionCall(@NotNull FunctionReference reference) {
            final String functionName = reference.getName();
            if (functionName != null && substringFunctions.contains(functionName)) {
                final PsiElement[] arguments = reference.getParameters();
                if ((arguments.length == 3 || arguments.length == 4) && arguments[2] instanceof BinaryExpression) {
                    /* check if 3rd argument is "strlen($search) - strlen(...)": "strlen($search)" is not needed */
                    final BinaryExpression binary = (BinaryExpression) arguments[2];
                    if (binary.getOperationType() == PhpTokenTypes.opMINUS) {
                        final PsiElement left = binary.getLeftOperand();
                        final PsiElement right = binary.getRightOperand();
                        if (right != null && OpenapiTypesUtil.isFunctionReference(left)) {
                            final FunctionReference leftCall = (FunctionReference) left;
                            final String leftName = leftCall.getName();
                            if (leftName != null && lengthFunctions.contains(leftName)) {
                                final PsiElement[] leftArguments = leftCall.getParameters();
                                if (leftArguments.length == 1 && OpenapiEquivalenceUtil.areEqual(leftArguments[0], arguments[0])) {
                                    final PsiElement startOffset = arguments[1];
                                    if (OpenapiEquivalenceUtil.areEqual(right, startOffset)) {
                                        /* case: third parameter is not needed at all */
                                        holder.registerProblem(arguments[2], String.format(MessagesPresentationUtil.prefixWithEa(patternDropLength), arguments[2].getText()), ProblemHighlightType.LIKE_UNUSED_SYMBOL, new DropThirdParameterFix(holder.getProject(), reference));
                                    } else if (OpenapiTypesUtil.isNumber(startOffset) && OpenapiTypesUtil.isNumber(right)) {
                                        try {
                                            int offset = Integer.parseInt(startOffset.getText()) - Integer.parseInt(right.getText());
                                            if (offset < 0) {
                                                /* case: third parameter can be simplified */
                                                holder.registerProblem(binary, String.format(MessagesPresentationUtil.prefixWithEa(patternSimplifyLength), offset), new SimplifyFix(String.valueOf(offset)));
                                            } else {
                                                /* case: third parameter is not needed at all */
                                                holder.registerProblem(arguments[2], String.format(MessagesPresentationUtil.prefixWithEa(patternDropLength), arguments[2].getText()), ProblemHighlightType.LIKE_UNUSED_SYMBOL, new DropThirdParameterFix(holder.getProject(), reference));
                                            }
                                        } catch (final NumberFormatException expected) {
                                        // return;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    };
}
Also used : BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) BinaryExpression(com.jetbrains.php.lang.psi.elements.BinaryExpression) FunctionReference(com.jetbrains.php.lang.psi.elements.FunctionReference) NotNull(org.jetbrains.annotations.NotNull) PsiElement(com.intellij.psi.PsiElement) NotNull(org.jetbrains.annotations.NotNull)

Example 5 with BinaryExpression

use of com.jetbrains.php.lang.psi.elements.BinaryExpression in project phpinspectionsea by kalessil.

the class StrContainsCanBeUsedInspector method buildVisitor.

@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
    return new BasePhpElementVisitor() {

        @Override
        public void visitPhpFunctionCall(@NotNull FunctionReference reference) {
            final String functionName = reference.getName();
            if (functionName != null && (functionName.equals("strpos") || functionName.equals("mb_strpos"))) {
                final boolean isTargetVersion = PhpLanguageLevel.get(holder.getProject()).atLeast(PhpLanguageLevel.PHP800);
                if (isTargetVersion) {
                    final PsiElement[] arguments = reference.getParameters();
                    if (arguments.length == 2) {
                        final PsiElement context = reference.getParent();
                        if (context instanceof BinaryExpression) {
                            final BinaryExpression binary = (BinaryExpression) context;
                            final IElementType operation = binary.getOperationType();
                            final boolean isTarget = (operation == PhpTokenTypes.opNOT_IDENTICAL || operation == PhpTokenTypes.opIDENTICAL) && PhpLanguageUtil.isFalse(OpenapiElementsUtil.getSecondOperand(binary, reference));
                            if (isTarget) {
                                final String replacement = String.format("%s%sstr_contains(%s, %s)", operation == PhpTokenTypes.opIDENTICAL ? "! " : "", reference.getImmediateNamespaceName(), arguments[0].getText(), arguments[1].getText());
                                holder.registerProblem(binary, String.format(MessagesPresentationUtil.prefixWithEa(message), replacement), new UseStrContainsFix(replacement));
                            }
                        }
                    }
                }
            }
        }
    };
}
Also used : IElementType(com.intellij.psi.tree.IElementType) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) BinaryExpression(com.jetbrains.php.lang.psi.elements.BinaryExpression) FunctionReference(com.jetbrains.php.lang.psi.elements.FunctionReference) NotNull(org.jetbrains.annotations.NotNull) PsiElement(com.intellij.psi.PsiElement) NotNull(org.jetbrains.annotations.NotNull)

Aggregations

BinaryExpression (com.jetbrains.php.lang.psi.elements.BinaryExpression)35 PsiElement (com.intellij.psi.PsiElement)34 IElementType (com.intellij.psi.tree.IElementType)26 BasePhpElementVisitor (com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor)25 NotNull (org.jetbrains.annotations.NotNull)25 FunctionReference (com.jetbrains.php.lang.psi.elements.FunctionReference)16 UnaryExpression (com.jetbrains.php.lang.psi.elements.UnaryExpression)9 ParenthesizedExpression (com.jetbrains.php.lang.psi.elements.ParenthesizedExpression)6 PhpType (com.jetbrains.php.lang.psi.resolve.types.PhpType)5 Nullable (org.jetbrains.annotations.Nullable)5 PhpTypedElement (com.jetbrains.php.lang.psi.elements.PhpTypedElement)4 StringLiteralExpression (com.jetbrains.php.lang.psi.elements.StringLiteralExpression)4 ProblemsHolder (com.intellij.codeInspection.ProblemsHolder)3 PsiElementVisitor (com.intellij.psi.PsiElementVisitor)3 PhpTokenTypes (com.jetbrains.php.lang.lexer.PhpTokenTypes)3 TernaryExpression (com.jetbrains.php.lang.psi.elements.TernaryExpression)3 BasePhpInspection (com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpInspection)3 ArrayList (java.util.ArrayList)3 HashSet (java.util.HashSet)3 Objects (java.util.Objects)3