Search in sources :

Example 91 with BasePhpElementVisitor

use of com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor in project phpinspectionsea by kalessil.

the class CallableMethodValidityInspector 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 && functionName.equals("is_callable")) {
                final PsiElement[] arguments = reference.getParameters();
                if (arguments.length == 1) {
                    final Set<PsiElement> values = PossibleValuesDiscoveryUtil.discover(arguments[0]);
                    final PsiElement callable = values.size() == 1 ? values.iterator().next() : null;
                    if (callable != null && this.isTarget(callable)) {
                        final PsiReference resolver = this.buildResolver(callable);
                        if (resolver != null) {
                            this.analyzeValidity(resolver.resolve(), arguments[0], callable);
                        }
                    }
                    values.clear();
                }
            }
        }

        @Nullable
        private PsiReference buildResolver(@NotNull PsiElement callable) {
            PsiReference result = null;
            final PhpCallbackFunctionUtil.PhpCallbackInfoHolder callback = PhpCallbackFunctionUtil.createCallback(callable);
            if (callback instanceof PhpCallbackFunctionUtil.PhpMemberCallbackInfoHolder) {
                PsiElement classReference = ((PhpCallbackFunctionUtil.PhpMemberCallbackInfoHolder) callback).getClassElement();
                result = PhpCallbackReferenceBase.createMemberReference(classReference, callback.getCallbackElement(), true);
            }
            return result;
        }

        private boolean isTarget(@NotNull PsiElement callback) {
            boolean result = callback instanceof StringLiteralExpression;
            if (!result && callback instanceof ArrayCreationExpression) {
                result = callback.getChildren().length == 2;
            }
            return result;
        }

        private void analyzeValidity(@Nullable PsiElement element, @NotNull PsiElement target, @NotNull PsiElement callable) {
            if (element instanceof Method) {
                final Method method = (Method) element;
                if (!method.getAccess().isPublic()) {
                    holder.registerProblem(target, MessagesPresentationUtil.prefixWithEa(patternNotPublic.replace("%m%", method.getName())));
                }
                boolean needStatic = false;
                if (callable instanceof StringLiteralExpression && !method.isStatic()) {
                    needStatic = true;
                }
                if (callable instanceof ArrayCreationExpression && !method.isStatic()) {
                    final PsiElement classCandidate = callable.getChildren()[0].getFirstChild();
                    /* try resolving the expression */
                    if (classCandidate instanceof PhpTypedElement) {
                        final PhpTypedElement candidate = (PhpTypedElement) classCandidate;
                        final Project project = holder.getProject();
                        for (final String type : candidate.getType().global(project).filterUnknown().getTypes()) {
                            final String resolvedType = Types.getType(type);
                            if (resolvedType.equals(Types.strString) || resolvedType.equals(Types.strCallable)) {
                                needStatic = true;
                                break;
                            }
                        }
                    }
                    /* older PS compatibility: recognize ::class properly */
                    if (!needStatic && classCandidate instanceof ClassConstantReference) {
                        final String constantName = ((ClassConstantReference) classCandidate).getName();
                        needStatic = null != constantName && constantName.equals("class");
                    }
                }
                if (needStatic) {
                    holder.registerProblem(target, MessagesPresentationUtil.prefixWithEa(patternNotStatic.replace("%m%", method.getName())));
                }
            }
        }
    };
}
Also used : PhpCallbackFunctionUtil(com.jetbrains.php.lang.PhpCallbackFunctionUtil) PsiReference(com.intellij.psi.PsiReference) NotNull(org.jetbrains.annotations.NotNull) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) Project(com.intellij.openapi.project.Project) PsiElement(com.intellij.psi.PsiElement) Nullable(org.jetbrains.annotations.Nullable) NotNull(org.jetbrains.annotations.NotNull)

Example 92 with BasePhpElementVisitor

use of com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor in project phpinspectionsea by kalessil.

