Search in sources :

Example 21 with PhpClass

use of com.jetbrains.php.lang.psi.elements.PhpClass 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 22 with PhpClass

use of com.jetbrains.php.lang.psi.elements.PhpClass 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)

Example 23 with PhpClass

use of com.jetbrains.php.lang.psi.elements.PhpClass in project phpinspectionsea by kalessil.

the class InstanceOfTraitStrategy method apply.

public static boolean apply(@NotNull BinaryExpression expression, @NotNull ProblemsHolder holder) {
    /* general structure expectations */
    if (expression.getOperationType() != PhpTokenTypes.kwINSTANCEOF) {
        return false;
    }
    final PsiElement right = expression.getRightOperand();
    if (!(right instanceof ClassReference) && !(right instanceof ClassConstantReference)) {
        return false;
    }
    /* $this, self, static are referencing to host classes, skip the case */
    if (lateBindingSymbols.contains(right.getText())) {
        return false;
    }
    /* getting class from invariant constructs  */
    PsiElement resolved = null;
    if (right instanceof ClassReference) {
        resolved = OpenapiResolveUtil.resolveReference((ClassReference) right);
    }
    if (right instanceof ClassConstantReference) {
        final ClassConstantReference ref = (ClassConstantReference) right;
        final PsiElement classReference = ref.getClassReference();
        final String constantName = ref.getName();
        if (null != constantName && constantName.equals("class") && classReference instanceof ClassReference) {
            resolved = OpenapiResolveUtil.resolveReference((ClassReference) classReference);
        }
    }
    /* analysis itself */
    if (resolved instanceof PhpClass && ((PhpClass) resolved).isTrait()) {
        holder.registerProblem(expression, MessagesPresentationUtil.prefixWithEa(message));
        return true;
    }
    return false;
}
Also used : PhpClass(com.jetbrains.php.lang.psi.elements.PhpClass) ClassReference(com.jetbrains.php.lang.psi.elements.ClassReference) PsiElement(com.intellij.psi.PsiElement) ClassConstantReference(com.jetbrains.php.lang.psi.elements.ClassConstantReference)

Example 24 with PhpClass

use of com.jetbrains.php.lang.psi.elements.PhpClass in project phpinspectionsea by kalessil.

the class ClassReImplementsParentInterfaceInspector method buildVisitor.

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

        @Override
        public void visitPhpClass(@NotNull PhpClass clazz) {
            final List<ClassReference> implemented = clazz.getImplementsList().getReferenceElements();
            if (!implemented.isEmpty()) {
                /* resolve own interfaces an maintain relation to original element */
                final Map<PsiElement, PhpClass> ownInterfaces = new LinkedHashMap<>(implemented.size());
                for (final ClassReference reference : implemented) {
                    final PsiElement resolved = OpenapiResolveUtil.resolveReference(reference);
                    if (resolved instanceof PhpClass) {
                        ownInterfaces.put(reference, (PhpClass) resolved);
                    }
                }
                implemented.clear();
                if (!ownInterfaces.isEmpty()) {
                    /* Case: indirect declaration duplication (parent already implements) */
                    final PhpClass parent = OpenapiResolveUtil.resolveSuperClass(clazz);
                    if (parent != null) {
                        final Set<PhpClass> inherited = InterfacesExtractUtil.getCrawlInheritanceTree(parent, false);
                        if (!inherited.isEmpty()) {
                            final Set<PsiElement> processed = new HashSet<>();
                            for (final Map.Entry<PsiElement, PhpClass> entry : ownInterfaces.entrySet()) {
                                final PhpClass ownInterface = entry.getValue();
                                if (inherited.contains(ownInterface) && processed.add(entry.getKey())) {
                                    holder.registerProblem(entry.getKey(), String.format(MessagesPresentationUtil.prefixWithEa(patternIndirectDuplication), ownInterface.getFQN(), parent.getFQN()), new TheLocalFix());
                                }
                            }
                            processed.clear();
                            inherited.clear();
                        }
                    }
                    ownInterfaces.clear();
                }
            }
        }
    };
}
Also used : PhpClass(com.jetbrains.php.lang.psi.elements.PhpClass) NotNull(org.jetbrains.annotations.NotNull) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) ClassReference(com.jetbrains.php.lang.psi.elements.ClassReference) PsiElement(com.intellij.psi.PsiElement) NotNull(org.jetbrains.annotations.NotNull)

