Search in sources :

Example 36 with BasePhpElementVisitor

use of com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor in project phpinspectionsea by kalessil.

the class CaseInsensitiveStringFunctionsMissUseInspector 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)) {
                return;
            }
            final PsiElement[] arguments = reference.getParameters();
            if (arguments.length != 2 && arguments.length != 3) {
                return;
            }
            // resolve second parameter
            final StringLiteralExpression pattern = ExpressionSemanticUtil.resolveAsStringLiteral(arguments[1]);
            // might be not available - in another file (PhpStorm limitations)
            if (pattern == null || pattern.getContainingFile() != arguments[1].getContainingFile()) {
                return;
            }
            final String patternString = pattern.getContents();
            if (!StringUtils.isEmpty(patternString) && !patternString.matches(".*\\p{L}.*")) {
                final String replacementFunctionName = mapping.get(functionName);
                holder.registerProblem(reference, MessagesPresentationUtil.prefixWithEa(messagePattern.replace("%f%", replacementFunctionName)), ProblemHighlightType.WEAK_WARNING, new TheLocalFix(replacementFunctionName));
            }
        }
    };
}
Also used : BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) StringLiteralExpression(com.jetbrains.php.lang.psi.elements.StringLiteralExpression) FunctionReference(com.jetbrains.php.lang.psi.elements.FunctionReference) NotNull(org.jetbrains.annotations.NotNull) PsiElement(com.intellij.psi.PsiElement) NotNull(org.jetbrains.annotations.NotNull)

Example 37 with BasePhpElementVisitor

use of com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor 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)

Example 38 with BasePhpElementVisitor

use of com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor in project phpinspectionsea by kalessil.

the class ForgottenDebugOutputInspector method buildVisitor.

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

        @Override
        public void visitPhpMethodReference(@NotNull MethodReference reference) {
            final String methodName = reference.getName();
            if (methodName != null && customMethodsNames.contains(methodName)) {
                for (final Couple<String> match : customMethods.values()) {
                    if (methodName.equals(match.getSecond())) {
                        final PsiElement resolved = OpenapiResolveUtil.resolveReference(reference);
                        if (resolved instanceof Method) {
                            final PhpClass clazz = ((Method) resolved).getContainingClass();
                            if (clazz != null && match.getFirst().equals(clazz.getFQN()) && !this.isInDebugFunction(reference)) {
                                holder.registerProblem(reference, MessagesPresentationUtil.prefixWithEa(message));
                                return;
                            }
                        }
                    }
                }
            }
        }

        @Override
        public void visitPhpFunctionCall(@NotNull FunctionReference reference) {
            final String functionName = reference.getName();
            if (functionName != null && customFunctions.contains(functionName) && !(reference.getParent() instanceof PhpUse)) {
                final Integer paramsNeeded = functionsRequirements.get(functionName);
                if (paramsNeeded == null || reference.getParameters().length != paramsNeeded) {
                    final boolean isValidContext = this.isBuffered(reference) || this.isInDebugFunction(reference);
                    if (!isValidContext) {
                        holder.registerProblem(reference, MessagesPresentationUtil.prefixWithEa(message));
                    }
                }
            }
        }

        private boolean isInDebugFunction(@NotNull PsiElement debugStatement) {
            final Function scope = ExpressionSemanticUtil.getScope(debugStatement);
            return scope != null && configuration.contains(scope instanceof Method ? scope.getFQN() : scope.getName());
        }

        private boolean isBuffered(@NotNull PsiElement debugStatement) {
            boolean result = false;
            PsiElement parent = debugStatement.getParent();
            /* statement can be prepended by @ (silence) */
            if (parent instanceof UnaryExpression) {
                final PsiElement operation = ((UnaryExpression) parent).getOperation();
                if (OpenapiTypesUtil.is(operation, PhpTokenTypes.opSILENCE)) {
                    parent = parent.getParent();
                }
            }
            /* ensure it's not prepended with 'ob_start();' */
            if (OpenapiTypesUtil.isStatementImpl(parent)) {
                final PsiElement preceding = ((Statement) parent).getPrevPsiSibling();
                if (preceding != null && OpenapiTypesUtil.isFunctionReference(preceding.getFirstChild())) {
                    final String precedingFunctionName = ((FunctionReference) preceding.getFirstChild()).getName();
                    if (precedingFunctionName != null && precedingFunctionName.equals("ob_start")) {
                        result = true;
                    }
                }
            }
            return result;
        }
    };
}
Also used : NotNull(org.jetbrains.annotations.NotNull) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) PsiElement(com.intellij.psi.PsiElement) NotNull(org.jetbrains.annotations.NotNull)

