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);
}
}
}
}
};
}
Aggregations