Search in sources :

Example 11 with FunctionReference

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

the class StrStrUsedAsStrPosInspector 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 && mapping.containsKey(functionName)) {
                final PsiElement[] arguments = reference.getParameters();
                if (arguments.length >= 2) {
                    /* checks implicit boolean comparison pattern */
                    final PsiElement parent = reference.getParent();
                    if (parent instanceof BinaryExpression) {
                        final BinaryExpression binary = (BinaryExpression) parent;
                        if (OpenapiTypesUtil.tsCOMPARE_EQUALITY_OPS.contains(binary.getOperationType())) {
                            final PsiElement secondOperand = OpenapiElementsUtil.getSecondOperand(binary, reference);
                            if (PhpLanguageUtil.isFalse(secondOperand)) {
                                final PsiElement operationNode = binary.getOperation();
                                if (operationNode != null) {
                                    String operation = operationNode.getText();
                                    operation = operation.length() == 2 ? operation + '=' : operation;
                                    final String call = String.format("%s%s(%s, %s)", reference.getImmediateNamespaceName(), mapping.get(functionName), arguments[0].getText(), arguments[1].getText());
                                    final boolean isRegular = ComparisonStyle.isRegular();
                                    final String replacement = String.format("%s %s %s", isRegular ? call : "false", operation, isRegular ? "false" : call);
                                    holder.registerProblem(binary, String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), replacement), new UseStrposFix(replacement));
                                    return;
                                }
                            }
                        }
                    }
                    /* checks non-implicit boolean comparison patternS */
                    if (ExpressionSemanticUtil.isUsedAsLogicalOperand(reference)) {
                        final String operation = parent instanceof UnaryExpression ? "===" : "!==";
                        final String call = String.format("%s%s(%s, %s)", reference.getImmediateNamespaceName(), mapping.get(functionName), arguments[0].getText(), arguments[1].getText());
                        final boolean isRegular = ComparisonStyle.isRegular();
                        final String replacement = String.format("%s %s %s", isRegular ? call : "false", operation, isRegular ? "false" : call);
                        holder.registerProblem(parent instanceof UnaryExpression ? parent : reference, String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), replacement), new UseStrposFix(replacement));
                    }
                }
            }
        }
    };
}
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) UnaryExpression(com.jetbrains.php.lang.psi.elements.UnaryExpression) NotNull(org.jetbrains.annotations.NotNull) PsiElement(com.intellij.psi.PsiElement) NotNull(org.jetbrains.annotations.NotNull)

Example 12 with FunctionReference

use of com.jetbrains.php.lang.psi.elements.FunctionReference 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 13 with FunctionReference

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

