Search in sources :

Example 1 with PhpDocRef

use of com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocRef in project phpinspectionsea by kalessil.

the class PhpUnitTestsInspector method buildVisitor.

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

        @Override
        public void visitPhpMethod(@NotNull Method method) {
            final PhpClass clazz = method.getContainingClass();
            final PsiElement nameNode = NamedElementUtil.getNameIdentifier(method);
            final PhpDocComment phpDoc = method.getDocComment();
            if (null == clazz || null == nameNode || phpDoc == null) {
                return;
            }
            final boolean isMethodNamedAsTest = method.getName().startsWith("test");
            for (final PhpDocTag tag : PsiTreeUtil.findChildrenOfType(phpDoc, PhpDocTag.class)) {
                final String tagName = tag.getName();
                if (tagName.equals("@dataProvider")) {
                    final PsiElement candidate = tag.getFirstPsiChild();
                    if (candidate instanceof PhpDocRef && this.isAnnotation(tag)) {
                        final List<PsiReference> references = Arrays.asList(candidate.getReferences());
                        if (!references.isEmpty()) {
                            Collections.reverse(references);
                            final PsiElement resolved = OpenapiResolveUtil.resolveReference(references.get(0));
                            if (resolved instanceof Method) {
                                if (SUGGEST_TO_USE_NAMED_DATASETS && !((Method) resolved).isAbstract()) {
                                    final GroupStatement body = ExpressionSemanticUtil.getGroupStatement(resolved);
                                    final PsiElement last = body == null ? null : ExpressionSemanticUtil.getLastStatement(body);
                                    if (last instanceof PhpReturn) {
                                        final PsiElement value = ExpressionSemanticUtil.getReturnValue((PhpReturn) last);
                                        if (value instanceof ArrayCreationExpression) {
                                            final PsiElement firstChild = ((ArrayCreationExpression) value).getFirstPsiChild();
                                            boolean isNamedDataset = firstChild == null;
                                            if (firstChild instanceof ArrayHashElement) {
                                                final PsiElement key = ((ArrayHashElement) firstChild).getKey();
                                                isNamedDataset = key instanceof StringLiteralExpression;
                                            }
                                            if (!isNamedDataset) {
                                                holder.registerProblem(nameNode, MessagesPresentationUtil.prefixWithEa(messageNamedProvider));
                                            }
                                        }
                                    }
                                }
                            } else {
                                holder.registerProblem(nameNode, MessagesPresentationUtil.prefixWithEa(messageDataProvider), ProblemHighlightType.GENERIC_ERROR);
                            }
                        } else {
                            holder.registerProblem(nameNode, MessagesPresentationUtil.prefixWithEa(messageDataProvider), ProblemHighlightType.GENERIC_ERROR);
                        }
                    }
                } else if (tagName.equals("@depends")) {
                    final PsiElement candidate = tag.getFirstPsiChild();
                    if (candidate instanceof PhpDocRef && this.isAnnotation(tag)) {
                        final List<PsiReference> references = Arrays.asList(candidate.getReferences());
                        if (!references.isEmpty()) {
                            Collections.reverse(references);
                            final PsiElement resolved = OpenapiResolveUtil.resolveReference(references.get(0));
                            if (resolved instanceof Method) {
                                final Method dependency = (Method) resolved;
                                if (!dependency.getName().startsWith("test")) {
                                    final PhpDocComment docBlock = dependency.getDocComment();
                                    if (docBlock == null || docBlock.getTagElementsByName("@test").length == 0) {
                                        holder.registerProblem(nameNode, MessagesPresentationUtil.prefixWithEa(messageDepends), ProblemHighlightType.GENERIC_ERROR);
                                    }
                                }
                            } else {
                                holder.registerProblem(nameNode, MessagesPresentationUtil.prefixWithEa(messageDepends), ProblemHighlightType.GENERIC_ERROR);
                            }
                        } else {
                            holder.registerProblem(nameNode, MessagesPresentationUtil.prefixWithEa(messageDepends), ProblemHighlightType.GENERIC_ERROR);
                        }
                    }
                } else if (tagName.equals("@covers")) {
                    final PsiElement candidate = tag.getFirstPsiChild();
                    if (candidate instanceof PhpDocRef && this.isAnnotation(tag)) {
                        final PhpDocRef referenceNeeded = (PhpDocRef) candidate;
                        final List<PsiReference> references = Arrays.asList(referenceNeeded.getReferences());
                        Collections.reverse(references);
                        /* resolve references, populate information about provided entries */
                        boolean hasCallableReference = false;
                        boolean hasClassReference = false;
                        final String referenceText = referenceNeeded.getText();
                        for (final PsiReference ref : references) {
                            final PsiElement resolved = OpenapiResolveUtil.resolveReference(ref);
                            if (resolved instanceof PhpClass) {
                                hasClassReference = true;
                                hasCallableReference = referenceText.endsWith("::");
                                break;
                            } else if (resolved instanceof Function) {
                                hasCallableReference = true;
                                hasClassReference = resolved instanceof Method;
                                break;
                            }
                        }
                        final boolean callableNeeded = referenceText.contains("::") && !referenceText.contains("::<");
                        if ((callableNeeded && !hasCallableReference) || (!callableNeeded && !hasClassReference)) {
                            holder.registerProblem(nameNode, MessagesPresentationUtil.prefixWithEa(String.format(messageCovers, referenceText)), ProblemHighlightType.GENERIC_ERROR);
                        }
                    }
                } else if (tagName.equals("@test")) {
                    if (isMethodNamedAsTest && this.isAnnotation(tag)) {
                        holder.registerProblem(tag.getFirstChild(), MessagesPresentationUtil.prefixWithEa(messageTest), ProblemHighlightType.LIKE_DEPRECATED, new AmbiguousTestAnnotationLocalFix());
                    }
                }
            }
        }

        private boolean isAnnotation(@NotNull PhpDocTag tag) {
            PsiElement previous = tag.getPrevSibling();
            previous = previous instanceof PsiWhiteSpace ? previous.getPrevSibling() : previous;
            final IElementType start = previous == null ? null : previous.getNode().getElementType();
            return start == PhpTokenTypes.DOC_COMMENT_START || start == PhpTokenTypes.DOC_LEADING_ASTERISK;
        }

        @Override
        public void visitPhpMethodReference(@NotNull MethodReference reference) {
            final String methodName = reference.getName();
            if (methodName != null) {
                if (methodName.startsWith("assert") && !methodName.equals("assert")) {
                    final List<BooleanSupplier> callbacks = new ArrayList<>();
                    callbacks.add(() -> AssertBoolInvertedStrategy.apply(methodName, reference, holder));
                    callbacks.add(() -> AssertBoolOfComparisonStrategy.apply(methodName, reference, holder));
                    if (SUGGEST_TO_USE_ASSERTSAME) {
                        callbacks.add(() -> AssertSameStrategy.apply(methodName, reference, holder));
                    }
                    if (PROMOTE_PHPUNIT_API) {
                        final PhpUnitVersion version = PHP_UNIT_VERSION == null ? PhpUnitVersion.PHPUNIT80 : PHP_UNIT_VERSION;
                        callbacks.add(() -> AssertEmptyStrategy.apply(methodName, reference, holder));
                        callbacks.add(() -> AssertConstantStrategy.apply(methodName, reference, holder));
                        callbacks.add(() -> AssertInternalTypeStrategy.apply(methodName, reference, holder, version));
                        callbacks.add(() -> AssertInstanceOfStrategy.apply(methodName, reference, holder));
                        callbacks.add(() -> AssertResourceExistsStrategy.apply(methodName, reference, holder, version));
                        callbacks.add(() -> AssertCountStrategy.apply(methodName, reference, holder));
                        callbacks.add(() -> AssertContainsStrategy.apply(methodName, reference, holder, version));
                        callbacks.add(() -> AssertRegexStrategy.apply(methodName, reference, holder));
                        /* AssertFileEqualsStrategy and AssertStringEqualsFileStrategy order is important */
                        callbacks.add(() -> AssertFileEqualsStrategy.apply(methodName, reference, holder));
                        callbacks.add(() -> AssertStringEqualsFileStrategy.apply(methodName, reference, holder));
                    }
                    for (final BooleanSupplier callback : callbacks) {
                        if (callback.getAsBoolean()) {
                            break;
                        }
                    }
                    callbacks.clear();
                } else if (methodName.equals("expects")) {
                    if (PROMOTE_MOCKING_ONCE) {
                        ExpectsOnceStrategy.apply(methodName, reference, holder);
                    }
                } else if (methodName.equals("will")) {
                    if (PROMOTE_MOCKING_WILL_RETURN) {
                        WillReturnStrategy.apply(methodName, reference, holder);
                    }
                }
            }
        }
    };
}
Also used : ArrayList(java.util.ArrayList) NotNull(org.jetbrains.annotations.NotNull) PhpDocTag(com.jetbrains.php.lang.documentation.phpdoc.psi.tags.PhpDocTag) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) PhpDocRef(com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocRef) ArrayList(java.util.ArrayList) List(java.util.List) BooleanSupplier(java.util.function.BooleanSupplier) PsiElement(com.intellij.psi.PsiElement) LeafPsiElement(com.intellij.psi.impl.source.tree.LeafPsiElement) PsiReference(com.intellij.psi.PsiReference) IElementType(com.intellij.psi.tree.IElementType) PhpDocComment(com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocComment) PsiWhiteSpace(com.intellij.psi.PsiWhiteSpace) NotNull(org.jetbrains.annotations.NotNull)

Aggregations

PsiElement (com.intellij.psi.PsiElement)1 PsiReference (com.intellij.psi.PsiReference)1 PsiWhiteSpace (com.intellij.psi.PsiWhiteSpace)1 LeafPsiElement (com.intellij.psi.impl.source.tree.LeafPsiElement)1 IElementType (com.intellij.psi.tree.IElementType)1 PhpDocComment (com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocComment)1 PhpDocRef (com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocRef)1 PhpDocTag (com.jetbrains.php.lang.documentation.phpdoc.psi.tags.PhpDocTag)1 BasePhpElementVisitor (com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor)1 ArrayList (java.util.ArrayList)1 List (java.util.List)1 BooleanSupplier (java.util.function.BooleanSupplier)1 NotNull (org.jetbrains.annotations.NotNull)1