Search in sources :

Example 1 with PhpType

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

the class OffsetOperationsInspector method isContainerSupportsArrayAccess.

@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private boolean isContainerSupportsArrayAccess(@NotNull ArrayAccessExpression expression, @NotNull Set<String> indexTypesSupported) {
    // ok JB parses `$var[]= ...` always as array, lets make it working properly and report them later
    final PsiElement container = expression.getValue();
    if (null == container) {
        return false;
    }
    final Set<String> containerTypes = new HashSet<>();
    if (container instanceof PhpTypedElement) {
        final PhpType type = OpenapiResolveUtil.resolveType((PhpTypedElement) container, container.getProject());
        if (type != null && !type.hasUnknown()) {
            type.getTypes().forEach(t -> containerTypes.add(Types.getType(t)));
        }
    }
    /* === cleanup resolved types === */
    if (containerTypes.contains(Types.strMixed)) {
        // mixed are not analyzable
        containerTypes.clear();
        return true;
    }
    if (containerTypes.size() == 2 && containerTypes.contains(Types.strString)) {
        final boolean isForeachKeyType = containerTypes.contains(Types.strInteger);
        final boolean isCoreApiStringType = containerTypes.contains(Types.strBoolean);
        if (isForeachKeyType || isCoreApiStringType) {
            containerTypes.clear();
            return true;
        }
    }
    if (containerTypes.contains(Types.strCallable)) {
        // treat callable as array
        containerTypes.remove(Types.strCallable);
        containerTypes.add(Types.strArray);
        containerTypes.add(Types.strString);
    }
    // don't process nulls
    containerTypes.remove(Types.strNull);
    // don't process generalized objects
    containerTypes.remove(Types.strObject);
    // don't process mysterious empty set type
    containerTypes.remove(Types.strEmptySet);
    /* === if we could not resolve container, do nothing === */
    if (containerTypes.isEmpty()) {
        return true;
    }
    final Project project = container.getProject();
    final PhpIndex index = PhpIndex.getInstance(project);
    boolean supportsOffsets = false;
    for (final String typeToCheck : containerTypes) {
        // commonly used case: string and array
        if (typeToCheck.equals(Types.strArray) || typeToCheck.equals(Types.strString)) {
            supportsOffsets = true;
            /* here we state which regular index types we want to promote */
            indexTypesSupported.add(Types.strString);
            indexTypesSupported.add(Types.strInteger);
            continue;
        }
        // some of possible types are scalars, what's wrong
        if (!typeToCheck.isEmpty() && typeToCheck.charAt(0) != '\\') {
            supportsOffsets = false;
            break;
        }
        // now we are at point when analyzing classes only
        final List<PhpClass> classes = OpenapiResolveUtil.resolveClassesAndInterfacesByFQN(typeToCheck, index);
        for (final PhpClass clazz : classes) {
            /* custom offsets management, follow annotated types */
            for (final String methodName : Arrays.asList("offsetGet", "offsetSet", "__get", "__set")) {
                final Method method = OpenapiResolveUtil.resolveMethod(clazz, methodName);
                if (method != null) {
                    /* regular array index types can be applied */
                    if (methodName.startsWith("__")) {
                        indexTypesSupported.add(Types.strString);
                        indexTypesSupported.add(Types.strInteger);
                    } else /* user-defined index types can be applied */
                    {
                        final Parameter[] parameters = method.getParameters();
                        if (parameters.length > 0) {
                            final PhpType type = OpenapiResolveUtil.resolveType(parameters[0], project);
                            if (type != null) {
                                type.filterUnknown().getTypes().forEach(t -> indexTypesSupported.add(Types.getType(t)));
                            }
                        }
                    }
                    supportsOffsets = true;
                }
            }
        }
        classes.clear();
    }
    // when might not support offset access, reuse types container to report back why
    if (!supportsOffsets) {
        indexTypesSupported.clear();
        indexTypesSupported.addAll(containerTypes);
    }
    containerTypes.clear();
    return supportsOffsets;
}
Also used : PhpIndex(com.jetbrains.php.PhpIndex) 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 2 with PhpType

use of com.jetbrains.php.lang.psi.resolve.types.PhpType 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 3 with PhpType

use of com.jetbrains.php.lang.psi.resolve.types.PhpType 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 4 with PhpType

use of com.jetbrains.php.lang.psi.resolve.types.PhpType in project yii2support by nvlad.

the class ClassUtils method getClassByVariable.

@Nullable
public static PhpClass getClassByVariable(Variable element) {
    if (element == null)
        return null;
    PhpType type = element.getType();
    String typeString = type.toString();
    String[] split = typeString.split("\\|");
    typeString = split[0];
    Pattern pattern = Pattern.compile("\\\\[A-Za-z\\\\]+");
    Matcher matcher = pattern.matcher(typeString);
    if (matcher.find())
        typeString = matcher.group();
    Collection<PhpClass> anyByFQN = PhpIndex.getInstance(element.getProject()).getAnyByFQN(typeString);
    if (anyByFQN.isEmpty())
        return null;
    else
        return anyByFQN.iterator().next();
}
Also used : Pattern(java.util.regex.Pattern) Matcher(java.util.regex.Matcher) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) Nullable(org.jetbrains.annotations.Nullable)

Example 5 with PhpType

use of com.jetbrains.php.lang.psi.resolve.types.PhpType in project yii2support by nvlad.

the class ClassUtils method getPhpClassByCallChain.

@Nullable
public static PhpClass getPhpClassByCallChain(MethodReference methodRef) {
    while (methodRef != null) {
        PhpExpression expr = methodRef.getClassReference();
        if (expr instanceof ClassReference) {
            return (PhpClass) ((ClassReference) expr).resolve();
        } else if (expr instanceof MethodReference) {
            methodRef = (MethodReference) expr;
        } else if (expr instanceof Variable) {
            PhpType type = expr.getType();
            String strType = type.toString();
            int index1 = strType.indexOf('\\');
            int index2 = strType.indexOf('.');
            if (index2 == -1)
                index2 = strType.length() - index1;
            if (index1 >= 0 && index2 >= 0 && index2 > index1) {
                String className = strType.substring(index1, index2);
                return ClassUtils.getClass(PhpIndex.getInstance(methodRef.getProject()), className);
            } else {
                return null;
            }
        // type.toString()
        } else {
            return null;
        }
    }
    return null;
}
Also used : PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) Nullable(org.jetbrains.annotations.Nullable)

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