Search in sources :

Example 21 with BinaryExpression

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

the class StrlenInEmptyStringCheckContextInspection 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 && (functionName.equals("strlen") || functionName.equals("mb_strlen"))) {
                final PsiElement[] arguments = reference.getParameters();
                if (arguments.length > 0 && ExpressionSemanticUtil.getBlockScope(reference) != null) {
                    boolean isMatchedPattern = false;
                    boolean isEmptyString = false;
                    PsiElement target = null;
                    /* check explicit numbers comparisons */
                    final PsiElement parent = reference.getParent();
                    if (parent instanceof BinaryExpression) {
                        final BinaryExpression binary = (BinaryExpression) parent;
                        final PsiElement left = binary.getLeftOperand();
                        final PsiElement secondOperand = OpenapiElementsUtil.getSecondOperand(binary, reference);
                        /* second operand should be a number */
                        if (OpenapiTypesUtil.isNumber(secondOperand)) {
                            final String number = secondOperand.getText();
                            /* check cases when comparing with 1 */
                            final IElementType operator = binary.getOperationType();
                            if (operator == PhpTokenTypes.opGREATER) {
                                isMatchedPattern = left == reference && number.equals("0");
                                target = binary;
                                isEmptyString = false;
                            } else if (operator == PhpTokenTypes.opLESS || operator == PhpTokenTypes.opGREATER_OR_EQUAL) {
                                isMatchedPattern = left == reference && number.equals("1");
                                target = binary;
                                isEmptyString = operator == PhpTokenTypes.opLESS;
                            }
                            /* check cases when checking equality to 0 */
                            if (!isMatchedPattern && OpenapiTypesUtil.tsCOMPARE_EQUALITY_OPS.contains(operator)) {
                                isMatchedPattern = number.equals("0");
                                target = binary;
                                isEmptyString = operator == PhpTokenTypes.opIDENTICAL || operator == PhpTokenTypes.opEQUAL;
                            }
                        }
                    }
                    /* checks NON-implicit boolean comparison patterns */
                    if (!isMatchedPattern && ExpressionSemanticUtil.isUsedAsLogicalOperand(reference)) {
                        isMatchedPattern = true;
                        target = reference;
                        final PsiElement operation = parent instanceof UnaryExpression ? ((UnaryExpression) parent).getOperation() : null;
                        if (operation != null) {
                            isEmptyString = OpenapiTypesUtil.is(operation, PhpTokenTypes.opNOT);
                            target = parent;
                        }
                    }
                    /* investigate possible issues */
                    if (isMatchedPattern) {
                        final boolean isRegular = ComparisonStyle.isRegular();
                        final String operator = (isEmptyString ? "=" : "!") + (this.canApplyIdentityOperator(arguments[0]) ? "==" : "=");
                        final String replacement = String.format(isRegular ? "%s %s ''" : "'' %s %s", isRegular ? arguments[0].getText() : operator, isRegular ? operator : arguments[0].getText());
                        holder.registerProblem(target, String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), replacement), new CompareToEmptyStringFix(replacement));
                    }
                }
            }
        }

        private boolean canApplyIdentityOperator(@NotNull PsiElement value) {
            if (value instanceof PhpTypedElement) {
                final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) value, holder.getProject());
                if (resolved != null && resolved.size() == 1) {
                    return Types.strString.equals(Types.getType(resolved.getTypes().iterator().next()));
                }
            }
            return false;
        }
    };
}
Also used : UnaryExpression(com.jetbrains.php.lang.psi.elements.UnaryExpression) NotNull(org.jetbrains.annotations.NotNull) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) 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) PhpTypedElement(com.jetbrains.php.lang.psi.elements.PhpTypedElement) PsiElement(com.intellij.psi.PsiElement) NotNull(org.jetbrains.annotations.NotNull)

Example 22 with BinaryExpression

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

the class UnclearOperationsPriorityStrategy method apply.

