Search in sources :

Example 26 with PhpType

use of com.jetbrains.php.lang.psi.resolve.types.PhpType in project phpinspectionsea by kalessil.

the class IncrementDecrementOperationEquivalentInspector method buildVisitor.

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

        /* ensures we are not touching arrays only, not strings and not objects */
        private boolean isArrayAccessOrString(@Nullable PhpPsiElement variable) {
            if (variable instanceof ArrayAccessExpression) {
                final PsiElement container = ((ArrayAccessExpression) variable).getValue();
                if (container instanceof PhpTypedElement) {
                    final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) container, holder.getProject());
                    if (resolved != null) {
                        final Set<String> types = new HashSet<>();
                        resolved.filterUnknown().getTypes().forEach(t -> types.add(Types.getType(t)));
                        final boolean isArray = types.contains(Types.strArray) && !types.contains(Types.strString);
                        types.clear();
                        return !isArray;
                    }
                }
            }
            return false;
        }

        @Override
        public void visitPhpSelfAssignmentExpression(@NotNull SelfAssignmentExpression expression) {
            final IElementType operation = expression.getOperationType();
            final PhpPsiElement value = expression.getValue();
            final PhpPsiElement variable = expression.getVariable();
            if (null != value && null != operation && null != variable) {
                if (operation == PhpTokenTypes.opPLUS_ASGN) {
                    if (value.getText().equals("1") && !isArrayAccessOrString(variable)) {
                        final String replacement = PREFER_PREFIX_STYLE ? ("++" + variable.getText()) : (variable.getText() + "++");
                        holder.registerProblem(expression, MessagesPresentationUtil.prefixWithEa(patternMessage.replace("%e%", replacement)), new UseIncrementFix(replacement));
                    }
                } else if (operation == PhpTokenTypes.opMINUS_ASGN) {
                    if (value.getText().equals("1") && !isArrayAccessOrString(variable)) {
                        final String replacement = PREFER_PREFIX_STYLE ? ("--" + variable.getText()) : (variable.getText() + "--");
                        holder.registerProblem(expression, MessagesPresentationUtil.prefixWithEa(patternMessage.replace("%e%", replacement)), new UseDecrementFix(replacement));
                    }
                }
            }
        }

        @Override
        public void visitPhpAssignmentExpression(@NotNull AssignmentExpression assignmentExpression) {
            final PhpPsiElement variable = assignmentExpression.getVariable();
            if (variable != null && assignmentExpression.getValue() instanceof BinaryExpression) {
                final BinaryExpression value = (BinaryExpression) assignmentExpression.getValue();
                /* operation and operands provided */
                final PsiElement leftOperand = value.getLeftOperand();
                final PsiElement rightOperand = value.getRightOperand();
                final IElementType operation = value.getOperationType();
                if (null == leftOperand || null == rightOperand || null == operation) {
                    return;
                }
                if (operation == PhpTokenTypes.opPLUS) {
                    /* plus operation: operand position NOT important */
                    if ((leftOperand.getText().equals("1") && OpenapiEquivalenceUtil.areEqual(rightOperand, variable)) || (rightOperand.getText().equals("1") && OpenapiEquivalenceUtil.areEqual(leftOperand, variable))) {
                        if (!isArrayAccessOrString(variable)) {
                            final String replacement = PREFER_PREFIX_STYLE ? ("++" + variable.getText()) : (variable.getText() + "++");
                            holder.registerProblem(assignmentExpression, MessagesPresentationUtil.prefixWithEa(patternMessage.replace("%e%", replacement)), new UseIncrementFix(replacement));
                        }
                    }
                } else if (operation == PhpTokenTypes.opMINUS) {
                    /* minus operation: operand position IS important */
                    if (rightOperand.getText().equals("1") && OpenapiEquivalenceUtil.areEqual(leftOperand, variable) && !isArrayAccessOrString(variable)) {
                        final String replacement = PREFER_PREFIX_STYLE ? ("--" + variable.getText()) : (variable.getText() + "--");
                        holder.registerProblem(assignmentExpression, MessagesPresentationUtil.prefixWithEa(patternMessage.replace("%e%", replacement)), new UseDecrementFix(replacement));
                    }
                }
            }
        }
    };
}
Also used : 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) Nullable(org.jetbrains.annotations.Nullable) PsiElement(com.intellij.psi.PsiElement) HashSet(java.util.HashSet) NotNull(org.jetbrains.annotations.NotNull)