the class ArrayIsListCanBeUsedInspector 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("array_keys") || functionName.equals("array_values"))) {
                final boolean isTargetVersion = PhpLanguageLevel.get(holder.getProject()).atLeast(PhpLanguageLevel.PHP800);
                if (isTargetVersion) {
                    final PsiElement[] arguments = reference.getParameters();
                    if (arguments.length == 1) {
                        final PsiElement context = reference.getParent();
                        if (context instanceof BinaryExpression) {
                            final BinaryExpression binary = (BinaryExpression) context;
                            final IElementType operator = binary.getOperationType();
                            if (OpenapiTypesUtil.tsCOMPARE_EQUALITY_OPS.contains(operator)) {
                                final PsiElement second = OpenapiElementsUtil.getSecondOperand(binary, reference);
                                if (functionName.equals("array_values")) {
                                    if (second != null && OpenapiEquivalenceUtil.areEqual(arguments[0], second)) {
                                        this.report(reference, operator, arguments[0]);
                                    }
                                } else if (functionName.equals("array_keys")) {
                                    if (OpenapiTypesUtil.isFunctionReference(second)) {
                                        final FunctionReference rightReference = (FunctionReference) second;
                                        final String rightFunctionName = rightReference.getName();
                                        final PsiElement[] rightArguments = rightReference.getParameters();
                                        if ((rightFunctionName != null && rightFunctionName.equals("range")) && rightArguments.length == 2) {
                                            final boolean rangeFromZero = OpenapiTypesUtil.isNumber(rightArguments[0]) && rightArguments[0].getText().equals("0");
                                            if (rangeFromZero && rightArguments[1] instanceof BinaryExpression) {
                                                final BinaryExpression rangeToBinary = (BinaryExpression) rightArguments[1];
                                                if (rangeToBinary.getOperationType() == PhpTokenTypes.opMINUS) {
                                                    final PsiElement right = rangeToBinary.getRightOperand();
                                                    final PsiElement left = rangeToBinary.getLeftOperand();
                                                    if (OpenapiTypesUtil.isNumber(right) && right.getText().equals("1") && OpenapiTypesUtil.isFunctionReference(left)) {
                                                        final FunctionReference leftReference = (FunctionReference) left;
                                                        final String leftName = leftReference.getName();
                                                        final PsiElement[] leftArguments = leftReference.getParameters();
                                                        if (leftName != null && leftName.equals("count") && leftArguments.length == 1) {
                                                            if (OpenapiEquivalenceUtil.areEqual(arguments[0], leftArguments[0])) {
                                                                this.report(reference, operator, arguments[0]);
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        private void report(@NotNull FunctionReference reference, @NotNull IElementType operator, @NotNull PsiElement argument) {
            final boolean listExpected = operator == PhpTokenTypes.opIDENTICAL || operator == PhpTokenTypes.opEQUAL;
            final String replacement = String.format("%s%sarray_is_list(%s)", listExpected ? "" : "!", reference.getImmediateNamespaceName(), argument.getText());
            holder.registerProblem(reference.getParent(), String.format(MessagesPresentationUtil.prefixWithEa(message), replacement), new UseArrayIsListFix(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)

Example 14 with FunctionReference

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

the class TypeUnsafeArraySearchInspector 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 && targetFunctions.contains(functionName)) {
                final PsiElement[] arguments = reference.getParameters();
                if (arguments.length == 2) {
                    /* false-positives: array of string literals */
                    if (arguments[1] instanceof ArrayCreationExpression) {
                        final PsiElement[] elements = arguments[1].getChildren();
                        if (elements.length > 0) {
                            final long validElementsCount = Arrays.stream(elements).filter(element -> OpenapiTypesUtil.is(element, PhpElementTypes.ARRAY_VALUE)).map(PsiElement::getFirstChild).filter(element -> element instanceof StringLiteralExpression).map(literal -> ((StringLiteralExpression) literal).getContents().trim()).filter(content -> !content.isEmpty() && !content.matches("^\\d+$")).count();
                            if (validElementsCount == elements.length) {
                                return;
                            }
                        }
                    }
                    /* false-positives: array and item types are complimentary */
                    if (arguments[0] instanceof PhpTypedElement && arguments[1] instanceof PhpTypedElement) {
                        final Project project = holder.getProject();
                        final PhpType arrayType = OpenapiResolveUtil.resolveType((PhpTypedElement) arguments[1], project);
                        final Set<String> arrayTypes = arrayType == null ? null : arrayType.filterUnknown().getTypes();
                        if (arrayTypes != null && arrayTypes.size() == 1) {
                            final PhpType itemType = OpenapiResolveUtil.resolveType((PhpTypedElement) arguments[0], project);
                            final Set<String> itemTypes = itemType == null ? null : itemType.filterUnknown().getTypes();
                            if (itemTypes != null && itemTypes.size() == 1) {
                                final boolean matching = this.areTypesMatching(itemTypes.iterator().next(), arrayTypes.iterator().next());
                                if (matching) {
                                    return;
                                }
                            }
                        }
                    }
                    /* general case: we need the third argument */
                    final String replacement = String.format("%s%s(%s, %s, true)", reference.getImmediateNamespaceName(), functionName, arguments[0].getText(), arguments[1].getText());
                    holder.registerProblem(reference, MessagesPresentationUtil.prefixWithEa(message), new MakeSearchTypeSensitiveFix(replacement));
                }
            }
        }

        private boolean areTypesMatching(@NotNull String itemType, @NotNull String arrayType) {
            boolean result = false;
            if (!itemType.isEmpty()) {
                result = arrayType.equals((itemType.charAt(0) == '\\' ? itemType : '\\' + itemType) + "[]");
            }
            return result;
        }
    };
}
Also used : Arrays(java.util.Arrays) BasePhpInspection(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpInspection) UseSuggestedReplacementFixer(com.kalessil.phpStorm.phpInspectionsEA.fixers.UseSuggestedReplacementFixer) Set(java.util.Set) PhpTypedElement(com.jetbrains.php.lang.psi.elements.PhpTypedElement) HashSet(java.util.HashSet) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) OpenapiTypesUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.OpenapiTypesUtil) OpenapiResolveUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.OpenapiResolveUtil) MessagesPresentationUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.MessagesPresentationUtil) PsiElement(com.intellij.psi.PsiElement) Project(com.intellij.openapi.project.Project) FunctionReference(com.jetbrains.php.lang.psi.elements.FunctionReference) StringLiteralExpression(com.jetbrains.php.lang.psi.elements.StringLiteralExpression) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) NotNull(org.jetbrains.annotations.NotNull) PsiElementVisitor(com.intellij.psi.PsiElementVisitor) PhpElementTypes(com.jetbrains.php.lang.parser.PhpElementTypes) ProblemsHolder(com.intellij.codeInspection.ProblemsHolder) ArrayCreationExpression(com.jetbrains.php.lang.psi.elements.ArrayCreationExpression) ArrayCreationExpression(com.jetbrains.php.lang.psi.elements.ArrayCreationExpression) StringLiteralExpression(com.jetbrains.php.lang.psi.elements.StringLiteralExpression) NotNull(org.jetbrains.annotations.NotNull) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) Project(com.intellij.openapi.project.Project) 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 15 with FunctionReference

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

the class DateUsageInspector 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("date")) {
                final PsiElement[] arguments = reference.getParameters();
                if (arguments.length == 2) {
                    final PsiElement candidate = arguments[1];
                    if (OpenapiTypesUtil.isFunctionReference(candidate)) {
                        final FunctionReference inner = (FunctionReference) candidate;
                        final String innerName = inner.getName();
                        if (innerName != null && innerName.equals("time") && inner.getParameters().length == 0) {
                            holder.registerProblem(inner, MessagesPresentationUtil.prefixWithEa(messageDropTime), ProblemHighlightType.LIKE_UNUSED_SYMBOL, new DropTimeFunctionCallLocalFix(holder.getProject(), arguments[0], arguments[1]));
                        }
                    }
                }
            }
        }
    };
}
Also used : BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) FunctionReference(com.jetbrains.php.lang.psi.elements.FunctionReference) NotNull(org.jetbrains.annotations.NotNull) PsiElement(com.intellij.psi.PsiElement) NotNull(org.jetbrains.annotations.NotNull)

