Search in sources :

Example 46 with PhpType

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

the class ArrayCastingEquivalentInspector method buildVisitor.

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

        @Override
        public void visitPhpIf(@NotNull If expression) {
            if (!ExpressionSemanticUtil.hasAlternativeBranches(expression)) {
                /* body has only assignment, which to be extracted */
                final GroupStatement body = ExpressionSemanticUtil.getGroupStatement(expression);
                if (body != null && ExpressionSemanticUtil.countExpressionsInGroup(body) == 1) {
                    PsiElement candidate = ExpressionSemanticUtil.getLastStatement(body);
                    candidate = (candidate == null ? null : candidate.getFirstChild());
                    if (!OpenapiTypesUtil.isAssignment(candidate)) {
                        return;
                    }
                    /* expecting !function(...) in condition */
                    PsiElement condition = null;
                    PsiElement operation = null;
                    if (expression.getCondition() instanceof UnaryExpression) {
                        final UnaryExpression inversion = (UnaryExpression) expression.getCondition();
                        operation = inversion.getOperation();
                        condition = ExpressionSemanticUtil.getExpressionTroughParenthesis(inversion.getValue());
                    }
                    if (!OpenapiTypesUtil.is(operation, PhpTokenTypes.opNOT) || !OpenapiTypesUtil.isFunctionReference(condition)) {
                        return;
                    }
                    /* inspect expression */
                    final AssignmentExpression assignment = (AssignmentExpression) candidate;
                    final PsiElement trueExpression = assignment.getVariable();
                    final PsiElement falseExpression = assignment.getValue();
                    if (trueExpression != null && falseExpression != null && this.isArrayCasting((FunctionReference) condition, trueExpression, falseExpression)) {
                        final String replacement = trueExpression.getText() + " = (array) " + trueExpression.getText();
                        holder.registerProblem(expression.getFirstChild(), message, new SimplifyFix(replacement));
                    }
                }
            }
        }

        /* expecting !function(...), true and false expressions */
        @Override
        public void visitPhpTernaryExpression(@NotNull TernaryExpression expression) {
            PsiElement trueExpression = expression.getTrueVariant();
            PsiElement falseExpression = expression.getFalseVariant();
            PsiElement condition = ExpressionSemanticUtil.getExpressionTroughParenthesis(expression.getCondition());
            if (condition instanceof UnaryExpression) {
                final UnaryExpression unary = (UnaryExpression) condition;
                if (OpenapiTypesUtil.is(unary.getOperation(), PhpTokenTypes.opNOT)) {
                    condition = ExpressionSemanticUtil.getExpressionTroughParenthesis(unary.getValue());
                    trueExpression = expression.getFalseVariant();
                    falseExpression = expression.getTrueVariant();
                }
            }
            if (trueExpression != null && falseExpression != null && OpenapiTypesUtil.isFunctionReference(condition)) {
                if (this.isArrayCasting((FunctionReference) condition, trueExpression, falseExpression)) {
                    final String replacement = "(array) " + trueExpression.getText();
                    holder.registerProblem(expression, message, new SimplifyFix(replacement));
                }
            }
        }

        private boolean isArrayCasting(@NotNull FunctionReference condition, @NotNull PsiElement trueExpression, @NotNull PsiElement falseExpression) {
            /* false variant should be array creation */
            if (falseExpression instanceof ArrayCreationExpression) {
                /* condition expected to be is_array(arg) */
                final String functionName = condition.getName();
                final PsiElement[] params = condition.getParameters();
                if (params.length == 1 && functionName != null && functionName.equals("is_array")) {
                    /* extract array values, expected one value only */
                    final List<PsiElement> valuesSet = new ArrayList<>();
                    for (final PsiElement child : falseExpression.getChildren()) {
                        if (child instanceof PhpPsiElement) {
                            valuesSet.add(child.getFirstChild());
                        }
                    }
                    /* ensure both true/false branches applied to the same subject */
                    boolean result = valuesSet.size() == 1 && OpeanapiEquivalenceUtil.areEqual(trueExpression, params[0]) && OpeanapiEquivalenceUtil.areEqual(trueExpression, valuesSet.get(0));
                    valuesSet.clear();
                    /* ensure the subject type is array casting safe */
                    if (result) {
                        final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) trueExpression, trueExpression.getProject());
                        if (resolved == null || resolved.isEmpty() || resolved.hasUnknown()) {
                            /* well, types resolved partially - do not report */
                            result = false;
                        } else {
                            /* also, object casting to array "exports" it instead of wrapping */
                            for (final String type : resolved.getTypes()) {
                                if (Types.getType(type).startsWith("\\")) {
                                    result = false;
                                    break;
                                }
                            }
                        }
                    }
                    return result;
                }
            }
            return false;
        }
    };
}
Also used : ArrayList(java.util.ArrayList) 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)