Example 25 with PhpClass

use of com.jetbrains.php.lang.psi.elements.PhpClass in project phpinspectionsea by kalessil.

the class TypeUnsafeComparisonInspector method buildVisitor.

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

        @Override
        public void visitPhpBinaryExpression(@NotNull BinaryExpression expression) {
            final IElementType operator = expression.getOperationType();
            if (operator == PhpTokenTypes.opEQUAL || operator == PhpTokenTypes.opNOT_EQUAL) {
                this.analyze(expression, operator);
            }
        }

        private void analyze(@NotNull final BinaryExpression subject, @NotNull final IElementType operator) {
            final String targetOperator = PhpTokenTypes.opEQUAL == operator ? "===" : "!==";
            final PsiElement left = subject.getLeftOperand();
            final PsiElement right = subject.getRightOperand();
            if (right instanceof StringLiteralExpression || left instanceof StringLiteralExpression) {
                final PsiElement nonStringOperand;
                final String literalValue;
                if (right instanceof StringLiteralExpression) {
                    literalValue = ((StringLiteralExpression) right).getContents();
                    nonStringOperand = ExpressionSemanticUtil.getExpressionTroughParenthesis(left);
                } else {
                    literalValue = ((StringLiteralExpression) left).getContents();
                    nonStringOperand = ExpressionSemanticUtil.getExpressionTroughParenthesis(right);
                }
                /* resolve 2nd operand type, if class ensure __toString is implemented */
                if (ClassInStringContextStrategy.apply(nonStringOperand, holder, subject, messageToStringMethodMissing)) {
                    /* TODO: weak warning regarding under-the-hood string casting */
                    return;
                }
                /* string literal is numeric or empty, no strict compare possible */
                if (!literalValue.isEmpty() && !literalValue.matches("^[+-]?[0-9]*\\.?[0-9]+$")) {
                    holder.registerProblem(subject, String.format(MessagesPresentationUtil.prefixWithEa(patternCompareStrict), targetOperator), new CompareStrictFix(targetOperator));
                    return;
                }
            }
            /* some objects supporting direct comparison: search for .compare_objects in PHP sources */
            if (left != null && right != null) {
                final boolean isComparableObject = this.isComparableObject(left) || this.isComparableObject(right);
                if (!isComparableObject) {
                    holder.registerProblem(subject, String.format(MessagesPresentationUtil.prefixWithEa(patternHarden), targetOperator), ProblemHighlightType.WEAK_WARNING);
                }
            }
        }

        private boolean isComparableObject(@NotNull PsiElement operand) {
            if (operand instanceof PhpTypedElement) {
                final Project project = holder.getProject();
                final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) operand, project);
                if (resolved != null) {
                    final PhpIndex index = PhpIndex.getInstance(project);
                    final Set<PhpClass> classes = new HashSet<>();
                    resolved.filterUnknown().getTypes().stream().filter(t -> t.charAt(0) == '\\').forEach(t -> classes.addAll(OpenapiResolveUtil.resolveClassesAndInterfacesByFQN(Types.getType(t), index)));
                    for (final PhpClass clazz : classes) {
                        final boolean hasAny = comparable.contains(clazz.getFQN()) || InterfacesExtractUtil.getCrawlInheritanceTree(clazz, true).stream().anyMatch(c -> comparable.contains(c.getFQN()));
                        if (hasAny) {
                            classes.clear();
                            return true;
                        }
                    }
                    classes.clear();
                }
            }
            return false;
        }
    };
}
Also used : IElementType(com.intellij.psi.tree.IElementType) PhpTokenTypes(com.jetbrains.php.lang.lexer.PhpTokenTypes) PhpIndex(com.jetbrains.php.PhpIndex) PhpTypedElement(com.jetbrains.php.lang.psi.elements.PhpTypedElement) HashSet(java.util.HashSet) ClassInStringContextStrategy(com.kalessil.phpStorm.phpInspectionsEA.utils.strategy.ClassInStringContextStrategy) BinaryExpression(com.jetbrains.php.lang.psi.elements.BinaryExpression) ProblemDescriptor(com.intellij.codeInspection.ProblemDescriptor) MessagesPresentationUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.MessagesPresentationUtil) PsiElement(com.intellij.psi.PsiElement) Project(com.intellij.openapi.project.Project) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) LocalQuickFix(com.intellij.codeInspection.LocalQuickFix) PsiElementVisitor(com.intellij.psi.PsiElementVisitor) ProblemsHolder(com.intellij.codeInspection.ProblemsHolder) PhpPsiElementFactory(com.jetbrains.php.lang.psi.PhpPsiElementFactory) PhpClass(com.jetbrains.php.lang.psi.elements.PhpClass) BasePhpInspection(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpInspection) ExpressionSemanticUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.ExpressionSemanticUtil) Types(com.kalessil.phpStorm.phpInspectionsEA.utils.Types) InterfacesExtractUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.hierarhy.InterfacesExtractUtil) LeafPsiElement(com.intellij.psi.impl.source.tree.LeafPsiElement) Set(java.util.Set) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) OpenapiResolveUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.OpenapiResolveUtil) ProblemHighlightType(com.intellij.codeInspection.ProblemHighlightType) StringLiteralExpression(com.jetbrains.php.lang.psi.elements.StringLiteralExpression) NotNull(org.jetbrains.annotations.NotNull) StringLiteralExpression(com.jetbrains.php.lang.psi.elements.StringLiteralExpression) PhpIndex(com.jetbrains.php.PhpIndex) PhpClass(com.jetbrains.php.lang.psi.elements.PhpClass) 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) BinaryExpression(com.jetbrains.php.lang.psi.elements.BinaryExpression) PhpTypedElement(com.jetbrains.php.lang.psi.elements.PhpTypedElement) PsiElement(com.intellij.psi.PsiElement) LeafPsiElement(com.intellij.psi.impl.source.tree.LeafPsiElement) HashSet(java.util.HashSet) NotNull(org.jetbrains.annotations.NotNull)