public static boolean apply(@NotNull BinaryExpression expression, @NotNull ProblemsHolder holder) {
    final IElementType operator = expression.getOperationType();
    final PsiElement parent = expression.getParent();
    if (operator == PhpTokenTypes.opAND || operator == PhpTokenTypes.opOR) {
        /* binary expressions, already wrapped into parentheses can be skipped */
        if (parent instanceof BinaryExpression) {
            final IElementType parentOperator = ((BinaryExpression) parent).getOperationType();
            if (parentOperator != operator && (parentOperator == PhpTokenTypes.opAND || parentOperator == PhpTokenTypes.opOR)) {
                final String replacement = '(' + expression.getText() + ')';
                holder.registerProblem(expression, MessagesPresentationUtil.prefixWithEa(message), new WrapItAsItIsFix(replacement));
                return true;
            }
        } else /* assignment dramatically changing precedence */
        if (OpenapiTypesUtil.isAssignment(parent) && !OpenapiTypesUtil.isStatementImpl(parent.getParent())) {
            final String replacement = '(' + expression.getText() + ')';
            holder.registerProblem(expression, MessagesPresentationUtil.prefixWithEa(message), new WrapItAsItIsFix(replacement));
            return true;
        }
    } else if (PhpTokenTypes.tsCOMPARE_OPS.contains(operator)) {
        if (OpenapiTypesUtil.isAssignment(parent) && parent.getParent() instanceof If) {
            final AssignmentExpression assignment = (AssignmentExpression) parent;
            final PsiElement assignedValue = assignment.getValue();
            if (assignedValue != null) {
                final String value = assignedValue.getText();
                final String replacement = assignment.getText().replace(value, '(' + value + ')');
                holder.registerProblem(parent, MessagesPresentationUtil.prefixWithEa(message), new WrapItAsItIsFix(replacement));
                return true;
            }
        } else if (PhpTokenTypes.tsCOMPARE_ORDER_OPS.contains(operator) && operator != PhpTokenTypes.opSPACESHIP) {
            final PsiElement left = expression.getLeftOperand();
            if (left instanceof UnaryExpression) {
                final UnaryExpression candidate = (UnaryExpression) left;
                if (OpenapiTypesUtil.is(candidate.getOperation(), PhpTokenTypes.opNOT)) {
                    final String value = candidate.getText();
                    final String replacement = expression.getText().replace(value, '(' + value + ')');
                    holder.registerProblem(expression, MessagesPresentationUtil.prefixWithEa(message), new WrapItAsItIsFix(replacement));
                    return true;
                }
            }
        }
    }
    return false;
}
Also used : IElementType(com.intellij.psi.tree.IElementType) BinaryExpression(com.jetbrains.php.lang.psi.elements.BinaryExpression) AssignmentExpression(com.jetbrains.php.lang.psi.elements.AssignmentExpression) UnaryExpression(com.jetbrains.php.lang.psi.elements.UnaryExpression) If(com.jetbrains.php.lang.psi.elements.If) PsiElement(com.intellij.psi.PsiElement)

Example 23 with BinaryExpression

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

the class ChainedCallsStrategy method apply.

