Search in sources :

Example 1 with PhpTypedElement

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

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

the class ComparableCoreClassesStrategy method isComparableObject.

private static boolean isComparableObject(@NotNull PsiElement operand, @NotNull PhpIndex index) {
    /* extract types of operand, check if classes are/inherited from \DateTime */
    final Set<String> operandTypes = new HashSet<>();
    if (operand instanceof PhpTypedElement) {
        final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) operand, operand.getProject());
        if (resolved != null) {
            resolved.filterUnknown().getTypes().forEach(t -> operandTypes.add(Types.getType(t)));
        }
    }
    if (!TypesSemanticsUtil.isNullableObjectInterface(operandTypes)) {
        operandTypes.clear();
        return false;
    }
    /* collect classes to check for \DateTime relationship */
    final List<PhpClass> operandClasses = new ArrayList<>();
    operandTypes.stream().filter(fqn -> fqn.charAt(0) == '\\').forEach(fqn -> operandClasses.addAll(OpenapiResolveUtil.resolveClassesAndInterfacesByFQN(fqn, index)));
    operandTypes.clear();
    /* inspect classes for being a/child of special once */
    for (final PhpClass clazz : operandClasses) {
        final HashSet<PhpClass> hierarchy = InterfacesExtractUtil.getCrawlInheritanceTree(clazz, true);
        for (final PhpClass oneClass : hierarchy) {
            if (comparableObjects.contains(oneClass.getFQN())) {
                return true;
            }
        }
        hierarchy.clear();
    }
    operandClasses.clear();
    return false;
}
Also used : PhpClass(com.jetbrains.php.lang.psi.elements.PhpClass) ExpressionSemanticUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.ExpressionSemanticUtil) Types(com.kalessil.phpStorm.phpInspectionsEA.utils.Types) TypesSemanticsUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.TypesSemanticsUtil) InterfacesExtractUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.hierarhy.InterfacesExtractUtil) Function(com.jetbrains.php.lang.psi.elements.Function) Set(java.util.Set) PhpIndex(com.jetbrains.php.PhpIndex) PhpTypedElement(com.jetbrains.php.lang.psi.elements.PhpTypedElement) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) Nullable(org.jetbrains.annotations.Nullable) List(java.util.List) OpenapiResolveUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.OpenapiResolveUtil) PsiElement(com.intellij.psi.PsiElement) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) NotNull(org.jetbrains.annotations.NotNull) ProblemsHolder(com.intellij.codeInspection.ProblemsHolder) PhpClass(com.jetbrains.php.lang.psi.elements.PhpClass) ArrayList(java.util.ArrayList) PhpTypedElement(com.jetbrains.php.lang.psi.elements.PhpTypedElement) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) HashSet(java.util.HashSet)

Example 3 with PhpTypedElement

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

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

the class MustReturnSpecifiedTypeStrategy method apply.

public static void apply(@NotNull PhpType allowedTypes, @NotNull Method method, @NotNull ProblemsHolder holder) {
    final PsiElement returnType = OpenapiElementsUtil.getReturnType(method);
    if (returnType != null) {
        /* case: return type has ben specified */
        final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) returnType, holder.getProject());
        if (resolved != null) {
            final PhpType normalizedType = new PhpType();
            resolved.filterUnknown().getTypes().forEach(t -> normalizedType.add(Types.getType(t)));
            if (!normalizedType.isEmpty() && !PhpType.isSubType(normalizedType, allowedTypes)) {
                final PsiElement nameNode = NamedElementUtil.getNameIdentifier(method);
                if (nameNode != null) {
                    final PhpType withoutStatic = allowedTypes.filter((new PhpType()).add(Types.strStatic));
                    holder.registerProblem(nameNode, String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), method.getName(), withoutStatic.toString(), normalizedType.toString()));
                }
            }
        }
    } else {
        final Collection<PhpReturn> returns = PsiTreeUtil.findChildrenOfType(method, PhpReturn.class);
        if (returns.isEmpty()) {
            /* case: the method doesn't return anything */
            final PsiElement nameNode = NamedElementUtil.getNameIdentifier(method);
            if (nameNode != null) {
                final PhpType withoutStatic = allowedTypes.filter((new PhpType()).add(Types.strStatic));
                holder.registerProblem(nameNode, String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), method.getName(), withoutStatic.toString(), ""));
            }
        } else {
            /* case: method returns non-compatible type */
            final PhpType withoutStatic = allowedTypes.filter((new PhpType()).add(Types.strStatic));
            final Project project = holder.getProject();
            for (final PhpReturn expression : returns) {
                final PhpType normalizedType = new PhpType();
                final PsiElement returnValue = ExpressionSemanticUtil.getExpressionTroughParenthesis(ExpressionSemanticUtil.getReturnValue(expression));
                if (returnValue instanceof PhpTypedElement) {
                    /* previously we had an issue with https://youtrack.jetbrains.com/issue/WI-31249 here */
                    final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) returnValue, project);
                    if (resolved != null) {
                        resolved.filterUnknown().getTypes().forEach(t -> normalizedType.add(Types.getType(t)));
                        /* case: resolve has failed or resolved types are compatible */
                        if (normalizedType.isEmpty() || PhpType.isSubType(normalizedType, allowedTypes)) {
                            continue;
                        } else /* case: closure or anonymous class */
                        if (method != ExpressionSemanticUtil.getScope(expression)) {
                            continue;
                        }
                    }
                }
                holder.registerProblem(expression, String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), method.getName(), withoutStatic.toString(), normalizedType.toString()));
            }
            returns.clear();
        }
    }
}
Also used : Project(com.intellij.openapi.project.Project) PhpReturn(com.jetbrains.php.lang.psi.elements.PhpReturn) PhpTypedElement(com.jetbrains.php.lang.psi.elements.PhpTypedElement) PsiElement(com.intellij.psi.PsiElement) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType)

Example 5 with PhpTypedElement

use of com.jetbrains.php.lang.psi.elements.PhpTypedElement 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)

Aggregations

PsiElement (com.intellij.psi.PsiElement)9 PhpTypedElement (com.jetbrains.php.lang.psi.elements.PhpTypedElement)9 PhpType (com.jetbrains.php.lang.psi.resolve.types.PhpType)9 NotNull (org.jetbrains.annotations.NotNull)7 HashSet (java.util.HashSet)6 ProblemsHolder (com.intellij.codeInspection.ProblemsHolder)5 BasePhpElementVisitor (com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor)5 IElementType (com.intellij.psi.tree.IElementType)4 BinaryExpression (com.jetbrains.php.lang.psi.elements.BinaryExpression)4 OpenapiResolveUtil (com.kalessil.phpStorm.phpInspectionsEA.utils.OpenapiResolveUtil)4 Set (java.util.Set)4 Project (com.intellij.openapi.project.Project)3 PsiElementVisitor (com.intellij.psi.PsiElementVisitor)3 PhpIndex (com.jetbrains.php.PhpIndex)3 PhpClass (com.jetbrains.php.lang.psi.elements.PhpClass)3 BasePhpInspection (com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpInspection)3 MessagesPresentationUtil (com.kalessil.phpStorm.phpInspectionsEA.utils.MessagesPresentationUtil)3 Types (com.kalessil.phpStorm.phpInspectionsEA.utils.Types)3 ProblemHighlightType (com.intellij.codeInspection.ProblemHighlightType)2 PhpTokenTypes (com.jetbrains.php.lang.lexer.PhpTokenTypes)2