Example 39 with BasePhpElementVisitor

use of com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor in project phpinspectionsea by kalessil.

the class GetClassUsageInspector method buildVisitor.

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

        @Override
        public void visitPhpFunctionCall(@NotNull FunctionReference reference) {
            final Project project = holder.getProject();
            if (PhpLanguageLevel.get(project).atLeast(PhpLanguageLevel.PHP710)) {
                final String functionName = reference.getName();
                if (functionName != null && functionName.equals("get_class")) {
                    final PsiElement[] arguments = reference.getParameters();
                    if (arguments.length == 1 && arguments[0] instanceof PhpTypedElement) {
                        final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) arguments[0], project);
                        if (resolved != null) {
                            final boolean hasNull = resolved.filterUnknown().getTypes().stream().anyMatch(t -> Types.getType(t).equals(Types.strNull));
                            if ((hasNull || isNullableParameter(arguments[0])) && !isNullabilityChecked(arguments[0])) {
                                holder.registerProblem(reference, MessagesPresentationUtil.prefixWithEa(message));
                            }
                        }
                    }
                }
            }
        }

        private boolean isNullabilityChecked(@NotNull PsiElement expression) {
            /* workaround for https://youtrack.jetbrains.com/issue/WI-38622 */
            boolean result = false;
            final Function scope = ExpressionSemanticUtil.getScope(expression);
            if (scope != null) {
                final GroupStatement body = ExpressionSemanticUtil.getGroupStatement(scope);
                final List<PsiElement> allUsages = PsiTreeUtil.findChildrenOfType(body, expression.getClass()).stream().filter(e -> OpenapiEquivalenceUtil.areEqual(e, expression)).collect(Collectors.toList());
                for (final PsiElement candidate : allUsages.subList(0, allUsages.indexOf(expression))) {
                    final PsiElement parent = candidate.getParent();
                    if (parent instanceof PhpEmpty || parent instanceof PhpIsset) {
                        result = true;
                    } else if (parent instanceof BinaryExpression) {
                        final BinaryExpression binary = (BinaryExpression) parent;
                        final IElementType operator = binary.getOperationType();
                        if (operator == PhpTokenTypes.kwINSTANCEOF) {
                            result = true;
                        } else if (OpenapiTypesUtil.tsCOMPARE_EQUALITY_OPS.contains(operator)) {
                            final PsiElement second = OpenapiElementsUtil.getSecondOperand(binary, candidate);
                            result = PhpLanguageUtil.isNull(second);
                        }
                    } else if (ExpressionSemanticUtil.isUsedAsLogicalOperand(candidate)) {
                        result = true;
                    }
                    /* break loop when null check being found */
                    if (result) {
                        break;
                    }
                }
                allUsages.clear();
            }
            return result;
        }

        private boolean isNullableParameter(@NotNull PsiElement expression) {
            boolean result = false;
            if (expression instanceof Variable) {
                final Function scope = ExpressionSemanticUtil.getScope(expression);
                if (scope != null) {
                    final String name = ((Variable) expression).getName();
                    result = Arrays.stream(scope.getParameters()).anyMatch(parameter -> name.equals(parameter.getName()) && PhpLanguageUtil.isNull(parameter.getDefaultValue()));
                }
            }
            return result;
        }
    };
}
Also used : Arrays(java.util.Arrays) BasePhpInspection(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpInspection) PhpLanguageLevel(com.kalessil.phpStorm.phpInspectionsEA.openApi.PhpLanguageLevel) com.jetbrains.php.lang.psi.elements(com.jetbrains.php.lang.psi.elements) IElementType(com.intellij.psi.tree.IElementType) PhpTokenTypes(com.jetbrains.php.lang.lexer.PhpTokenTypes) Collectors(java.util.stream.Collectors) PsiTreeUtil(com.intellij.psi.util.PsiTreeUtil) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) com.kalessil.phpStorm.phpInspectionsEA.utils(com.kalessil.phpStorm.phpInspectionsEA.utils) List(java.util.List) PsiElement(com.intellij.psi.PsiElement) Project(com.intellij.openapi.project.Project) 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) Project(com.intellij.openapi.project.Project) PsiElement(com.intellij.psi.PsiElement) NotNull(org.jetbrains.annotations.NotNull)

