Search in sources :

Example 11 with PhpType

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

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

the class GetClassUsageInspector method buildVisitor.

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

        @Override
        public void visitPhpFunctionCall(@NotNull FunctionReference reference) {
            final Project project = holder.getProject();
            if (PhpLanguageLevel.get(project).atLeast(PhpLanguageLevel.PHP710)) {
                final String functionName = reference.getName();
                if (functionName != null && functionName.equals("get_class")) {
                    final PsiElement[] arguments = reference.getParameters();
                    if (arguments.length == 1 && arguments[0] instanceof PhpTypedElement) {
                        final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) arguments[0], project);
                        if (resolved != null) {
                            final boolean hasNull = resolved.filterUnknown().getTypes().stream().anyMatch(t -> Types.getType(t).equals(Types.strNull));
                            if ((hasNull || isNullableParameter(arguments[0])) && !isNullabilityChecked(arguments[0])) {
                                holder.registerProblem(reference, MessagesPresentationUtil.prefixWithEa(message));
                            }
                        }
                    }
                }
            }
        }

        private boolean isNullabilityChecked(@NotNull PsiElement expression) {
            /* workaround for https://youtrack.jetbrains.com/issue/WI-38622 */
            boolean result = false;
            final Function scope = ExpressionSemanticUtil.getScope(expression);
            if (scope != null) {
                final GroupStatement body = ExpressionSemanticUtil.getGroupStatement(scope);
                final List<PsiElement> allUsages = PsiTreeUtil.findChildrenOfType(body, expression.getClass()).stream().filter(e -> OpenapiEquivalenceUtil.areEqual(e, expression)).collect(Collectors.toList());
                for (final PsiElement candidate : allUsages.subList(0, allUsages.indexOf(expression))) {
                    final PsiElement parent = candidate.getParent();
                    if (parent instanceof PhpEmpty || parent instanceof PhpIsset) {
                        result = true;
                    } else if (parent instanceof BinaryExpression) {
                        final BinaryExpression binary = (BinaryExpression) parent;
                        final IElementType operator = binary.getOperationType();
                        if (operator == PhpTokenTypes.kwINSTANCEOF) {
                            result = true;
                        } else if (OpenapiTypesUtil.tsCOMPARE_EQUALITY_OPS.contains(operator)) {
                            final PsiElement second = OpenapiElementsUtil.getSecondOperand(binary, candidate);
                            result = PhpLanguageUtil.isNull(second);
                        }
                    } else if (ExpressionSemanticUtil.isUsedAsLogicalOperand(candidate)) {
                        result = true;
                    }
                    /* break loop when null check being found */
                    if (result) {
                        break;
                    }
                }
                allUsages.clear();
            }
            return result;
        }

        private boolean isNullableParameter(@NotNull PsiElement expression) {
            boolean result = false;
            if (expression instanceof Variable) {
                final Function scope = ExpressionSemanticUtil.getScope(expression);
                if (scope != null) {
                    final String name = ((Variable) expression).getName();
                    result = Arrays.stream(scope.getParameters()).anyMatch(parameter -> name.equals(parameter.getName()) && PhpLanguageUtil.isNull(parameter.getDefaultValue()));
                }
            }
            return result;
        }
    };
}
Also used : Arrays(java.util.Arrays) BasePhpInspection(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpInspection) PhpLanguageLevel(com.kalessil.phpStorm.phpInspectionsEA.openApi.PhpLanguageLevel) com.jetbrains.php.lang.psi.elements(com.jetbrains.php.lang.psi.elements) IElementType(com.intellij.psi.tree.IElementType) PhpTokenTypes(com.jetbrains.php.lang.lexer.PhpTokenTypes) Collectors(java.util.stream.Collectors) 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) Project(com.intellij.openapi.project.Project) 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) IElementType(com.intellij.psi.tree.IElementType) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) Project(com.intellij.openapi.project.Project) PsiElement(com.intellij.psi.PsiElement) NotNull(org.jetbrains.annotations.NotNull)

Example 13 with PhpType

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