Example 47 with PhpType

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

the class ReferencingObjectsInspector method buildVisitor.

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

        /* re-dispatch to inspector */
        @Override
        public void visitPhpMethod(@NotNull Method method) {
            this.inspectCallable(method);
        }

        @Override
        public void visitPhpFunction(@NotNull Function function) {
            this.inspectCallable(function);
        }

        private void inspectCallable(@NotNull Function callable) {
            if (NamedElementUtil.getNameIdentifier(callable) != null) {
                Arrays.stream(callable.getParameters()).filter(parameter -> {
                    final PhpType declared = parameter.getDeclaredType();
                    return !declared.isEmpty() && parameter.isPassByRef() && !PhpType.isSubType(declared, php7Types);
                }).filter(parameter -> {
                    boolean result = true;
                    final String parameterName = parameter.getName();
                    final GroupStatement body = ExpressionSemanticUtil.getGroupStatement(callable);
                    for (final Variable variable : PsiTreeUtil.findChildrenOfType(body, Variable.class)) {
                        final PsiElement parent = variable.getParent();
                        if (parent instanceof AssignmentExpression && parameterName.equals(variable.getName())) {
                            final AssignmentExpression assignment = (AssignmentExpression) parent;
                            if (assignment.getVariable() == variable) {
                                result = false;
                                break;
                            }
                        }
                    }
                    return result;
                }).forEach(parameter -> {
                    final String message = messageParameter.replace("%p%", parameter.getName());
                    holder.registerProblem(parameter, message, new ParameterLocalFix(parameter));
                });
            }
        }

        @Override
        public void visitPhpNewExpression(@NotNull NewExpression expression) {
            final PsiElement parent = expression.getParent();
            if (parent instanceof AssignmentExpression) {
                final AssignmentExpression assignment = (AssignmentExpression) parent;
                if (assignment.getValue() == expression) {
                    PsiElement operation = assignment.getValue().getPrevSibling();
                    if (operation instanceof PsiWhiteSpace) {
                        operation = operation.getPrevSibling();
                    }
                    if (operation != null && operation.getText().replaceAll("\\s+", "").equals("=&")) {
                        holder.registerProblem(expression, messageAssignment, new InstantiationLocalFix(operation));
                    }
                }
            }
        }
    };
}
Also used : PhpPsiElementFactory(com.jetbrains.php.lang.psi.PhpPsiElementFactory) Arrays(java.util.Arrays) BasePhpInspection(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpInspection) ExpressionSemanticUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.ExpressionSemanticUtil) com.jetbrains.php.lang.psi.elements(com.jetbrains.php.lang.psi.elements) LeafPsiElement(com.intellij.psi.impl.source.tree.LeafPsiElement) PsiTreeUtil(com.intellij.psi.util.PsiTreeUtil) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) ProblemDescriptor(com.intellij.codeInspection.ProblemDescriptor) NamedElementUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.NamedElementUtil) Project(com.intellij.openapi.project.Project) com.intellij.psi(com.intellij.psi) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) NotNull(org.jetbrains.annotations.NotNull) LocalQuickFix(com.intellij.codeInspection.LocalQuickFix) 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) LeafPsiElement(com.intellij.psi.impl.source.tree.LeafPsiElement) NotNull(org.jetbrains.annotations.NotNull)

Example 48 with PhpType

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

