diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java index 9f0aaed83d1c..654642cc687e 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java @@ -53,6 +53,7 @@ import com.intellij.openapi.application.ApplicationNamesInfo; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.JavaSdk; import com.intellij.openapi.projectRoots.ProjectJdkTable; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.ProjectRootManager; @@ -631,7 +632,7 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb } private static boolean versionMatch(@Nullable Sdk sdk, String version) { - if (sdk != null) { + if (sdk != null && sdk.getSdkType() instanceof JavaSdk) { String versionString = sdk.getVersionString(); return versionString != null && versionString.contains(version); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index 4085d87f8a18..597ff2556d85 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -1620,6 +1620,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh 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.add(ModuleHighlightUtil.checkFileLocation(module, myFile)); } @@ -1644,6 +1645,15 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } } + @Override + public void visitUsesStatement(PsiUsesStatement statement) { + super.visitUsesStatement(statement); + if (PsiUtil.isLanguageLevel9OrHigher(myFile)) { + PsiJavaCodeReferenceElement ref = statement.getClassReference(); + if (!myHolder.hasErrorResults()) myHolder.add(ModuleHighlightUtil.checkServiceReference(ref)); + } + } + @Nullable private HighlightInfo checkFeature(@NotNull PsiElement element, @NotNull Feature feature) { return HighlightUtil.checkFeature(element, feature, myLanguageLevel, myFile); diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java index 23757e593965..e6bc4c0ebd31 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java @@ -35,17 +35,19 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.search.FilenameIndex; import com.intellij.psi.util.PsiUtil; +import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.graph.Graph; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.PropertyKey; -import java.util.Collection; -import java.util.List; -import java.util.Set; +import java.util.*; +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; @@ -83,23 +85,10 @@ public class ModuleHighlightUtil { @NotNull static List checkDuplicateRequires(@NotNull PsiJavaModule module) { - List results = ContainerUtil.newSmartList(); - - Set names = ContainerUtil.newHashSet(); - for (PsiRequiresStatement statement : psiTraverser().children(module).filter(PsiRequiresStatement.class)) { - PsiJavaModuleReferenceElement ref = statement.getReferenceElement(); - if (ref != null) { - String text = ref.getReferenceText(); - if (!names.add(text)) { - String message = JavaErrorMessages.message("module.duplicate.requires", text); - HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).description(message).create(); - QuickFixAction.registerQuickFixAction(info, new DeleteElementFix(statement)); - results.add(info); - } - } - } - - return results; + return checkDuplicateRefs( + psiTraverser().children(module).filter(PsiRequiresStatement.class), + st -> Optional.ofNullable(st.getReferenceElement()).map(PsiJavaModuleReferenceElement::getReferenceText).orElse(null), + "module.duplicate.requires"); } @Nullable @@ -202,23 +191,51 @@ public class ModuleHighlightUtil { @NotNull static List checkDuplicateExports(@NotNull PsiJavaModule module) { - List results = ContainerUtil.newSmartList(); + 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"); + } - Set names = ContainerUtil.newHashSet(); - for (PsiExportsStatement statement : psiTraverser().children(module).filter(PsiExportsStatement.class)) { - PsiJavaCodeReferenceElement ref = statement.getPackageReference(); - if (ref != null) { - String text = PsiNameHelper.getQualifiedClassName(ref.getText(), true); - if (!names.add(text)) { - String message = JavaErrorMessages.message("module.duplicate.export", text); - HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).description(message).create(); - QuickFixAction.registerQuickFixAction(info, new DeleteElementFix(statement)); - results.add(info); - } + @Nullable + static HighlightInfo checkServiceReference(@Nullable PsiJavaCodeReferenceElement refElement) { + if (refElement != null) { + PsiElement target = refElement.resolve(); + if (target instanceof PsiClass && ((PsiClass)target).isEnum()) { + String message = JavaErrorMessages.message("module.service.enum", ((PsiClass)target).getName()); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range(refElement)).description(message).create(); } } - return results; + return null; + } + + @NotNull + static List 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 List checkDuplicateRefs(Iterable statements, + Function ref, + @PropertyKey(resourceBundle = BUNDLE) String key) { + List results = null; + + Set 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() { @@ -228,4 +245,8 @@ public class ModuleHighlightUtil { private static TextRange range(PsiJavaModule module) { return new TextRange(module.getTextOffset(), module.getNameElement().getTextRange().getEndOffset()); } + + private static PsiElement range(PsiJavaCodeReferenceElement refElement) { + return ObjectUtils.notNull(refElement.getReferenceNameElement(), refElement); + } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/reporting/ReportMissingOrExcessiveInlineHint.kt b/java/java-impl/src/com/intellij/reporting/ReportMissingOrExcessiveInlineHint.kt index 30a7091a21e0..a93bb77cbb25 100644 --- a/java/java-impl/src/com/intellij/reporting/ReportMissingOrExcessiveInlineHint.kt +++ b/java/java-impl/src/com/intellij/reporting/ReportMissingOrExcessiveInlineHint.kt @@ -92,7 +92,8 @@ class ReportMissingOrExcessiveInlineHint : AnAction() { } private fun showHint(editor: Editor) { - ApplicationManager.getApplication().invokeLater { + //hack, in most cases hint will not be shown without invokeLater, see IDEA-CR-13295 + ApplicationManager.getApplication().invokeLater { HintManager.getInstance().showInformationHint(editor, "Troubled inline hint was reported") } } diff --git a/java/java-psi-api/src/com/intellij/psi/PsiUsesStatement.java b/java/java-psi-api/src/com/intellij/psi/PsiUsesStatement.java index 7b58dc78fe53..3b1486202a7f 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiUsesStatement.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiUsesStatement.java @@ -15,10 +15,14 @@ */ package com.intellij.psi; +import org.jetbrains.annotations.Nullable; + /** * Represents a {@code uses} statement of a Java module declaration. * * @since 2016.3 */ public interface PsiUsesStatement extends PsiElement { + @Nullable + PsiJavaCodeReferenceElement getClassReference(); } \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java index 123f77628e3c..0bfd02ada81d 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java @@ -175,6 +175,9 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme PsiJavaCodeReferenceCodeFragment fragment = (PsiJavaCodeReferenceCodeFragment)treeParent.getPsi(); return fragment.isClassesAccepted() ? CLASS_FQ_OR_PACKAGE_NAME_KIND : PACKAGE_NAME_KIND; } + if (i == JavaElementType.USES_STATEMENT) { + return CLASS_FQ_NAME_KIND; + } diagnoseUnknownParent(); return CLASS_NAME_KIND; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiUsesStatementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiUsesStatementImpl.java index 2ae1c78ece91..4702ec8228e0 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiUsesStatementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiUsesStatementImpl.java @@ -17,16 +17,25 @@ package com.intellij.psi.impl.source; import com.intellij.psi.JavaElementVisitor; import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.PsiJavaCodeReferenceElement; import com.intellij.psi.PsiUsesStatement; import com.intellij.psi.impl.source.tree.CompositePsiElement; import com.intellij.psi.impl.source.tree.JavaElementType; +import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class PsiUsesStatementImpl extends CompositePsiElement implements PsiUsesStatement { public PsiUsesStatementImpl() { super(JavaElementType.USES_STATEMENT); } + @Nullable + @Override + public PsiJavaCodeReferenceElement getClassReference() { + return PsiTreeUtil.getChildOfType(this, PsiJavaCodeReferenceElement.class); + } + @Override public void accept(@NotNull PsiElementVisitor visitor) { if (visitor instanceof JavaElementVisitor) { diff --git a/java/java-psi-impl/src/messages/JavaErrorMessages.properties b/java/java-psi-impl/src/messages/JavaErrorMessages.properties index 852118da2dd0..87523672ad5d 100644 --- a/java/java-psi-impl/src/messages/JavaErrorMessages.properties +++ b/java/java-psi-impl/src/messages/JavaErrorMessages.properties @@ -402,6 +402,8 @@ package.not.found=Package not found: {0} package.is.empty=Package is empty: {0} module.duplicate.export=Duplicate export: {0} module.self.export=Exports to itself +module.service.enum=The service definition is an enum: {0} +module.duplicate.uses=Duplicate uses: {0} feature.generics=Generics feature.annotations=Annotations diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ModuleHighlightingTest.kt b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ModuleHighlightingTest.kt index b667390a56cc..aa8d37bae175 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ModuleHighlightingTest.kt +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ModuleHighlightingTest.kt @@ -81,6 +81,27 @@ class ModuleHighlightingTest : LightCodeInsightFixtureTestCase() { }""".trimIndent()) } + fun testUses() { + addFile("pkg/main/C.java", "package pkg.main;\nclass C { }") + addFile("pkg/main/E.java", "package pkg.main;\npublic enum E { }") + doTest(""" + module M { + uses pkg.main; + uses pkg.main.X; + uses pkg.main.C; + uses pkg.main.E; + }""".trimIndent()) + } + + fun testDuplicateUses() { + addFile("pkg/main/C.java", "package pkg.main;\npublic class C { }") + doTest(""" + module M { + uses pkg.main.C; + uses pkg. main . /*...*/ C; + }""".trimIndent()) + } + // private fun addFile(path: String, text: String) = VfsTestUtil.createFile(LightPlatformTestCase.getSourceRoot(), path, text) diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 904eb968f67f..a58af1a98ce0 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -786,4 +786,7 @@ rainbow.highlighter.colors.description=List of colors for rainbow highlighter in ide.new.icons=false ide.new.icons.restartRequired=true -ide.new.icons.description=Trying new platform icons \ No newline at end of file +ide.new.icons.description=Trying new platform icons + +ide.remote.interpreters.use.rsync=true +ide.remote.interpreters.use.rsync.description=Use rsync utility to synchronize remote interpreters and local stubs