Aggregations

FunctionReference (com.jetbrains.php.lang.psi.elements.FunctionReference)58 PsiElement (com.intellij.psi.PsiElement)55 NotNull (org.jetbrains.annotations.NotNull)46 BasePhpElementVisitor (com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor)43 BinaryExpression (com.jetbrains.php.lang.psi.elements.BinaryExpression)16 StringLiteralExpression (com.jetbrains.php.lang.psi.elements.StringLiteralExpression)15 IElementType (com.intellij.psi.tree.IElementType)11 PhpUnitAssertFixer (com.kalessil.phpStorm.phpInspectionsEA.fixers.PhpUnitAssertFixer)9 ArrayCreationExpression (com.jetbrains.php.lang.psi.elements.ArrayCreationExpression)6 UnaryExpression (com.jetbrains.php.lang.psi.elements.UnaryExpression)6 Function (com.jetbrains.php.lang.psi.elements.Function)5 MethodReference (com.jetbrains.php.lang.psi.elements.MethodReference)5 ParameterList (com.jetbrains.php.lang.psi.elements.ParameterList)5 PhpLanguageLevel (com.jetbrains.php.config.PhpLanguageLevel)4 ArrayList (java.util.ArrayList)4 Nullable (org.jetbrains.annotations.Nullable)4 ProblemsHolder (com.intellij.codeInspection.ProblemsHolder)3 PsiWhiteSpace (com.intellij.psi.PsiWhiteSpace)3 ArrayAccessExpression (com.jetbrains.php.lang.psi.elements.ArrayAccessExpression)3 HashSet (java.util.HashSet)3