private static void apply(@NotNull MethodReference reference, @NotNull Map<MethodReference, String> nullTestedReferences, @NotNull ProblemsHolder holder) {
    final PsiElement operator = OpenapiPsiSearchUtil.findResolutionOperator(reference);
    if (OpenapiTypesUtil.is(operator, PhpTokenTypes.ARROW) && !OpenapiTypesUtil.isNullSafeMemberReferenceOperator(operator)) {
        final PsiElement base = reference.getFirstPsiChild();
        if (base instanceof FunctionReference) {
            final FunctionReference baseCall = (FunctionReference) base;
            final PhpType returnType = OpenapiResolveUtil.resolveType(baseCall, holder.getProject());
            if (returnType != null) {
                final String methodName = baseCall.getName();
                for (final String resolvedType : returnType.filterUnknown().getTypes()) {
                    final String type = Types.getType(resolvedType);
                    if (type.equals(Types.strNull) || type.equals(Types.strVoid)) {
                        boolean isNullTested = false;
                        for (final Map.Entry<MethodReference, String> knownReference : nullTestedReferences.entrySet()) {
                            final String nullTestedMethodName = knownReference.getValue();
                            if (nullTestedMethodName != null && nullTestedMethodName.equals(methodName) && OpenapiEquivalenceUtil.areEqual(knownReference.getKey(), baseCall)) {
                                isNullTested = true;
                                break;
                            }
                        }
                        if (!isNullTested) {
                            holder.registerProblem(operator, MessagesPresentationUtil.prefixWithEa(message));
                            break;
                        }
                    }
                }
            }
        }
        /* collect null-tested references: only after main inspection! */
        final PsiElement parent = reference.getParent();
        if (parent instanceof BinaryExpression) {
            final BinaryExpression parentExpression = (BinaryExpression) parent;
            final IElementType operation = parentExpression.getOperationType();
            if (OpenapiTypesUtil.tsCOMPARE_EQUALITY_OPS.contains(operation)) {
                final PsiElement secondOperand = OpenapiElementsUtil.getSecondOperand(parentExpression, reference);
                if (PhpLanguageUtil.isNull(secondOperand)) {
                    nullTestedReferences.put(reference, reference.getName());
                }
            } else if (operation == PhpTokenTypes.kwINSTANCEOF || PhpTokenTypes.tsSHORT_CIRCUIT_AND_OPS.contains(operation)) {
                nullTestedReferences.put(reference, reference.getName());
            }
        } else if (ExpressionSemanticUtil.isUsedAsLogicalOperand(reference)) {
            nullTestedReferences.put(reference, reference.getName());
        }
    }
}
Also used : IElementType(com.intellij.psi.tree.IElementType) BinaryExpression(com.jetbrains.php.lang.psi.elements.BinaryExpression) FunctionReference(com.jetbrains.php.lang.psi.elements.FunctionReference) MethodReference(com.jetbrains.php.lang.psi.elements.MethodReference) HashMap(java.util.HashMap) Map(java.util.Map) PsiElement(com.intellij.psi.PsiElement) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType)

Example 24 with BinaryExpression

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

the class SuspiciousBinaryOperationInspector method buildVisitor.

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

        @Override
        public void visitPhpBinaryExpression(@NotNull BinaryExpression expression) {
            final Collection<BooleanSupplier> callbacks = new ArrayList<>();
            callbacks.add(() -> InstanceOfTraitStrategy.apply(expression, holder));
            callbacks.add(() -> EqualsInAssignmentContextStrategy.apply(expression, holder));
            callbacks.add(() -> GreaterOrEqualInHashElementStrategy.apply(expression, holder));
            callbacks.add(() -> NullableArgumentComparisonStrategy.apply(expression, holder));
            callbacks.add(() -> IdenticalOperandsStrategy.apply(expression, holder));
            callbacks.add(() -> MisplacedOperatorStrategy.apply(expression, holder));
            callbacks.add(() -> NullCoalescingOperatorCorrectnessStrategy.apply(expression, holder));
            callbacks.add(() -> ConcatenationWithArrayStrategy.apply(expression, holder));
            if (VERIFY_CONSTANTS_IN_CONDITIONS) {
                callbacks.add(() -> HardcodedConstantValuesStrategy.apply(expression, holder));
            }
            if (VERIFY_UNCLEAR_OPERATIONS_PRIORITIES) {
                callbacks.add(() -> UnclearOperationsPriorityStrategy.apply(expression, holder));
            }
            /* run through strategies until the first one fired something */
            for (final BooleanSupplier strategy : callbacks) {
                if (strategy.getAsBoolean()) {
                    break;
                }
            }
            callbacks.clear();
        }
    };
}
Also used : BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) BinaryExpression(com.jetbrains.php.lang.psi.elements.BinaryExpression) ArrayList(java.util.ArrayList) NotNull(org.jetbrains.annotations.NotNull) BooleanSupplier(java.util.function.BooleanSupplier) NotNull(org.jetbrains.annotations.NotNull)

Example 25 with BinaryExpression

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