the class SubStrUsedAsArrayAccessInspector method buildVisitor.

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

        @Override
        public void visitPhpFunctionCall(@NotNull FunctionReference reference) {
            /* check if it's the target function */
            final String functionName = reference.getName();
            if (functionName != null && functionName.equals("substr")) {
                final PsiElement[] arguments = reference.getParameters();
                if (arguments.length == 3) {
                    final PsiElement length = arguments[2];
                    if (OpenapiTypesUtil.isNumber(length) && length.getText().equals("1")) {
                        final boolean isValidSource = arguments[0] instanceof Variable || arguments[0] instanceof ArrayAccessExpression || arguments[0] instanceof FieldReference;
                        if (isValidSource) {
                            final PhpTypedElement container = (PhpTypedElement) arguments[0];
                            final PhpType resolvedType = OpenapiResolveUtil.resolveType(container, holder.getProject());
                            if (resolvedType != null) {
                                final boolean isValidType = resolvedType.filterUnknown().getTypes().stream().anyMatch(t -> Types.getType(t).equals(Types.strString));
                                if (isValidType) {
                                    final String source = arguments[0].getText();
                                    final String offset = arguments[1].getText();
                                    final String replacement = offset.startsWith("-") ? String.format("%s[strlen(%s) %s]", source, source, offset.replaceFirst("-", "- ")) : String.format("%s[%s]", source, offset);
                                    holder.registerProblem(reference, String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), replacement), new TheLocalFix(replacement));
                                }
                            }
                        }
                    }
                }
            }
        }
    };
}
Also used : 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 14 with PhpType

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

the class ParameterDefaultValueIsNotNullInspector method buildVisitor.

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

        @Override
        public void visitPhpMethod(@NotNull Method method) {
            this.analyze(method);
        }

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

        private void analyze(@NotNull Function function) {
            final Parameter[] arguments = function.getParameters();
            if (arguments.length > 0) {
                /* collect violations */
                final List<Parameter> violations = new ArrayList<>();
                for (final Parameter argument : arguments) {
                    final PsiElement defaultValue = argument.getDefaultValue();
                    if (defaultValue != null && !PhpLanguageUtil.isNull(defaultValue)) {
                        /* false-positives: null can not be used due to implicit type hints */
                        final PhpType declared = OpenapiResolveUtil.resolveDeclaredType(argument);
                        if (declared.isEmpty() || declared.getTypes().stream().anyMatch(t -> Types.getType(t).equals(Types.strNull))) {
                            violations.add(argument);
                        }
                    }
                }
                if (!violations.isEmpty()) {
                    /* false-positives: methods overrides, so violation should be addressed in the parent */
                    if (function instanceof Method) {
                        final PhpClass clazz = ((Method) function).getContainingClass();
                        if (clazz != null) {
                            final PhpClass parent = OpenapiResolveUtil.resolveSuperClass(clazz);
                            if (parent != null) {
                                final Method parentMethod = OpenapiResolveUtil.resolveMethod(parent, function.getName());
                                if (parentMethod != null && !parentMethod.getAccess().isPrivate()) {
                                    violations.clear();
                                    return;
                                }
                            }
                        }
                    }
                    /* report violations */
                    violations.forEach(param -> holder.registerProblem(param, MessagesPresentationUtil.prefixWithEa(message)));
                    violations.clear();
                }
            }
        }
    };
}
Also used : PhpClass(com.jetbrains.php.lang.psi.elements.PhpClass) BasePhpInspection(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpInspection) Types(com.kalessil.phpStorm.phpInspectionsEA.utils.Types) PhpLanguageUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.PhpLanguageUtil) Function(com.jetbrains.php.lang.psi.elements.Function) Method(com.jetbrains.php.lang.psi.elements.Method) ArrayList(java.util.ArrayList) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) List(java.util.List) OpenapiResolveUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.OpenapiResolveUtil) MessagesPresentationUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.MessagesPresentationUtil) PsiElement(com.intellij.psi.PsiElement) Parameter(com.jetbrains.php.lang.psi.elements.Parameter) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) NotNull(org.jetbrains.annotations.NotNull) PsiElementVisitor(com.intellij.psi.PsiElementVisitor) ProblemsHolder(com.intellij.codeInspection.ProblemsHolder) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) Function(com.jetbrains.php.lang.psi.elements.Function) PhpClass(com.jetbrains.php.lang.psi.elements.PhpClass) ArrayList(java.util.ArrayList) Parameter(com.jetbrains.php.lang.psi.elements.Parameter) 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 15 with PhpType

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