Aggregations

PhpClass (com.jetbrains.php.lang.psi.elements.PhpClass)35 PsiElement (com.intellij.psi.PsiElement)26 NotNull (org.jetbrains.annotations.NotNull)19 BasePhpElementVisitor (com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor)14 Method (com.jetbrains.php.lang.psi.elements.Method)11 PhpIndex (com.jetbrains.php.PhpIndex)8 ProblemsHolder (com.intellij.codeInspection.ProblemsHolder)7 PhpType (com.jetbrains.php.lang.psi.resolve.types.PhpType)7 MessagesPresentationUtil (com.kalessil.phpStorm.phpInspectionsEA.utils.MessagesPresentationUtil)6 OpenapiResolveUtil (com.kalessil.phpStorm.phpInspectionsEA.utils.OpenapiResolveUtil)6 PsiElementVisitor (com.intellij.psi.PsiElementVisitor)5 Field (com.jetbrains.php.lang.psi.elements.Field)5 BasePhpInspection (com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpInspection)5 HashSet (java.util.HashSet)5 Project (com.intellij.openapi.project.Project)4 ClassReference (com.jetbrains.php.lang.psi.elements.ClassReference)4 ArrayList (java.util.ArrayList)4 List (java.util.List)4 ProblemHighlightType (com.intellij.codeInspection.ProblemHighlightType)3 Editor (com.intellij.openapi.editor.Editor)3