the class OpAssignShortSyntaxInspector method buildVisitor.

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

        @Override
        public void visitPhpAssignmentExpression(@NotNull AssignmentExpression assignment) {
            final PsiElement value = ExpressionSemanticUtil.getExpressionTroughParenthesis(assignment.getValue());
            if (value instanceof BinaryExpression) {
                final BinaryExpression binary = (BinaryExpression) value;
                final PsiElement operator = binary.getOperation();
                if (operator != null) {
                    final PsiElement left = binary.getLeftOperand();
                    final PsiElement right = binary.getRightOperand();
                    final PsiElement variable = assignment.getVariable();
                    if (variable != null && left != null && right != null) {
                        final IElementType operation = operator.getNode().getElementType();
                        if (mapping.containsKey(operation)) {
                            final LinkedList<PsiElement> fragments = new LinkedList<>();
                            fragments.addLast(right);
                            PsiElement candidate = left;
                            while (candidate instanceof BinaryExpression) {
                                final BinaryExpression current = (BinaryExpression) candidate;
                                final PsiElement rightPart = current.getRightOperand();
                                if (rightPart != null) {
                                    fragments.addLast(rightPart);
                                }
                                if (current.getOperationType() != operation) {
                                    break;
                                }
                                candidate = current.getLeftOperand();
                            }
                            if (candidate != null && OpenapiEquivalenceUtil.areEqual(variable, candidate)) {
                                final boolean canShorten = (fragments.size() == 1 || chainingSafeOperators.contains(operation)) && fragments.stream().noneMatch(f -> f instanceof BinaryExpression);
                                if (canShorten) {
                                    /* false-positives: string elements manipulation, causes a fatal error */
                                    boolean isStringManipulation = false;
                                    if (variable instanceof ArrayAccessExpression) {
                                        final PsiElement stringCandidate = ((ArrayAccessExpression) variable).getValue();
                                        if (stringCandidate instanceof PhpTypedElement) {
                                            final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) stringCandidate, holder.getProject());
                                            if (resolved != null && !resolved.hasUnknown()) {
                                                isStringManipulation = resolved.getTypes().stream().anyMatch(t -> Types.getType(t).equals(Types.strString));
                                            }
                                        }
                                    }
                                    if (!isStringManipulation) {
                                        Collections.reverse(fragments);
                                        final String replacement = String.format("%s %s= %s", candidate.getText(), operator.getText(), fragments.stream().map(PsiElement::getText).collect(Collectors.joining(" " + operator.getText() + " ")));
                                        holder.registerProblem(assignment, String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), replacement), new UseShorthandOperatorFix(replacement));
                                    }
                                }
                            }
                            fragments.clear();
                        }
                    }
                }
            }
        }
    };
}
Also used : java.util(java.util) BasePhpInspection(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpInspection) IElementType(com.intellij.psi.tree.IElementType) ArrayAccessExpression(com.jetbrains.php.lang.psi.elements.ArrayAccessExpression) AssignmentExpression(com.jetbrains.php.lang.psi.elements.AssignmentExpression) PhpTokenTypes(com.jetbrains.php.lang.lexer.PhpTokenTypes) UseSuggestedReplacementFixer(com.kalessil.phpStorm.phpInspectionsEA.fixers.UseSuggestedReplacementFixer) PhpTypedElement(com.jetbrains.php.lang.psi.elements.PhpTypedElement) Collectors(java.util.stream.Collectors) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) com.kalessil.phpStorm.phpInspectionsEA.utils(com.kalessil.phpStorm.phpInspectionsEA.utils) BinaryExpression(com.jetbrains.php.lang.psi.elements.BinaryExpression) PsiElement(com.intellij.psi.PsiElement) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) NotNull(org.jetbrains.annotations.NotNull) PsiElementVisitor(com.intellij.psi.PsiElementVisitor) ProblemsHolder(com.intellij.codeInspection.ProblemsHolder) NotNull(org.jetbrains.annotations.NotNull) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) IElementType(com.intellij.psi.tree.IElementType) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) AssignmentExpression(com.jetbrains.php.lang.psi.elements.AssignmentExpression) BinaryExpression(com.jetbrains.php.lang.psi.elements.BinaryExpression) PhpTypedElement(com.jetbrains.php.lang.psi.elements.PhpTypedElement) ArrayAccessExpression(com.jetbrains.php.lang.psi.elements.ArrayAccessExpression) 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