the class ForeachSourceInspector method buildVisitor.

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

        @Override
        public void visitPhpForeach(@NotNull ForeachStatement foreach) {
            final PsiElement source = ExpressionSemanticUtil.getExpressionTroughParenthesis(foreach.getArray());
            if (source instanceof PhpTypedElement && !isEnsuredByPyParentIf(foreach, source)) {
                this.analyseContainer(source);
            }
        }

        /* should cover is_array/is_iterable in direct parent if of the loop, while PS types resolving gets improved */
        private boolean isEnsuredByPyParentIf(@NotNull ForeachStatement foreach, @NotNull PsiElement source) {
            boolean result = false;
            if (foreach.getPrevPsiSibling() == null) {
                final PsiElement ifCandidate = foreach.getParent() instanceof GroupStatement ? foreach.getParent().getParent() : null;
                final PsiElement conditions;
                if (ifCandidate instanceof If) {
                    conditions = ((If) ifCandidate).getCondition();
                } else if (ifCandidate instanceof ElseIf) {
                    conditions = ((ElseIf) ifCandidate).getCondition();
                } else {
                    conditions = null;
                }
                if (conditions != null) {
                    for (final PsiElement candidate : PsiTreeUtil.findChildrenOfType(conditions, source.getClass())) {
                        if (OpeanapiEquivalenceUtil.areEqual(candidate, source)) {
                            final PsiElement call = candidate.getParent() instanceof ParameterList ? candidate.getParent().getParent() : null;
                            if (OpenapiTypesUtil.isFunctionReference(call)) {
                                final String functionName = ((FunctionReference) call).getName();
                                if (functionName != null && (functionName.equals("is_array") || functionName.equals("is_iterable"))) {
                                    result = true;
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            return result;
        }

        private void analyseContainer(@NotNull PsiElement container) {
            final PhpType resolvedType = OpenapiResolveUtil.resolveType((PhpTypedElement) container, container.getProject());
            if (resolvedType == null) {
                return;
            }
            final Set<String> types = new HashSet<>();
            resolvedType.filterUnknown().getTypes().forEach(t -> types.add(Types.getType(t)));
            if (types.isEmpty()) {
                /* false-positives: pre-defined variables */
                if (container instanceof Variable) {
                    final String variableName = ((Variable) container).getName();
                    if (ExpressionCostEstimateUtil.predefinedVars.contains(variableName)) {
                        return;
                    }
                }
                if (REPORT_UNRECOGNIZED_TYPES) {
                    holder.registerProblem(container, patternNotRecognized, ProblemHighlightType.WEAK_WARNING);
                }
                return;
            }
            /* false-positives: multiple return types checked only in function/method; no global context */
            final PsiElement scope = ExpressionSemanticUtil.getBlockScope(container);
            if (types.size() > 1 && !(scope instanceof Function)) {
                types.clear();
                return;
            }
            /* false-positives: mixed parameter type, parameter overridden before foreach */
            if (types.size() > 1 && scope instanceof Function && container instanceof Variable) {
                final String parameter = ((Variable) container).getName();
                final PhpEntryPointInstruction start = ((Function) scope).getControlFlow().getEntryPoint();
                final PhpAccessVariableInstruction[] uses = PhpControlFlowUtil.getFollowingVariableAccessInstructions(start, parameter, false);
                for (final PhpAccessVariableInstruction instruction : uses) {
                    final PhpPsiElement expression = instruction.getAnchor();
                    /* when matched itself, stop processing */
                    if (expression == container) {
                        break;
                    }
                    final PsiElement parent = expression.getParent();
                    if (parent instanceof AssignmentExpression) {
                        final PsiElement matchCandidate = ((AssignmentExpression) parent).getVariable();
                        if (matchCandidate != null && OpeanapiEquivalenceUtil.areEqual(matchCandidate, container)) {
                            types.clear();
                            return;
                        }
                    }
                }
            }
            /* false-positives: array type parameter declaration adds mixed */
            if (types.size() > 1 && scope instanceof Function && container instanceof ArrayAccessExpression) {
                final PsiElement candidate = ((ArrayAccessExpression) container).getValue();
                if (candidate instanceof Variable && types.contains(Types.strMixed) && types.contains(Types.strArray)) {
                    types.remove(Types.strMixed);
                }
            }
            /* gracefully request to specify exact types which can appear (mixed, object) */
            if (types.contains(Types.strMixed)) {
                /* false-positive: mixed definitions from stub functions */
                boolean isStubFunction = false;
                if (OpenapiTypesUtil.isFunctionReference(container)) {
                    final PsiElement function = OpenapiResolveUtil.resolveReference((FunctionReference) container);
                    final String filePath = function == null ? null : function.getContainingFile().getVirtualFile().getCanonicalPath();
                    isStubFunction = filePath != null && filePath.contains(".jar!") && filePath.contains("/stubs/");
                }
                /* false-positive: mixed definition from array type */
                if (!isStubFunction && !types.contains(Types.strArray) && REPORT_MIXED_TYPES) {
                    final String message = String.format(patternMixedTypes, Types.strMixed);
                    holder.registerProblem(container, message, ProblemHighlightType.WEAK_WARNING);
                }
                types.remove(Types.strMixed);
            }
            if (types.contains(Types.strObject)) {
                if (REPORT_MIXED_TYPES) {
                    final String message = String.format(patternMixedTypes, Types.strObject);
                    holder.registerProblem(container, message, ProblemHighlightType.WEAK_WARNING);
                }
                types.remove(Types.strObject);
            }
            /* respect patter when returned array and bool|null for indicating failures*/
            if (types.size() == 2 && types.contains(Types.strArray)) {
                types.remove(Types.strBoolean);
                types.remove(Types.strNull);
            }
            /* do not process foreach-compatible types */
            types.remove(Types.strArray);
            types.remove(Types.strIterable);
            types.remove("\\Traversable");
            types.remove("\\Iterator");
            types.remove("\\IteratorAggregate");
            /* don't process mysterious empty set type */
            types.remove(Types.strEmptySet);
            /* iterate rest of types */
            if (!types.isEmpty()) {
                final PhpIndex index = PhpIndex.getInstance(holder.getProject());
                for (final String type : types) {
                    /* report if scalar type is met */
                    if (!type.startsWith("\\")) {
                        holder.registerProblem(container, String.format(patternScalar, type), ProblemHighlightType.GENERIC_ERROR);
                        continue;
                    }
                    /* check classes for the Traversable interface in the inheritance chain */
                    final List<PhpClass> classes = OpenapiResolveUtil.resolveClassesAndInterfacesByFQN(type, index);
                    if (!classes.isEmpty()) {
                        boolean hasTraversable = false;
                        for (final PhpClass clazz : classes) {
                            final Set<PhpClass> interfaces = InterfacesExtractUtil.getCrawlInheritanceTree(clazz, false);
                            if (!interfaces.isEmpty()) {
                                hasTraversable = interfaces.stream().anyMatch(i -> i.getFQN().equals("\\Traversable"));
                                interfaces.clear();
                                if (hasTraversable) {
                                    break;
                                }
                            }
                        }
                        classes.clear();
                        if (!hasTraversable) {
                            holder.registerProblem(container, String.format(patternObject, type));
                        }
                    }
                }
                types.clear();
            }
        }
    };
}
Also used : PhpEntryPointInstruction(com.jetbrains.php.codeInsight.controlFlow.instructions.PhpEntryPointInstruction) BasePhpInspection(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpInspection) com.jetbrains.php.lang.psi.elements(com.jetbrains.php.lang.psi.elements) InterfacesExtractUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.hierarhy.InterfacesExtractUtil) Set(java.util.Set) ExpressionCostEstimateUtil(com.kalessil.phpStorm.phpInspectionsEA.inspectors.ifs.utils.ExpressionCostEstimateUtil) PhpIndex(com.jetbrains.php.PhpIndex) OptionsComponent(com.kalessil.phpStorm.phpInspectionsEA.options.OptionsComponent) PhpControlFlowUtil(com.jetbrains.php.codeInsight.controlFlow.PhpControlFlowUtil) 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) List(java.util.List) PsiElement(com.intellij.psi.PsiElement) ProblemHighlightType(com.intellij.codeInspection.ProblemHighlightType) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) NotNull(org.jetbrains.annotations.NotNull) PsiElementVisitor(com.intellij.psi.PsiElementVisitor) ProblemsHolder(com.intellij.codeInspection.ProblemsHolder) PhpAccessVariableInstruction(com.jetbrains.php.codeInsight.controlFlow.instructions.PhpAccessVariableInstruction) javax.swing(javax.swing) PhpEntryPointInstruction(com.jetbrains.php.codeInsight.controlFlow.instructions.PhpEntryPointInstruction) 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) HashSet(java.util.HashSet) PhpAccessVariableInstruction(com.jetbrains.php.codeInsight.controlFlow.instructions.PhpAccessVariableInstruction) PhpIndex(com.jetbrains.php.PhpIndex) NotNull(org.jetbrains.annotations.NotNull)