the class ProperNullCoalescingOperatorUsageInspector method buildVisitor.

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

        @Override
        public void visitPhpBinaryExpression(@NotNull BinaryExpression binary) {
            if (binary.getOperationType() == PhpTokenTypes.opCOALESCE && !this.isPartOfCoalesce(binary) && !this.isTypeCasted(binary)) {
                final PsiElement left = binary.getLeftOperand();
                final PsiElement right = binary.getRightOperand();
                if (left != null && right != null) {
                    /* case: `call() ?? null` */
                    if (PhpLanguageUtil.isNull(right)) {
                        if (left instanceof FunctionReference) {
                            holder.registerProblem(binary, String.format(MessagesPresentationUtil.prefixWithEa(messageSimplify), left.getText()), new UseLeftOperandFix(left.getText()));
                        }
                        return;
                    }
                    /* case: `returns_string_or_null() ?? []` */
                    if (ANALYZE_TYPES && left instanceof PhpTypedElement && right instanceof PhpTypedElement) {
                        final Function scope = ExpressionSemanticUtil.getScope(binary);
                        if (scope != null) {
                            final Set<String> leftTypes = this.resolve((PhpTypedElement) left);
                            if (leftTypes != null && !leftTypes.isEmpty()) {
                                final Set<String> rightTypes = this.resolve((PhpTypedElement) right);
                                if (rightTypes != null && !rightTypes.isEmpty()) {
                                    final boolean complimentary = ALLOW_OVERLAPPING_TYPES ? rightTypes.stream().anyMatch(leftTypes::contains) : rightTypes.containsAll(leftTypes);
                                    if (!complimentary && !this.areRelated(rightTypes, leftTypes)) {
                                        holder.registerProblem(binary, String.format(MessagesPresentationUtil.prefixWithEa(messageMismatch), leftTypes.toString(), rightTypes.toString()));
                                    }
                                    rightTypes.clear();
                                }
                                leftTypes.clear();
                            }
                        }
                    }
                }
            }
        }

        private boolean isTypeCasted(@NotNull BinaryExpression binary) {
            final PsiElement parent = binary.getParent();
            if (parent instanceof ParenthesizedExpression) {
                final PsiElement grandParent = parent.getParent();
                if (grandParent instanceof UnaryExpression) {
                    final PsiElement operator = ((UnaryExpression) grandParent).getOperation();
                    return operator != null && PhpTokenTypes.tsCAST_OPS.contains(operator.getNode().getElementType());
                }
            }
            return false;
        }

        private boolean isPartOfCoalesce(@NotNull BinaryExpression binary) {
            final PsiElement parent = binary.getParent();
            return parent instanceof BinaryExpression && ((BinaryExpression) parent).getOperationType() == PhpTokenTypes.opCOALESCE;
        }

        private boolean areRelated(@NotNull Set<String> rightTypes, @NotNull Set<String> leftTypes) {
            final Set<PhpClass> left = this.extractClasses(leftTypes);
            if (!left.isEmpty()) {
                final Set<PhpClass> right = this.extractClasses(rightTypes);
                if (!right.isEmpty() && left.stream().anyMatch(right::contains)) {
                    left.clear();
                    right.clear();
                    return true;
                }
                left.clear();
            }
            return false;
        }

        private HashSet<PhpClass> extractClasses(@NotNull Set<String> types) {
            final HashSet<PhpClass> classes = new HashSet<>();
            final PhpIndex index = PhpIndex.getInstance(holder.getProject());
            types.stream().filter(t -> t.startsWith("\\")).forEach(t -> OpenapiResolveUtil.resolveClassesAndInterfacesByFQN(t, index).forEach(c -> classes.addAll(InterfacesExtractUtil.getCrawlInheritanceTree(c, true))));
            return classes;
        }

        @Nullable
        private Set<String> resolve(@NotNull PhpTypedElement subject) {
            final PhpType type = OpenapiResolveUtil.resolveType(subject, holder.getProject());
            if (type != null && !type.hasUnknown()) {
                final Set<String> types = type.getTypes().stream().map(Types::getType).collect(Collectors.toSet());
                if (!types.isEmpty() && !types.contains(Types.strMixed) && !types.contains(Types.strObject)) {
                    types.remove(Types.strStatic);
                    types.remove(Types.strNull);
                    return types;
                }
                types.clear();
            }
            return null;
        }
    };
}
Also used : 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) PhpTokenTypes(com.jetbrains.php.lang.lexer.PhpTokenTypes) UseSuggestedReplacementFixer(com.kalessil.phpStorm.phpInspectionsEA.fixers.UseSuggestedReplacementFixer) Set(java.util.Set) PhpIndex(com.jetbrains.php.PhpIndex) OptionsComponent(com.kalessil.phpStorm.phpInspectionsEA.options.OptionsComponent) Collectors(java.util.stream.Collectors) HashSet(java.util.HashSet) Nullable(org.jetbrains.annotations.Nullable) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) com.kalessil.phpStorm.phpInspectionsEA.utils(com.kalessil.phpStorm.phpInspectionsEA.utils) PsiElement(com.intellij.psi.PsiElement) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) NotNull(org.jetbrains.annotations.NotNull) PsiElementVisitor(com.intellij.psi.PsiElementVisitor) ProblemsHolder(com.intellij.codeInspection.ProblemsHolder) javax.swing(javax.swing) Set(java.util.Set) HashSet(java.util.HashSet) PhpIndex(com.jetbrains.php.PhpIndex) 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) 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