[java] for service implementations, checks a provider first (IDEA-169447)

This commit is contained in:
Roman Shevchenko
2017-03-17 19:18:00 +01:00
parent 5b411bbec0
commit 89ea31f0a5
2 changed files with 15 additions and 15 deletions
@@ -378,14 +378,24 @@ public class ModuleHighlightUtil {
PsiElement implTarget = implRef.resolve();
if (implTarget instanceof PsiClass) {
PsiClass implClass = (PsiClass)implTarget;
PsiMethod provider;
if (findModule(statement) != findModule(implClass)) {
String message = JavaErrorMessages.message("module.service.alien");
results.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range(implRef)).descriptionAndTooltip(message).create());
}
if (InheritanceUtil.isInheritorOrSelf(implClass, (PsiClass)intTarget, true)) {
PsiMethod provider = ContainerUtil.find(
implClass.findMethodsByName("provider", false),
m -> m.hasModifierProperty(PsiModifier.PUBLIC) && m.hasModifierProperty(PsiModifier.STATIC) && m.getParameterList().getParametersCount() == 0);
if (provider != null) {
PsiType type = provider.getReturnType();
PsiClass typeClass = type instanceof PsiClassType ? ((PsiClassType)type).resolve() : null;
if (!InheritanceUtil.isInheritorOrSelf(typeClass, (PsiClass)intTarget, true)) {
String message = JavaErrorMessages.message("module.service.provider.type", implClass.getName());
results.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range(implRef)).descriptionAndTooltip(message).create());
}
}
else if (InheritanceUtil.isInheritorOrSelf(implClass, (PsiClass)intTarget, true)) {
if (implClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
String message = JavaErrorMessages.message("module.service.abstract", implClass.getName());
results.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range(implRef)).descriptionAndTooltip(message).create());
@@ -399,14 +409,6 @@ public class ModuleHighlightUtil {
results.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range(implRef)).descriptionAndTooltip(message).create());
}
}
else if ((provider = findProvider(implClass)) != null) {
PsiType type = provider.getReturnType();
PsiClass typeClass = type instanceof PsiClassType ? ((PsiClassType)type).resolve() : null;
if (!InheritanceUtil.isInheritorOrSelf(typeClass, (PsiClass)intTarget, true)) {
String message = JavaErrorMessages.message("module.service.provider.type", implClass.getName());
results.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range(implRef)).descriptionAndTooltip(message).create());
}
}
else {
String message = JavaErrorMessages.message("module.service.impl");
results.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range(implRef)).descriptionAndTooltip(message).create());
@@ -417,11 +419,6 @@ public class ModuleHighlightUtil {
return results;
}
private static PsiMethod findProvider(PsiClass implClass) {
return JBIterable.of(implClass.findMethodsByName("provider", false))
.find(p -> p.hasModifierProperty(PsiModifier.PUBLIC) && p.hasModifierProperty(PsiModifier.STATIC) && p.getParameterList().getParametersCount() == 0);
}
@Nullable
static HighlightInfo checkPackageAccessibility(@NotNull PsiJavaCodeReferenceElement ref,
@NotNull PsiElement target,
@@ -156,6 +156,7 @@ class ModuleHighlightingTest : LightJava9ModulesCodeInsightFixtureTestCase() {
fun testProvides() {
addFile("pkg/main/C.java", "package pkg.main;\npublic interface C { }")
addFile("pkg/main/CT.java", "package pkg.main;\npublic interface CT<T> { }")
addFile("pkg/main/Impl1.java", "package pkg.main;\nclass Impl1 { }")
addFile("pkg/main/Impl2.java", "package pkg.main;\npublic class Impl2 { }")
addFile("pkg/main/Impl3.java", "package pkg.main;\npublic abstract class Impl3 implements C { }")
@@ -165,6 +166,7 @@ class ModuleHighlightingTest : LightJava9ModulesCodeInsightFixtureTestCase() {
addFile("pkg/main/Impl7.java", "package pkg.main;\npublic class Impl7 {\n public static void provider();\n}")
addFile("pkg/main/Impl8.java", "package pkg.main;\npublic class Impl8 {\n public static C provider();\n}")
addFile("pkg/main/Impl9.java", "package pkg.main;\npublic class Impl9 {\n public class Inner implements C { }\n}")
addFile("pkg/main/Impl10.java", "package pkg.main;\npublic class Impl10<T> implements CT<T> {\n private Impl10() { }\n public static CT provider();\n}")
addFile("module-info.java", "module M2 {\n exports pkg.m2;\n}", M2)
addFile("pkg/m2/C.java", "package pkg.m2;\npublic class C { }", M2)
addFile("pkg/m2/Impl.java", "package pkg.m2;\npublic class Impl extends C { }", M2)
@@ -181,6 +183,7 @@ class ModuleHighlightingTest : LightJava9ModulesCodeInsightFixtureTestCase() {
provides pkg.main.C with pkg.main.<error descr="The 'provider' method return type must be a subtype of the service interface type: Impl7">Impl7</error>;
provides pkg.main.C with pkg.main.Impl8;
provides pkg.main.C with pkg.main.Impl9.<error descr="The service implementation is an inner class: Inner">Inner</error>;
provides pkg.main.CT with pkg.main.Impl10;
provides pkg.m2.C with pkg.m2.<error descr="The service implementation must be defined in the same module as the provides directive">Impl</error>;
}""".trimIndent())
}