the class UnserializeExploitsInspector 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 && functionName.equals("unserialize")) {
                final boolean supportsOptions = PhpLanguageLevel.get(holder.getProject()).atLeast(PhpLanguageLevel.PHP700);
                final PsiElement[] arguments = reference.getParameters();
                if (arguments.length == 1 && !this.isTestContext(reference)) {
                    /* pattern: use 2nd argument since PHP7 */
                    if (supportsOptions) {
                        holder.registerProblem(reference, MessagesPresentationUtil.prefixWithEa(messageUseSecondArgument));
                    }
                    /* pattern: exploitable calls */
                    this.inspectExploits(holder, arguments[0]);
                } else if (arguments.length == 2 && !this.isTestContext(reference)) {
                    if (arguments[1] instanceof ArrayCreationExpression) {
                        final boolean hasClassesListed = arguments[1].getChildren().length > 0;
                        if (!hasClassesListed) {
                            holder.registerProblem(reference, MessagesPresentationUtil.prefixWithEa(messageUseSecondArgument));
                        }
                    } else if (PhpLanguageUtil.isTrue(arguments[1])) {
                        holder.registerProblem(reference, MessagesPresentationUtil.prefixWithEa(messageUseSecondArgument));
                    }
                }
            }
        }

        private void inspectExploits(@NotNull ProblemsHolder holder, @NotNull PsiElement argument) {
            final Set<PsiElement> values = PossibleValuesDiscoveryUtil.discover(argument);
            if (!values.isEmpty()) {
                final List<String> reporting = new ArrayList<>();
                for (PsiElement value : values) {
                    if (OpenapiTypesUtil.isFunctionReference(value)) {
                        final FunctionReference call = (FunctionReference) value;
                        final String functionName = call.getName();
                        if (functionName != null && untrustedFunctions.contains(functionName)) {
                            reporting.add(functionName + "(...)");
                        }
                        continue;
                    }
                    /* extract array access variable */
                    if (value instanceof ArrayAccessExpression) {
                        PsiElement container = value;
                        while (container instanceof ArrayAccessExpression) {
                            container = ((ArrayAccessExpression) container).getValue();
                        }
                        if (container instanceof Variable) {
                            value = container;
                        }
                    }
                    if (value instanceof Variable && untrustedVars.contains(((Variable) value).getName())) {
                        reporting.add(value.getText());
                    // continue
                    }
                /* other expressions are not supported currently */
                }
                /* got something for reporting */
                if (!reporting.isEmpty()) {
                    /* sort reporting list to produce testable results */
                    Collections.sort(reporting);
                    holder.registerProblem(argument, MessagesPresentationUtil.prefixWithEa(messagePattern.replace("%e%", String.join(", ", reporting))), ProblemHighlightType.GENERIC_ERROR);
                    reporting.clear();
                }
            }
            values.clear();
        }
    };
}
Also used : Variable(com.jetbrains.php.lang.psi.elements.Variable) ArrayCreationExpression(com.jetbrains.php.lang.psi.elements.ArrayCreationExpression) NotNull(org.jetbrains.annotations.NotNull) ProblemsHolder(com.intellij.codeInspection.ProblemsHolder) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) FunctionReference(com.jetbrains.php.lang.psi.elements.FunctionReference) ArrayAccessExpression(com.jetbrains.php.lang.psi.elements.ArrayAccessExpression) PsiElement(com.intellij.psi.PsiElement) NotNull(org.jetbrains.annotations.NotNull)

Example 93 with BasePhpElementVisitor

use of com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor in project phpinspectionsea by kalessil.

