Search in sources :

Example 1 with Types

use of com.kalessil.phpStorm.phpInspectionsEA.utils.Types 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 2 with Types

use of com.kalessil.phpStorm.phpInspectionsEA.utils.Types in project phpinspectionsea by kalessil.

the class CollectPossibleThrowsUtil method collectNestedAndWorkflowExceptions.

public static HashMap<PhpClass, HashSet<PsiElement>> collectNestedAndWorkflowExceptions(PsiElement scope, HashSet<PsiElement> processed, @NotNull final ProblemsHolder holder) {
    final HashMap<PhpClass, HashSet<PsiElement>> exceptions = new HashMap<>();
    /* recursively invoke and analyse nested try-catches checks */
    final Collection<Try> tryStatements = PsiTreeUtil.findChildrenOfType(scope, Try.class);
    if (tryStatements.size() > 0) {
        for (Try nestedTry : tryStatements) {
            if (!processed.contains(nestedTry)) {
                /* process nested workflow */
                final HashMap<PhpClass, HashSet<PsiElement>> nestedTryExceptions = collectNestedAndWorkflowExceptions(nestedTry, processed, holder);
                // holder.registerProblem(nestedTry.getFirstChild(), "Nested: " + nestedTryExceptions.toString(), ProblemHighlightType.WEAK_WARNING);
                if (nestedTryExceptions.size() > 0) {
                    for (final Map.Entry<PhpClass, HashSet<PsiElement>> nestedTryExceptionsPair : nestedTryExceptions.entrySet()) {
                        /* extract pairs Exception class => source expressions */
                        final PhpClass key = nestedTryExceptionsPair.getKey();
                        final HashSet<PsiElement> expressionsToDispatch = nestedTryExceptionsPair.getValue();
                        if (exceptions.containsKey(key)) {
                            /* merge entries and release refs */
                            exceptions.get(key).addAll(expressionsToDispatch);
                            expressionsToDispatch.clear();
                        } else {
                            /* store as it is */
                            exceptions.put(key, expressionsToDispatch);
                        }
                    }
                    nestedTryExceptions.clear();
                }
            }
        }
        tryStatements.clear();
    }
    /* process try-catch */
    if (scope instanceof Try) {
        /* extract workflow exceptions */
        HashMap<PhpClass, HashSet<PsiElement>> tryWorkflowExceptions = collectTryWorkflowExceptions((Try) scope, processed, holder);
        // holder.registerProblem(scope.getFirstChild(), "Throws: " + tryWorkflowExceptions.toString(), ProblemHighlightType.WEAK_WARNING);
        /* mark processed and exit, as try-catch handled in special way */
        processed.add(scope);
        exceptions.clear();
        return tryWorkflowExceptions;
    }
    /* process new statements: throws, constructors */
    Collection<NewExpression> newExpressions = PsiTreeUtil.findChildrenOfType(scope, NewExpression.class);
    if (newExpressions.size() > 0) {
        for (NewExpression newExpression : newExpressions) {
            /* skip processed */
            if (processed.contains(newExpression)) {
                continue;
            }
            // holder.registerProblem(newExpression, "New expression wil be analyzed", ProblemHighlightType.WEAK_WARNING);
            /* skip what can not be resolved */
            ClassReference newClassRef = newExpression.getClassReference();
            if (null == newClassRef) {
                processed.add(newExpression);
                continue;
            }
            PhpClass newClass;
            final PsiElement resolved = OpenapiResolveUtil.resolveReference(newClassRef);
            if (resolved instanceof PhpClass) {
                newClass = (PhpClass) resolved;
            } else if (resolved instanceof Method) {
                newClass = ((Method) resolved).getContainingClass();
            } else {
                processed.add(newExpression);
                continue;
            }
            /* throws processed */
            if (newExpression.getParent() instanceof PhpThrow) {
                /* put an expression, create container if necessary */
                if (!exceptions.containsKey(newClass)) {
                    exceptions.put(newClass, new HashSet<>());
                }
                exceptions.get(newClass).add(newExpression.getParent());
                processed.add(newExpression);
                continue;
            }
            /* process constructors invocation */
            final Method constructor = newClass == null ? null : newClass.getConstructor();
            if (constructor != null) {
                // holder.registerProblem(newExpression, "Constructor found", ProblemHighlightType.WEAK_WARNING);
                /* lookup for annotated exceptions */
                final HashSet<PhpClass> constructorExceptions = new HashSet<>();
                ThrowsResolveUtil.resolveThrownExceptions(constructor, constructorExceptions);
                /* link expression with each possible exception */
                if (constructorExceptions.size() > 0) {
                    for (PhpClass constructorException : constructorExceptions) {
                        /* put an expression, create container if necessary */
                        if (!exceptions.containsKey(constructorException)) {
                            exceptions.put(constructorException, new HashSet<>());
                        }
                        exceptions.get(constructorException).add(newExpression.getParent());
                    }
                    constructorExceptions.clear();
                }
            }
            processed.add(newExpression);
        }
        newExpressions.clear();
    }
    /* process throws - some of them might not use new-expression */
    final Project project = holder.getProject();
    final PhpIndex objIndex = PhpIndex.getInstance(project);
    Collection<PhpThrow> throwExpressions = PsiTreeUtil.findChildrenOfType(scope, PhpThrow.class);
    if (!throwExpressions.isEmpty()) {
        for (final PhpThrow throwExpression : throwExpressions) {
            /* skip processed */
            if (processed.contains(throwExpression)) {
                continue;
            }
            /* resolve argument */
            final PsiElement argument = throwExpression.getArgument();
            if (argument instanceof PhpTypedElement) {
                /* resolve argument types */
                final HashSet<String> types = new HashSet<>();
                final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) argument, project);
                if (resolved != null) {
                    resolved.filterUnknown().getTypes().forEach(t -> types.add(Types.getType(t)));
                }
                if (!types.isEmpty()) {
                    /* remove extra definition of \Exception unexpectedly added by PhpStorm */
                    final boolean dropExtraDefinitions = argument instanceof Variable && types.size() > 1 && types.contains("\\Exception");
                    if (dropExtraDefinitions) {
                        types.remove("\\Exception");
                    }
                    for (final String type : types) {
                        if (type.startsWith("\\")) {
                            /* process classes references */
                            final Collection<PhpClass> classes = OpenapiResolveUtil.resolveClassesByFQN(type, objIndex);
                            if (!classes.isEmpty()) {
                                /* put an expression, create container if necessary */
                                final PhpClass exception = classes.iterator().next();
                                exceptions.computeIfAbsent(exception, e -> new HashSet<>()).add(throwExpression);
                            }
                        }
                    }
                    types.clear();
                }
            }
            processed.add(throwExpression);
        }
        throwExpressions.clear();
    }
    /* process nested calls */
    Collection<MethodReference> calls = PsiTreeUtil.findChildrenOfType(scope, MethodReference.class);
    if (calls.size() > 0) {
        for (MethodReference call : calls) {
            /* skip processed */
            if (processed.contains(call)) {
                continue;
            }
            PsiElement methodResolved = OpenapiResolveUtil.resolveReference(call);
            if (methodResolved instanceof Method) {
                /* lookup for annotated exceptions */
                final HashSet<PhpClass> methodExceptions = new HashSet<>();
                ThrowsResolveUtil.resolveThrownExceptions((Method) methodResolved, methodExceptions);
                /* link expression with each possible exception */
                if (methodExceptions.size() > 0) {
                    for (PhpClass methodException : methodExceptions) {
                        /* put an expression, create container if necessary */
                        if (!exceptions.containsKey(methodException)) {
                            exceptions.put(methodException, new HashSet<>());
                        }
                        exceptions.get(methodException).add(call);
                    }
                    methodExceptions.clear();
                }
            }
            processed.add(call);
        }
        calls.clear();
    }
    return exceptions;
}
Also used : com.jetbrains.php.lang.psi.elements(com.jetbrains.php.lang.psi.elements) Types(com.kalessil.phpStorm.phpInspectionsEA.utils.Types) InterfacesExtractUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.hierarhy.InterfacesExtractUtil) Collection(java.util.Collection) HashMap(java.util.HashMap) PhpIndex(com.jetbrains.php.PhpIndex) HashSet(java.util.HashSet) PsiTreeUtil(com.intellij.psi.util.PsiTreeUtil) OpenapiResolveUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.OpenapiResolveUtil) ThrowsResolveUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.phpDoc.ThrowsResolveUtil) Map(java.util.Map) 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) ProblemsHolder(com.intellij.codeInspection.ProblemsHolder) HashMap(java.util.HashMap) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) PsiElement(com.intellij.psi.PsiElement) HashSet(java.util.HashSet) PhpIndex(com.jetbrains.php.PhpIndex) Project(com.intellij.openapi.project.Project) HashMap(java.util.HashMap) Map(java.util.Map)