Example 49 with PhpType

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

Example 50 with PhpType

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

the class RenderUtil method getViewArguments.

@NotNull
public static Map<String, PhpType> getViewArguments(MethodReference reference) {
    final Map<String, PhpType> result = new LinkedHashMap<>();
    result.put("this", new PhpType.PhpTypeBuilder().add(Yii2SupportSettings.getInstance(reference.getProject()).defaultViewClass).build());
    ParameterList parameterList = reference.getParameterList();
    if (parameterList == null) {
        return result;
    }
    if (parameterList.getParameters().length == 1) {
        return result;
    }
    final PsiElement parameter = parameterList.getParameters()[1];
    if (parameter instanceof ArrayCreationExpression) {
        final ArrayCreationExpression array = (ArrayCreationExpression) parameter;
        for (ArrayHashElement item : array.getHashElements()) {
            PhpPsiElement keyElement = item.getKey();
            String key;
            if (keyElement instanceof StringLiteralExpression) {
                key = ((StringLiteralExpression) keyElement).getContents();
            } else {
                continue;
            }
            PhpType valueType;
            final PhpPsiElement valueElement = item.getValue();
            if (valueElement instanceof PhpExpression) {
                valueType = ((PhpTypedElement) valueElement).getType().global(valueElement.getProject());
            } else {
                continue;
            }
            result.put(key, valueType);
        }
        return result;
    }
    return result;
}
Also used : PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) LinkedHashMap(java.util.LinkedHashMap) 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