Example 27 with PhpType

use of com.jetbrains.php.lang.psi.resolve.types.PhpType in project phpinspectionsea by kalessil.

the class MisplacedOperatorStrategy method apply.

public static boolean apply(@NotNull BinaryExpression expression, @NotNull ProblemsHolder holder) {
    final PsiElement parent = expression.getParent().getParent();
    /* basic operator filter */
    if (parent instanceof FunctionReference && operations.contains(expression.getOperationType())) {
        final FunctionReference call = (FunctionReference) parent;
        final PsiElement[] arguments = call.getParameters();
        final PsiElement candidate = arguments.length > 0 ? arguments[arguments.length - 1] : null;
        /* BO should be the last parameter of a call in logical contexts */
        if (candidate == expression && ExpressionSemanticUtil.isUsedAsLogicalOperand(parent)) {
            final PsiElement resolved = OpenapiResolveUtil.resolveReference(call);
            if (resolved instanceof Function) {
                /* resolve the last parameter types: if bool not defined implicitly, continue */
                final Function function = (Function) resolved;
                final Parameter[] params = function.getParameters();
                if (params.length >= arguments.length) {
                    final Parameter parameter = params[arguments.length - 1];
                    final Set<String> types = new HashSet<>();
                    parameter.getType().filterUnknown().getTypes().forEach(t -> types.add(Types.getType(t)));
                    if (!types.contains(Types.strBoolean)) {
                        final PsiElement rightOperand = expression.getRightOperand();
                        final PsiElement leftOperand = expression.getLeftOperand();
                        if (leftOperand != null && rightOperand instanceof PhpTypedElement) {
                            final Project project = holder.getProject();
                            final PhpType allowedTypes = function.getType().global(project).filterUnknown();
                            final PhpType operandTypes = ((PhpTypedElement) rightOperand).getType().global(project).filterUnknown();
                            final PsiElement operator = expression.getOperation();
                            if (operator != null && allowedTypes.getTypes().containsAll(operandTypes.getTypes())) {
                                final String replacement = "%c% %o% %r%".replace("%r%", rightOperand.getText()).replace("%o%", operator.getText()).replace("%c%", call.getText()).replace(expression.getText(), leftOperand.getText());
                                holder.registerProblem(operator, MessagesPresentationUtil.prefixWithEa(message), new MisplacedOperatorFix(holder.getProject(), replacement, call));
                                return true;
                            }
                        }
                    }
                    types.clear();
                }
            }
        }
    }
    return false;
}
Also used : PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) Project(com.intellij.openapi.project.Project) PsiElement(com.intellij.psi.PsiElement) HashSet(java.util.HashSet)

Example 28 with PhpType

use of com.jetbrains.php.lang.psi.resolve.types.PhpType in project phpinspectionsea by kalessil.

the class NullableArgumentComparisonStrategy method apply.

public static boolean apply(@NotNull BinaryExpression expression, @NotNull ProblemsHolder holder) {
    boolean result = false;
    final IElementType operator = expression.getOperationType();
    if (mapping.containsKey(operator)) {
        PsiElement parent = expression.getParent();
        while (parent instanceof ParenthesizedExpression) {
            parent = parent.getParent();
        }
        final PsiElement argument = expression.getLeftOperand();
        final PsiElement value = expression.getRightOperand();
        if (parent instanceof UnaryExpression && argument instanceof PhpTypedElement && value != null) {
            final UnaryExpression target = (UnaryExpression) parent;
            if (OpenapiTypesUtil.is(target.getOperation(), PhpTokenTypes.opNOT)) {
                final PhpType type = OpenapiResolveUtil.resolveType((PhpTypedElement) argument, holder.getProject());
                if (type != null && !type.hasUnknown()) {
                    final Set<String> types = new HashSet<>();
                    type.getTypes().forEach(t -> types.add(Types.getType(t)));
                    if (types.contains(Types.strNull) || types.contains(Types.strBoolean)) {
                        final String replacement = String.format("%s %s %s", argument.getText(), mapping.get(operator), value.getText());
                        holder.registerProblem(target, MessagesPresentationUtil.prefixWithEa(String.format(messagePattern, replacement)), new NullableArgumentComparisonFix(replacement));
                        result = true;
                    }
                    types.clear();
                }
            }
        }
    }
    return result;
}
Also used : IElementType(com.intellij.psi.tree.IElementType) ParenthesizedExpression(com.jetbrains.php.lang.psi.elements.ParenthesizedExpression) PhpTypedElement(com.jetbrains.php.lang.psi.elements.PhpTypedElement) UnaryExpression(com.jetbrains.php.lang.psi.elements.UnaryExpression) PsiElement(com.intellij.psi.PsiElement) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) HashSet(java.util.HashSet)