Example 40 with BasePhpElementVisitor

use of com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor in project phpinspectionsea by kalessil.

the class SubStrUsedAsArrayAccessInspector method buildVisitor.

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

        @Override
        public void visitPhpFunctionCall(@NotNull FunctionReference reference) {
            /* check if it's the target function */
            final String functionName = reference.getName();
            if (functionName != null && functionName.equals("substr")) {
                final PsiElement[] arguments = reference.getParameters();
                if (arguments.length == 3) {
                    final PsiElement length = arguments[2];
                    if (OpenapiTypesUtil.isNumber(length) && length.getText().equals("1")) {
                        final boolean isValidSource = arguments[0] instanceof Variable || arguments[0] instanceof ArrayAccessExpression || arguments[0] instanceof FieldReference;
                        if (isValidSource) {
                            final PhpTypedElement container = (PhpTypedElement) arguments[0];
                            final PhpType resolvedType = OpenapiResolveUtil.resolveType(container, holder.getProject());
                            if (resolvedType != null) {
                                final boolean isValidType = resolvedType.filterUnknown().getTypes().stream().anyMatch(t -> Types.getType(t).equals(Types.strString));
                                if (isValidType) {
                                    final String source = arguments[0].getText();
                                    final String offset = arguments[1].getText();
                                    final String replacement = offset.startsWith("-") ? String.format("%s[strlen(%s) %s]", source, source, offset.replaceFirst("-", "- ")) : String.format("%s[%s]", source, offset);
                                    holder.registerProblem(reference, String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), replacement), new TheLocalFix(replacement));
                                }
                            }
                        }
                    }
                }
            }
        }
    };
}
Also used : NotNull(org.jetbrains.annotations.NotNull) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) PsiElement(com.intellij.psi.PsiElement) NotNull(org.jetbrains.annotations.NotNull)

Aggregations

BasePhpElementVisitor (com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor)169 NotNull (org.jetbrains.annotations.NotNull)169 PsiElement (com.intellij.psi.PsiElement)157 FunctionReference (com.jetbrains.php.lang.psi.elements.FunctionReference)43 ProblemsHolder (com.intellij.codeInspection.ProblemsHolder)40 BasePhpInspection (com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpInspection)39 PsiElementVisitor (com.intellij.psi.PsiElementVisitor)37 PhpType (com.jetbrains.php.lang.psi.resolve.types.PhpType)33 IElementType (com.intellij.psi.tree.IElementType)32 com.jetbrains.php.lang.psi.elements (com.jetbrains.php.lang.psi.elements)29 Project (com.intellij.openapi.project.Project)25 BinaryExpression (com.jetbrains.php.lang.psi.elements.BinaryExpression)25 HashSet (java.util.HashSet)24 PsiTreeUtil (com.intellij.psi.util.PsiTreeUtil)22 MessagesPresentationUtil (com.kalessil.phpStorm.phpInspectionsEA.utils.MessagesPresentationUtil)19 StringLiteralExpression (com.jetbrains.php.lang.psi.elements.StringLiteralExpression)18 ArrayList (java.util.ArrayList)18 Set (java.util.Set)18 Nullable (org.jetbrains.annotations.Nullable)18 PhpTokenTypes (com.jetbrains.php.lang.lexer.PhpTokenTypes)17