the class OnlyWritesOnParameterInspector method buildVisitor.

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

        @Override
        public void visitPhpMethod(@NotNull Method method) {
            if (!method.isAbstract()) {
                this.visitPhpFunction(method);
            }
        }

        @Override
        public void visitPhpFunction(@NotNull Function function) {
            Arrays.stream(function.getParameters()).filter(parameter -> !parameter.getName().isEmpty() && !parameter.isPassByRef()).filter(parameter -> {
                final PhpType declaredType = OpenapiResolveUtil.resolveDeclaredType(parameter).filterUnknown().filterNull();
                final boolean isObject = !declaredType.isEmpty() && declaredType.getTypes().stream().anyMatch(t -> {
                    final String type = Types.getType(t);
                    return type.equals(Types.strObject) || type.startsWith("\\");
                });
                return !isObject;
            }).forEach(parameter -> this.analyzeAndReturnUsagesCount(parameter.getName(), function));
            final List<Variable> variables = ExpressionSemanticUtil.getUseListVariables(function);
            if (variables != null) {
                this.checkUseVariables(variables, function);
                variables.clear();
            }
        }

        @Override
        public void visitPhpAssignmentExpression(@NotNull AssignmentExpression assignment) {
            /* because this hook fired e.g. for `.=` assignments (a BC break by PhpStorm) */
            if (OpenapiTypesUtil.isAssignment(assignment)) {
                final PsiElement variable = assignment.getVariable();
                if (variable instanceof Variable) {
                    /* false-positives: predefined and global variables */
                    final String variableName = ((Variable) variable).getName();
                    if (variableName.isEmpty() || ExpressionCostEstimateUtil.predefinedVars.contains(variableName)) {
                        return;
                    }
                    /* filter target contexts: we are supporting only certain of them */
                    final PsiElement parent = assignment.getParent();
                    final boolean isTargetContext = parent instanceof ParenthesizedExpression || parent instanceof ArrayIndex || (parent instanceof BinaryExpression && OpenapiTypesUtil.tsCOMPARE_EQUALITY_OPS.contains(((BinaryExpression) parent).getOperationType())) || OpenapiTypesUtil.isStatementImpl(parent) || OpenapiTypesUtil.isAssignment(parent);
                    if (isTargetContext) {
                        final Function scope = ExpressionSemanticUtil.getScope(assignment);
                        if (scope != null && Arrays.stream(scope.getParameters()).noneMatch(p -> p.getName().equals(variableName))) {
                            final List<Variable> uses = ExpressionSemanticUtil.getUseListVariables(scope);
                            final boolean isUseVariable = uses != null && uses.stream().anyMatch(u -> u.getName().equals(variableName));
                            if (!isUseVariable) {
                                this.analyzeAndReturnUsagesCount(variableName, scope);
                            }
                        }
                    }
                }
            }
        }

        private void checkUseVariables(@NotNull List<Variable> variables, @NotNull Function function) {
            for (final Variable variable : variables) {
                final String parameterName = variable.getName();
                if (!parameterName.isEmpty()) {
                    PsiElement previous = variable.getPrevSibling();
                    if (previous instanceof PsiWhiteSpace) {
                        previous = previous.getPrevSibling();
                    }
                    if (OpenapiTypesUtil.is(previous, PhpTokenTypes.opBIT_AND)) {
                        if (OpenapiControlFlowUtil.getFollowingVariableAccessInstructions(function.getControlFlow().getEntryPoint(), parameterName).isEmpty()) {
                            holder.registerProblem(variable, MessagesPresentationUtil.prefixWithEa(messageUnused), ProblemHighlightType.LIKE_UNUSED_SYMBOL);
                        }
                    } else if (this.analyzeAndReturnUsagesCount(parameterName, function) == 0) {
                        holder.registerProblem(variable, MessagesPresentationUtil.prefixWithEa(messageUnused), ProblemHighlightType.LIKE_UNUSED_SYMBOL);
                    }
                }
            }
        }

        private int analyzeAndReturnUsagesCount(@NotNull String parameterName, @NotNull Function function) {
            final List<PhpAccessVariableInstruction> usages = OpenapiControlFlowUtil.getFollowingVariableAccessInstructions(function.getControlFlow().getEntryPoint(), parameterName);
            if (usages.isEmpty()) {
                return 0;
            }
            final List<PsiElement> targetExpressions = new ArrayList<>();
            boolean isReference = false;
            int intCountReadAccesses = 0;
            int intCountWriteAccesses = 0;
            for (final PhpAccessVariableInstruction instruction : usages) {
                final PsiElement variable = instruction.getAnchor();
                final PsiElement parent = variable.getParent();
                if (parent instanceof ArrayAccessExpression) {
                    /* find out which expression is holder */
                    PsiElement objLastSemanticExpression = variable;
                    PsiElement objTopSemanticExpression = objLastSemanticExpression.getParent();
                    /* TODO: iterator for array access expression */
                    while (objTopSemanticExpression instanceof ArrayAccessExpression) {
                        objLastSemanticExpression = objTopSemanticExpression;
                        objTopSemanticExpression = objTopSemanticExpression.getParent();
                    }
                    /* estimate operation type */
                    if (objTopSemanticExpression instanceof AssignmentExpression && ((AssignmentExpression) objTopSemanticExpression).getVariable() == objLastSemanticExpression) {
                        intCountWriteAccesses++;
                        if (isReference) {
                            /* when modifying the reference it's link READ and linked WRITE semantics */
                            intCountReadAccesses++;
                        } else {
                            /* when modifying non non-reference, register as write only access for reporting */
                            targetExpressions.add(objLastSemanticExpression);
                        }
                        continue;
                    }
                    if (objTopSemanticExpression instanceof UnaryExpression) {
                        final PsiElement operation = ((UnaryExpression) objTopSemanticExpression).getOperation();
                        if (OpenapiTypesUtil.is(operation, PhpTokenTypes.opINCREMENT) || OpenapiTypesUtil.is(operation, PhpTokenTypes.opDECREMENT)) {
                            targetExpressions.add(objLastSemanticExpression);
                            ++intCountWriteAccesses;
                            continue;
                        }
                    }
                    intCountReadAccesses++;
                    continue;
                }
                /* ++/-- operations */
                if (parent instanceof UnaryExpression) {
                    final PsiElement operation = ((UnaryExpression) parent).getOperation();
                    if (OpenapiTypesUtil.is(operation, PhpTokenTypes.opINCREMENT) || OpenapiTypesUtil.is(operation, PhpTokenTypes.opDECREMENT)) {
                        ++intCountWriteAccesses;
                        if (isReference) {
                            /* when modifying the reference it's link READ and linked WRITE semantics */
                            ++intCountReadAccesses;
                        } else {
                            /* when modifying non-reference, register as write only access for reporting */
                            targetExpressions.add(parent);
                        }
                    }
                    if (!OpenapiTypesUtil.isStatementImpl(parent.getParent())) {
                        ++intCountReadAccesses;
                    }
                    continue;
                }
                if (parent instanceof SelfAssignmentExpression) {
                    final SelfAssignmentExpression selfAssignment = (SelfAssignmentExpression) parent;
                    final PsiElement sameVariableCandidate = selfAssignment.getVariable();
                    if (sameVariableCandidate instanceof Variable) {
                        final Variable candidate = (Variable) sameVariableCandidate;
                        if (candidate.getName().equals(parameterName)) {
                            ++intCountWriteAccesses;
                            if (isReference) {
                                /* when modifying the reference it's link READ and linked WRITE semantics */
                                ++intCountReadAccesses;
                            } else {
                                /* when modifying non-reference, register as write only access for reporting */
                                targetExpressions.add(variable);
                            }
                            if (!OpenapiTypesUtil.isStatementImpl(parent.getParent())) {
                                ++intCountReadAccesses;
                            }
                            continue;
                        }
                    }
                }
                /* if variable assigned with reference, we need to preserve this information for correct checks */
                if (parent instanceof AssignmentExpression) {
                    /* ensure variable with the same name being written */
                    final AssignmentExpression referenceAssignmentCandidate = (AssignmentExpression) parent;
                    /* check if the target used as a container */
                    final PsiElement assignmentVariableCandidate = referenceAssignmentCandidate.getVariable();
                    if (assignmentVariableCandidate instanceof Variable) {
                        final Variable candidate = (Variable) assignmentVariableCandidate;
                        if (candidate.getName().equals(parameterName)) {
                            ++intCountWriteAccesses;
                            if (isReference) {
                                /* when modifying the reference it's link READ and linked WRITE semantics */
                                ++intCountReadAccesses;
                            }
                            /* now ensure operation is assignment of reference */
                            if (OpenapiTypesUtil.isAssignmentByReference(referenceAssignmentCandidate)) {
                                isReference = true;
                            }
                            /* false-negative: inline assignment result has been used */
                            if (usages.size() == 2 && usages.get(0).getAnchor() == usages.get(1).getAnchor()) {
                                holder.registerProblem(assignmentVariableCandidate, MessagesPresentationUtil.prefixWithEa(messageUnused), ProblemHighlightType.LIKE_UNUSED_SYMBOL);
                                return 1;
                            }
                            continue;
                        }
                    }
                    /* check if the target used as a value */
                    final PsiElement assignmentValueCandidate = referenceAssignmentCandidate.getValue();
                    if (assignmentValueCandidate instanceof Variable) {
                        final Variable candidate = (Variable) assignmentValueCandidate;
                        if (candidate.getName().equals(parameterName)) {
                            ++intCountReadAccesses;
                            continue;
                        }
                    }
                }
                /* local variables access wrongly reported write in some cases, so rely on custom checks */
                if (parent instanceof ParameterList || parent instanceof PhpUseList || parent instanceof PhpUnset || parent instanceof PhpEmpty || parent instanceof PhpIsset || parent instanceof ForeachStatement) {
                    intCountReadAccesses++;
                    continue;
                }
                /* ok variable usage works well with openapi */
                final PhpAccessInstruction.Access instructionAccess = instruction.getAccess();
                if (instructionAccess.isWrite()) {
                    targetExpressions.add(variable);
                    ++intCountWriteAccesses;
                } else if (instructionAccess.isRead()) {
                    ++intCountReadAccesses;
                }
            }
            if (intCountReadAccesses == 0 && intCountWriteAccesses > 0 && !this.isAnySuppressed(targetExpressions)) {
                final boolean report = IGNORE_INCLUDES || !this.hasIncludes(function);
                if (report) {
                    for (final PsiElement targetExpression : new HashSet<>(targetExpressions)) {
                        holder.registerProblem(targetExpression, MessagesPresentationUtil.prefixWithEa(messageOnlyWrites), ProblemHighlightType.LIKE_UNUSED_SYMBOL);
                    }
                }
            }
            targetExpressions.clear();
            return usages.size();
        }

        private boolean isAnySuppressed(@NotNull List<PsiElement> expressions) {
            for (final PsiElement one : expressions) {
                final PsiElement parent = one.getParent();
                if (parent instanceof AssignmentExpression) {
                    final PsiElement grandParent = parent.getParent();
                    if (OpenapiTypesUtil.isStatementImpl(grandParent)) {
                        final PsiElement previous = ((PhpPsiElement) grandParent).getPrevPsiSibling();
                        if (previous instanceof PhpDocComment) {
                            final String candidate = previous.getText();
                            if (candidate.contains("@noinspection") && candidate.contains(getShortName())) {
                                return true;
                            }
                        }
                    }
                }
            }
            return false;
        }

        private boolean hasIncludes(@NotNull Function function) {
            final GroupStatement body = ExpressionSemanticUtil.getGroupStatement(function);
            if (body != null) {
                return PsiTreeUtil.findChildOfType(body, Include.class) != null;
            }
            return false;
        }
    };
}
Also used : PhpAccessInstruction(com.jetbrains.php.codeInsight.controlFlow.instructions.PhpAccessInstruction) PhpDocComment(com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocComment) Arrays(java.util.Arrays) BasePhpInspection(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpInspection) com.jetbrains.php.lang.psi.elements(com.jetbrains.php.lang.psi.elements) PhpTokenTypes(com.jetbrains.php.lang.lexer.PhpTokenTypes) ExpressionCostEstimateUtil(com.kalessil.phpStorm.phpInspectionsEA.inspectors.ifs.utils.ExpressionCostEstimateUtil) OptionsComponent(com.kalessil.phpStorm.phpInspectionsEA.options.OptionsComponent) ArrayList(java.util.ArrayList) 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) PsiWhiteSpace(com.intellij.psi.PsiWhiteSpace) 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) 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) ArrayList(java.util.ArrayList) List(java.util.List) PhpAccessInstruction(com.jetbrains.php.codeInsight.controlFlow.instructions.PhpAccessInstruction) PsiElement(com.intellij.psi.PsiElement) HashSet(java.util.HashSet) PhpAccessVariableInstruction(com.jetbrains.php.codeInsight.controlFlow.instructions.PhpAccessVariableInstruction) PhpDocComment(com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocComment) PsiWhiteSpace(com.intellij.psi.PsiWhiteSpace) NotNull(org.jetbrains.annotations.NotNull)