Example 29 with PhpType

use of com.jetbrains.php.lang.psi.resolve.types.PhpType in project phpinspectionsea by kalessil.

the class ClassMethodNameMatchesFieldNameInspector method buildVisitor.

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

        @Override
        public void visitPhpMethod(@NotNull Method method) {
            final PhpClass clazz = method.getContainingClass();
            if (clazz != null && !clazz.isInterface()) {
                final Field field = OpenapiResolveUtil.resolveField(clazz, method.getName());
                if (field != null) {
                    final PsiElement nameNode = NamedElementUtil.getNameIdentifier(method);
                    final PhpType resolvedType = OpenapiResolveUtil.resolveType(field, holder.getProject());
                    if (resolvedType != null && nameNode != null) {
                        final PhpType knownType = resolvedType.filterUnknown();
                        if (knownType.isEmpty()) {
                            holder.registerProblem(nameNode, MessagesPresentationUtil.prefixWithEa(messageFieldType));
                        } else {
                            final boolean isCallable = knownType.getTypes().stream().anyMatch(t -> Types.getType(t).equals(Types.strCallable));
                            if (isCallable) {
                                holder.registerProblem(nameNode, MessagesPresentationUtil.prefixWithEa(messageMatches));
                            }
                        }
                    }
                }
            }
        }
    };
}
Also used : BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) Field(com.jetbrains.php.lang.psi.elements.Field) PhpClass(com.jetbrains.php.lang.psi.elements.PhpClass) Method(com.jetbrains.php.lang.psi.elements.Method) NotNull(org.jetbrains.annotations.NotNull) PsiElement(com.intellij.psi.PsiElement) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) NotNull(org.jetbrains.annotations.NotNull)

Example 30 with PhpType

use of com.jetbrains.php.lang.psi.resolve.types.PhpType in project phpinspectionsea by kalessil.