Aggregations

ProblemsHolder (com.intellij.codeInspection.ProblemsHolder)2 PsiElement (com.intellij.psi.PsiElement)2 PhpIndex (com.jetbrains.php.PhpIndex)2 PhpType (com.jetbrains.php.lang.psi.resolve.types.PhpType)2 OpenapiResolveUtil (com.kalessil.phpStorm.phpInspectionsEA.utils.OpenapiResolveUtil)2 Types (com.kalessil.phpStorm.phpInspectionsEA.utils.Types)2 InterfacesExtractUtil (com.kalessil.phpStorm.phpInspectionsEA.utils.hierarhy.InterfacesExtractUtil)2 HashSet (java.util.HashSet)2 NotNull (org.jetbrains.annotations.NotNull)2 Project (com.intellij.openapi.project.Project)1 PsiTreeUtil (com.intellij.psi.util.PsiTreeUtil)1 com.jetbrains.php.lang.psi.elements (com.jetbrains.php.lang.psi.elements)1 Function (com.jetbrains.php.lang.psi.elements.Function)1 PhpClass (com.jetbrains.php.lang.psi.elements.PhpClass)1 PhpTypedElement (com.jetbrains.php.lang.psi.elements.PhpTypedElement)1 ExpressionSemanticUtil (com.kalessil.phpStorm.phpInspectionsEA.utils.ExpressionSemanticUtil)1 TypesSemanticsUtil (com.kalessil.phpStorm.phpInspectionsEA.utils.TypesSemanticsUtil)1 ThrowsResolveUtil (com.kalessil.phpStorm.phpInspectionsEA.utils.phpDoc.ThrowsResolveUtil)1 ArrayList (java.util.ArrayList)1 Collection (java.util.Collection)1