Example 94 with BasePhpElementVisitor

use of com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor in project phpinspectionsea by kalessil.

the class ClassOverridesFieldOfSuperClassInspector method buildVisitor.

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

        @Override
        public void visitPhpField(@NotNull Field ownField) {
            /* skip un-explorable and test classes */
            final PhpClass clazz = ownField.getContainingClass();
            if (clazz == null || this.isTestContext(clazz)) {
                return;
            }
            /* skip static, constants and un-processable fields */
            final PsiElement ownFieldNameId = NamedElementUtil.getNameIdentifier(ownField);
            if (null == ownFieldNameId || ownField.isConstant() || ownField.getModifier().isStatic()) {
                return;
            }
            /* ensure field is not defined via annotation */
            if (!(ExpressionSemanticUtil.getBlockScope(ownFieldNameId) instanceof PhpClass)) {
                return;
            }
            /* ensure field doesn't have any user-land annotations */
            final PhpDocTag[] tags = PsiTreeUtil.getChildrenOfType(ownField.getDocComment(), PhpDocTag.class);
            final boolean annotated = tags != null && Arrays.stream(tags).anyMatch(t -> !t.getName().equals(t.getName().toLowerCase()));
            if (annotated) {
                return;
            }
            final PhpClass parent = OpenapiResolveUtil.resolveSuperClass(clazz);
            final String ownFieldName = ownField.getName();
            final Field parentField = parent == null ? null : OpenapiResolveUtil.resolveField(parent, ownFieldName);
            if (parentField != null) {
                final PhpClass parentFieldHolder = parentField.getContainingClass();
                final PsiElement fieldNameNode = NamedElementUtil.getNameIdentifier(ownField);
                if (fieldNameNode != null && parentFieldHolder != null) {
                    /* re-defining private fields with the same name is pretty suspicious itself */
                    if (parentField.getModifier().isPrivate()) {
                        if (REPORT_PRIVATE_REDEFINITION) {
                            holder.registerProblem(fieldNameNode, MessagesPresentationUtil.prefixWithEa(patternProtectedCandidate.replace("%c%", parentFieldHolder.getFQN())), ProblemHighlightType.WEAK_WARNING);
                        }
                        return;
                    }
                    /* report only cases when access level is not changed */
                    if (!ownField.getModifier().getAccess().isWeakerThan(parentField.getModifier().getAccess())) {
                        /* fire common warning */
                        holder.registerProblem(fieldNameNode, MessagesPresentationUtil.prefixWithEa(patternShadows.replace("%p%", ownFieldName).replace("%c%", parentFieldHolder.getFQN())), ProblemHighlightType.WEAK_WARNING);
                    }
                }
            }
        }
    };
}
Also used : PhpDocTag(com.jetbrains.php.lang.documentation.phpdoc.psi.tags.PhpDocTag) Arrays(java.util.Arrays) PhpClass(com.jetbrains.php.lang.psi.elements.PhpClass) BasePhpInspection(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpInspection) ExpressionSemanticUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.ExpressionSemanticUtil) OptionsComponent(com.kalessil.phpStorm.phpInspectionsEA.options.OptionsComponent) PhpDocTag(com.jetbrains.php.lang.documentation.phpdoc.psi.tags.PhpDocTag) PsiTreeUtil(com.intellij.psi.util.PsiTreeUtil) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) OpenapiResolveUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.OpenapiResolveUtil) MessagesPresentationUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.MessagesPresentationUtil) PsiElement(com.intellij.psi.PsiElement) NamedElementUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.NamedElementUtil) ProblemHighlightType(com.intellij.codeInspection.ProblemHighlightType) NotNull(org.jetbrains.annotations.NotNull) PsiElementVisitor(com.intellij.psi.PsiElementVisitor) Field(com.jetbrains.php.lang.psi.elements.Field) ProblemsHolder(com.intellij.codeInspection.ProblemsHolder) javax.swing(javax.swing) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) Field(com.jetbrains.php.lang.psi.elements.Field) PhpClass(com.jetbrains.php.lang.psi.elements.PhpClass) NotNull(org.jetbrains.annotations.NotNull) PsiElement(com.intellij.psi.PsiElement) NotNull(org.jetbrains.annotations.NotNull)

