[java] unifies duplicate module statements highlighting

This commit is contained in:
Roman Shevchenko
2016-08-26 13:41:16 +03:00
parent aadb5b59d6
commit d56896f01b
3 changed files with 52 additions and 70 deletions
@@ -1618,9 +1618,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
if (!myHolder.hasErrorResults()) myHolder.add(checkFeature(module, Feature.MODULES));
if (!myHolder.hasErrorResults()) myHolder.add(ModuleHighlightUtil.checkFileName(module, myFile));
if (!myHolder.hasErrorResults()) myHolder.add(ModuleHighlightUtil.checkFileDuplicates(module, myFile));
if (!myHolder.hasErrorResults()) myHolder.addAll(ModuleHighlightUtil.checkDuplicateRequires(module));
if (!myHolder.hasErrorResults()) myHolder.addAll(ModuleHighlightUtil.checkDuplicateExports(module));
if (!myHolder.hasErrorResults()) myHolder.addAll(ModuleHighlightUtil.checkDuplicateUses(module));
if (!myHolder.hasErrorResults()) myHolder.addAll(ModuleHighlightUtil.checkDuplicateStatements(module));
if (!myHolder.hasErrorResults()) myHolder.add(ModuleHighlightUtil.checkFileLocation(module, myFile));
}
@@ -47,7 +47,6 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.intellij.codeInsight.daemon.JavaErrorMessages.BUNDLE;
import static com.intellij.psi.PsiJavaModule.MODULE_INFO_FILE;
import static com.intellij.psi.SyntaxTraverser.psiTraverser;
@@ -84,11 +83,45 @@ public class ModuleHighlightUtil {
}
@NotNull
static List<HighlightInfo> checkDuplicateRequires(@NotNull PsiJavaModule module) {
return checkDuplicateRefs(
static List<HighlightInfo> checkDuplicateStatements(@NotNull PsiJavaModule module) {
List<HighlightInfo> results = ContainerUtil.newSmartList();
checkDuplicateRefs(
psiTraverser().children(module).filter(PsiRequiresStatement.class),
st -> Optional.ofNullable(st.getReferenceElement()).map(PsiJavaModuleReferenceElement::getReferenceText).orElse(null),
"module.duplicate.requires");
st -> Optional.ofNullable(st.getReferenceElement()).map(PsiJavaModuleReferenceElement::getReferenceText),
"module.duplicate.requires", results);
checkDuplicateRefs(
psiTraverser().children(module).filter(PsiExportsStatement.class),
st -> Optional.ofNullable(st.getPackageReference()).map(ModuleHighlightUtil::refText),
"module.duplicate.export", results);
checkDuplicateRefs(
psiTraverser().children(module).filter(PsiUsesStatement.class),
st -> Optional.ofNullable(st.getClassReference()).map(ModuleHighlightUtil::refText),
"module.duplicate.uses", results);
return results;
}
private static <T extends PsiElement> void checkDuplicateRefs(Iterable<T> statements,
Function<T, Optional<String>> ref,
@PropertyKey(resourceBundle = JavaErrorMessages.BUNDLE) String key,
List<HighlightInfo> results) {
Set<String> filter = ContainerUtil.newHashSet();
for (T statement : statements) {
String refText = ref.apply(statement).orElse(null);
if (refText != null && !filter.add(refText)) {
String message = JavaErrorMessages.message(key, refText);
HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).description(message).create();
QuickFixAction.registerQuickFixAction(info, new DeleteElementFix(statement));
results.add(info);
}
}
}
private static String refText(PsiJavaCodeReferenceElement ref) {
return PsiNameHelper.getQualifiedClassName(ref.getText(), true);
}
@Nullable
@@ -189,14 +222,6 @@ public class ModuleHighlightUtil {
return results;
}
@NotNull
static List<HighlightInfo> checkDuplicateExports(@NotNull PsiJavaModule module) {
return checkDuplicateRefs(
psiTraverser().children(module).filter(PsiExportsStatement.class),
st -> Optional.ofNullable(st.getPackageReference()).map(ref -> PsiNameHelper.getQualifiedClassName(ref.getText(), true)).orElse(null),
"module.duplicate.export");
}
@Nullable
static HighlightInfo checkServiceReference(@Nullable PsiJavaCodeReferenceElement refElement) {
if (refElement != null) {
@@ -210,34 +235,6 @@ public class ModuleHighlightUtil {
return null;
}
@NotNull
static List<HighlightInfo> checkDuplicateUses(@NotNull PsiJavaModule module) {
return checkDuplicateRefs(
psiTraverser().children(module).filter(PsiUsesStatement.class),
st -> Optional.ofNullable(st.getClassReference()).map(ref -> PsiNameHelper.getQualifiedClassName(ref.getText(), true)).orElse(null),
"module.duplicate.uses");
}
private static <T extends PsiElement> List<HighlightInfo> checkDuplicateRefs(Iterable<T> statements,
Function<T, String> ref,
@PropertyKey(resourceBundle = BUNDLE) String key) {
List<HighlightInfo> results = null;
Set<String> names = ContainerUtil.newHashSet();
for (T statement : statements) {
String refText = ref.apply(statement);
if (refText != null && !names.add(refText)) {
String message = JavaErrorMessages.message(key, refText);
HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).description(message).create();
QuickFixAction.registerQuickFixAction(info, new DeleteElementFix(statement));
if (results == null) results = ContainerUtil.newSmartList();
results.add(info);
}
}
return results != null ? results : Collections.emptyList();
}
private static QuickFixFactory factory() {
return QuickFixFactory.getInstance();
}
@@ -42,6 +42,19 @@ class ModuleHighlightingTest : LightCodeInsightFixtureTestCase() {
myFixture.checkHighlighting()
}
fun testDuplicateStatements() {
addFile("pkg/main/C.java", "package pkg.main;\npublic class C { }")
doTest("""
module M {
requires M2;
<error descr="Duplicate requires: M2">requires M2;</error>
exports pkg.main;
<error descr="Duplicate export: pkg.main">exports pkg. main;</error>
uses pkg.main.C;
<error descr="Duplicate uses: pkg.main.C">uses pkg. main . /*...*/ C;</error>
}""".trimIndent(), true)
}
fun testRequires() {
doTest("""
module M1 {
@@ -51,14 +64,6 @@ class ModuleHighlightingTest : LightCodeInsightFixtureTestCase() {
}""".trimIndent(), true)
}
fun testDuplicateRequires() {
doTest("""
module M {
requires M2;
<error descr="Duplicate requires: M2">requires M2;</error>
}""".trimIndent(), true)
}
fun testExports() {
addFile("pkg/empty/package-info.java", "package pkg.empty;")
addFile("pkg/main/C.java", "package pkg.main;\nclass C { }")
@@ -72,15 +77,6 @@ class ModuleHighlightingTest : LightCodeInsightFixtureTestCase() {
}""".trimIndent())
}
fun testDuplicateExports() {
addFile("pkg/main/C.java", "package pkg.main;\nclass C { }")
doTest("""
module M {
exports pkg.main;
<error descr="Duplicate export: pkg.main">exports pkg. main;</error>
}""".trimIndent())
}
fun testUses() {
addFile("pkg/main/C.java", "package pkg.main;\nclass C { }")
addFile("pkg/main/E.java", "package pkg.main;\npublic enum E { }")
@@ -93,15 +89,6 @@ class ModuleHighlightingTest : LightCodeInsightFixtureTestCase() {
}""".trimIndent())
}
fun testDuplicateUses() {
addFile("pkg/main/C.java", "package pkg.main;\npublic class C { }")
doTest("""
module M {
uses pkg.main.C;
<error descr="Duplicate uses: pkg.main.C">uses pkg. main . /*...*/ C;</error>
}""".trimIndent())
}
//<editor-fold desc="Helpers.">
private fun addFile(path: String, text: String) = VfsTestUtil.createFile(LightPlatformTestCase.getSourceRoot(), path, text)