the class LoopWhichDoesNotLoopInspector method buildVisitor.

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

        @Override
        public void visitPhpForeach(@NotNull ForeachStatement loop) {
            final boolean isBlade = holder.getFile().getName().endsWith(".blade.php");
            if (!isBlade && this.isNotLooping(loop)) {
                /* false-positive: return first element from generator, iterable and co */
                final GroupStatement body = ExpressionSemanticUtil.getGroupStatement(loop);
                final PsiElement last = body == null ? null : ExpressionSemanticUtil.getLastStatement(body);
                if (last != null && !OpenapiTypesUtil.isThrowExpression(last)) {
                    final PsiElement source = loop.getArray();
                    if (source instanceof PhpTypedElement) {
                        final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) source, holder.getProject());
                        final boolean isValid = resolved != null && resolved.filterUnknown().getTypes().stream().anyMatch(type -> foreachExceptions.contains(Types.getType(type)));
                        if (isValid) {
                            return;
                        }
                    }
                }
                holder.registerProblem(loop.getFirstChild(), MessagesPresentationUtil.prefixWithEa(message));
            }
        }

        @Override
        public void visitPhpFor(@NotNull For loop) {
            final boolean isBlade = holder.getFile().getName().endsWith(".blade.php");
            if (!isBlade && this.isNotLooping(loop)) {
                holder.registerProblem(loop.getFirstChild(), MessagesPresentationUtil.prefixWithEa(message));
            }
        }

        @Override
        public void visitPhpWhile(@NotNull While loop) {
            final boolean isBlade = holder.getFile().getName().endsWith(".blade.php");
            if (!isBlade && this.isNotLooping(loop)) {
                holder.registerProblem(loop.getFirstChild(), MessagesPresentationUtil.prefixWithEa(message));
            }
        }

        @Override
        public void visitPhpDoWhile(@NotNull DoWhile loop) {
            final boolean isBlade = holder.getFile().getName().endsWith(".blade.php");
            if (!isBlade && this.isNotLooping(loop)) {
                holder.registerProblem(loop.getFirstChild(), MessagesPresentationUtil.prefixWithEa(message));
            }
        }

        private boolean isNotLooping(@NotNull PhpPsiElement loop) {
            final GroupStatement body = ExpressionSemanticUtil.getGroupStatement(loop);
            if (null == body) {
                return false;
            }
            final PsiElement lastExpression = ExpressionSemanticUtil.getLastStatement(body);
            final boolean isLoopTerminatedWithLastExpression = lastExpression instanceof PhpBreak || lastExpression instanceof PhpReturn || OpenapiTypesUtil.isThrowExpression(lastExpression);
            /* loop is empty or terminates on first iteration */
            if (null != lastExpression && !isLoopTerminatedWithLastExpression) {
                return false;
            }
            /* detect continue statements, which makes the loop looping */
            for (final PhpContinue expression : PsiTreeUtil.findChildrenOfType(body, PhpContinue.class)) {
                int nestingLevel = 0;
                PsiElement parent = expression.getParent();
                while (null != parent && !(parent instanceof Function) && !(parent instanceof PsiFile)) {
                    if (OpenapiTypesUtil.isLoop(parent)) {
                        ++nestingLevel;
                        if (parent == loop) {
                            /* extract level of continuation from the statement */
                            int continueLevel = 1;
                            final PsiElement argument = expression.getArgument();
                            if (null != argument) {
                                try {
                                    continueLevel = Integer.parseInt(argument.getText());
                                } catch (final NumberFormatException notParsed) {
                                    continueLevel = 1;
                                }
                            }
                            /* matched continue for the current loop */
                            if (continueLevel == nestingLevel) {
                                return false;
                            }
                        }
                    }
                    parent = parent.getParent();
                }
            }
            return true;
        }
    };
}
Also used : BasePhpInspection(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpInspection) com.jetbrains.php.lang.psi.elements(com.jetbrains.php.lang.psi.elements) Set(java.util.Set) HashSet(java.util.HashSet) PsiTreeUtil(com.intellij.psi.util.PsiTreeUtil) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) com.kalessil.phpStorm.phpInspectionsEA.utils(com.kalessil.phpStorm.phpInspectionsEA.utils) PsiElement(com.intellij.psi.PsiElement) PsiFile(com.intellij.psi.PsiFile) 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) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) PsiFile(com.intellij.psi.PsiFile) PsiElement(com.intellij.psi.PsiElement) NotNull(org.jetbrains.annotations.NotNull)

Aggregations

PhpType (com.jetbrains.php.lang.psi.resolve.types.PhpType)56 PsiElement (com.intellij.psi.PsiElement)46 NotNull (org.jetbrains.annotations.NotNull)41 BasePhpElementVisitor (com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor)33 ProblemsHolder (com.intellij.codeInspection.ProblemsHolder)20 Project (com.intellij.openapi.project.Project)20 HashSet (java.util.HashSet)20 BasePhpInspection (com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpInspection)16 Nullable (org.jetbrains.annotations.Nullable)16 com.jetbrains.php.lang.psi.elements (com.jetbrains.php.lang.psi.elements)15 PsiElementVisitor (com.intellij.psi.PsiElementVisitor)14 PhpIndex (com.jetbrains.php.PhpIndex)14 com.kalessil.phpStorm.phpInspectionsEA.utils (com.kalessil.phpStorm.phpInspectionsEA.utils)13 IElementType (com.intellij.psi.tree.IElementType)12 Set (java.util.Set)12 PhpTokenTypes (com.jetbrains.php.lang.lexer.PhpTokenTypes)10 PsiTreeUtil (com.intellij.psi.util.PsiTreeUtil)9 PhpTypedElement (com.jetbrains.php.lang.psi.elements.PhpTypedElement)9 InterfacesExtractUtil (com.kalessil.phpStorm.phpInspectionsEA.utils.hierarhy.InterfacesExtractUtil)8 Collectors (java.util.stream.Collectors)8