Example 95 with BasePhpElementVisitor

use of com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor in project phpinspectionsea by kalessil.

the class LongInheritanceChainInspector method buildVisitor.

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

        @Override
        public void visitPhpClass(@NotNull PhpClass clazz) {
            final PsiElement psiClassName = NamedElementUtil.getNameIdentifier(clazz);
            final String className = clazz.getName();
            /* skip un-reportable, exception and test classes */
            if (psiClassName == null || className.endsWith("Exception") || this.isTestContext(clazz)) {
                return;
            }
            PhpClass classToCheck = clazz;
            PhpClass parent = OpenapiResolveUtil.resolveSuperClass(classToCheck);
            /* false-positives: abstract class implementation */
            if (null != parent && !classToCheck.isAbstract() && parent.isAbstract()) {
                return;
            }
            int parentsCount = 0;
            /* in source code class CAN extend itself, PS will report it but data structure is incorrect still */
            while (null != parent && clazz != parent) {
                classToCheck = parent;
                parent = OpenapiResolveUtil.resolveSuperClass(classToCheck);
                ++parentsCount;
                if (null != parent) {
                    /* show-stoppers: frameworks god classes */
                    if (showStoppers.contains(parent.getFQN())) {
                        ++parentsCount;
                        break;
                    }
                    /* exceptions named according to DDD, check parents named with exception suffix */
                    if (parent.getName().endsWith("Exception")) {
                        return;
                    }
                }
            }
            if (parentsCount >= COMPLAIN_THRESHOLD && !clazz.isDeprecated()) {
                holder.registerProblem(psiClassName, MessagesPresentationUtil.prefixWithEa(messagePattern.replace("%c%", String.valueOf(parentsCount))), ProblemHighlightType.WEAK_WARNING);
            }
        }
    };
}
Also used : BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) PhpClass(com.jetbrains.php.lang.psi.elements.PhpClass) NotNull(org.jetbrains.annotations.NotNull) PsiElement(com.intellij.psi.PsiElement) NotNull(org.jetbrains.annotations.NotNull)

Aggregations

BasePhpElementVisitor (com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor)169 NotNull (org.jetbrains.annotations.NotNull)169 PsiElement (com.intellij.psi.PsiElement)157 FunctionReference (com.jetbrains.php.lang.psi.elements.FunctionReference)43 ProblemsHolder (com.intellij.codeInspection.ProblemsHolder)40 BasePhpInspection (com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpInspection)39 PsiElementVisitor (com.intellij.psi.PsiElementVisitor)37 PhpType (com.jetbrains.php.lang.psi.resolve.types.PhpType)33 IElementType (com.intellij.psi.tree.IElementType)32 com.jetbrains.php.lang.psi.elements (com.jetbrains.php.lang.psi.elements)29 Project (com.intellij.openapi.project.Project)25 BinaryExpression (com.jetbrains.php.lang.psi.elements.BinaryExpression)25 HashSet (java.util.HashSet)24 PsiTreeUtil (com.intellij.psi.util.PsiTreeUtil)22 MessagesPresentationUtil (com.kalessil.phpStorm.phpInspectionsEA.utils.MessagesPresentationUtil)19 StringLiteralExpression (com.jetbrains.php.lang.psi.elements.StringLiteralExpression)18 ArrayList (java.util.ArrayList)18 Set (java.util.Set)18 Nullable (org.jetbrains.annotations.Nullable)18 PhpTokenTypes (com.jetbrains.php.lang.lexer.PhpTokenTypes)17