diff --git a/idea/resources/inspectionDescriptions/KotlinInternalInJava.html b/idea/resources/inspectionDescriptions/KotlinInternalInJava.html
new file mode 100644
index 00000000000..0644bcf0d22
--- /dev/null
+++ b/idea/resources/inspectionDescriptions/KotlinInternalInJava.html
@@ -0,0 +1,5 @@
+
+
+This inspection reports usages of Kotlin internal declarations from Java code in different module.
+
+
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index 83a16bc9a23..f4b715320e7 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -2074,6 +2074,14 @@
language="kotlin"
/>
+
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinInternalInJavaInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinInternalInJavaInspection.kt
new file mode 100644
index 00000000000..686fe979fdc
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinInternalInJavaInspection.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.inspections
+
+import com.intellij.codeInspection.LocalInspectionTool
+import com.intellij.codeInspection.ProblemsHolder
+import com.intellij.psi.*
+import org.jetbrains.kotlin.asJava.elements.KtLightElement
+import org.jetbrains.kotlin.idea.caches.resolve.getNullableModuleInfo
+import org.jetbrains.kotlin.lexer.KtTokens.INTERNAL_KEYWORD
+import org.jetbrains.kotlin.psi.KtModifierListOwner
+
+
+class KotlinInternalInJavaInspection : LocalInspectionTool() {
+ override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
+ return object : JavaElementVisitor() {
+ override fun visitReferenceExpression(expression: PsiReferenceExpression?) {
+ expression?.checkAndReport(holder)
+ }
+
+ override fun visitReferenceElement(reference: PsiJavaCodeReferenceElement?) {
+ reference?.checkAndReport(holder)
+ }
+ }
+ }
+
+ private fun PsiElement.checkAndReport(holder: ProblemsHolder) {
+ val lightElement = (this as? PsiReference)?.resolve() as? KtLightElement<*, *> ?: return
+ val modifierListOwner = lightElement.kotlinOrigin as? KtModifierListOwner ?: return
+ if(inSameModule(modifierListOwner)) {
+ return
+ }
+
+ if(modifierListOwner.hasModifier(INTERNAL_KEYWORD)) {
+ holder.registerProblem(this, "Usage of Kotlin internal declaration from different module")
+ }
+ }
+
+ private fun PsiElement.inSameModule(element: PsiElement) = getNullableModuleInfo()?.equals(element.getNullableModuleInfo()) ?: true
+}
diff --git a/idea/testData/multiFileInspections/kotlinInternalInJava/before/A/A.iml b/idea/testData/multiFileInspections/kotlinInternalInJava/before/A/A.iml
new file mode 100644
index 00000000000..0f75d4273fc
--- /dev/null
+++ b/idea/testData/multiFileInspections/kotlinInternalInJava/before/A/A.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/idea/testData/multiFileInspections/kotlinInternalInJava/before/A/src/SomeInternalClass.kt b/idea/testData/multiFileInspections/kotlinInternalInJava/before/A/src/SomeInternalClass.kt
new file mode 100644
index 00000000000..2503e5ca423
--- /dev/null
+++ b/idea/testData/multiFileInspections/kotlinInternalInJava/before/A/src/SomeInternalClass.kt
@@ -0,0 +1 @@
+internal class SomeInternalClass
\ No newline at end of file
diff --git a/idea/testData/multiFileInspections/kotlinInternalInJava/before/A/src/test.java b/idea/testData/multiFileInspections/kotlinInternalInJava/before/A/src/test.java
new file mode 100644
index 00000000000..7901a490090
--- /dev/null
+++ b/idea/testData/multiFileInspections/kotlinInternalInJava/before/A/src/test.java
@@ -0,0 +1,17 @@
+
+import kotlin.collections.MapsKt;
+import kotlin.internal.PlatformImplementations; // Internal in stdlib, error
+import java.util.function.Consumer;
+
+
+public class SomeClass extends PlatformImplementations { // Internal in stdlib, error
+ public static void doSomething() {
+ PlatformImplementations a; // Internal in stdlib, error
+ Integer c;
+ MapsKt.mapCapacity(3); // Internal in stdlib, error
+ Consumer fun = MapsKt::mapCapacity; // Internal in stdlib, error
+ SomeInternalClass b = new SomeInternalClass(); // Internal in same module, OK
+
+ SomeInternalClassInOtherModule b = new SomeInternalClassInOtherModule(); // Internal in other module, error
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/multiFileInspections/kotlinInternalInJava/before/B/B.iml b/idea/testData/multiFileInspections/kotlinInternalInJava/before/B/B.iml
new file mode 100644
index 00000000000..c90834f2d60
--- /dev/null
+++ b/idea/testData/multiFileInspections/kotlinInternalInJava/before/B/B.iml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/idea/testData/multiFileInspections/kotlinInternalInJava/before/B/src/SomeInternalClassInOtherModule.kt b/idea/testData/multiFileInspections/kotlinInternalInJava/before/B/src/SomeInternalClassInOtherModule.kt
new file mode 100644
index 00000000000..d5468ede628
--- /dev/null
+++ b/idea/testData/multiFileInspections/kotlinInternalInJava/before/B/src/SomeInternalClassInOtherModule.kt
@@ -0,0 +1 @@
+internal class SomeInternalClassInOtherModule
\ No newline at end of file
diff --git a/idea/testData/multiFileInspections/kotlinInternalInJava/expected.xml b/idea/testData/multiFileInspections/kotlinInternalInJava/expected.xml
new file mode 100644
index 00000000000..7a83f9a08f7
--- /dev/null
+++ b/idea/testData/multiFileInspections/kotlinInternalInJava/expected.xml
@@ -0,0 +1,72 @@
+
+
+ test.java
+ 3
+ A
+ <default>
+
+ Usage of Kotlin internal declarations from Java
+ Usage of Kotlin internal declaration from different module
+
+
+
+ test.java
+ 7
+ A
+ <default>
+
+ Usage of Kotlin internal declarations from Java
+ Usage of Kotlin internal declaration from different module
+
+
+
+ test.java
+ 9
+ A
+ <default>
+
+ Usage of Kotlin internal declarations from Java
+ Usage of Kotlin internal declaration from different module
+
+
+
+ test.java
+ 11
+ A
+ <default>
+
+ Usage of Kotlin internal declarations from Java
+ Usage of Kotlin internal declaration from different module
+
+
+
+ test.java
+ 12
+ A
+ <default>
+
+ Usage of Kotlin internal declarations from Java
+ Usage of Kotlin internal declaration from different module
+
+
+
+ test.java
+ 15
+ A
+ <default>
+
+ Usage of Kotlin internal declarations from Java
+ Usage of Kotlin internal declaration from different module
+
+
+
+ test.java
+ 15
+ A
+ <default>
+
+ Usage of Kotlin internal declarations from Java
+ Usage of Kotlin internal declaration from different module
+
+
+
\ No newline at end of file
diff --git a/idea/testData/multiFileInspections/kotlinInternalInJava/kotlinInternalInJava.test b/idea/testData/multiFileInspections/kotlinInternalInJava/kotlinInternalInJava.test
new file mode 100644
index 00000000000..19c36bbaf48
--- /dev/null
+++ b/idea/testData/multiFileInspections/kotlinInternalInJava/kotlinInternalInJava.test
@@ -0,0 +1,5 @@
+{
+ "inspectionClass": "org.jetbrains.kotlin.idea.inspections.KotlinInternalInJavaInspection",
+ "withRuntime": "true",
+ "isMultiModule": "true"
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractMultiFileInspectionTest.kt b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractMultiFileInspectionTest.kt
index 5c91d5c2a15..351cd852c01 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractMultiFileInspectionTest.kt
+++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractMultiFileInspectionTest.kt
@@ -24,13 +24,13 @@ import com.intellij.codeInspection.LocalInspectionTool
import com.intellij.codeInspection.ex.InspectionManagerEx
import com.intellij.codeInspection.ex.LocalInspectionToolWrapper
import com.intellij.openapi.util.io.FileUtil
-import com.intellij.testFramework.IdeaTestUtil
import com.intellij.testFramework.InspectionTestUtil
import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl
import org.jetbrains.kotlin.idea.jsonUtils.getString
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
import org.jetbrains.kotlin.idea.test.KotlinMultiFileTestCase
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
+import org.jetbrains.kotlin.idea.util.projectStructure.allModules
import java.io.File
abstract class AbstractMultiFileInspectionTest : KotlinMultiFileTestCase() {
@@ -44,19 +44,18 @@ abstract class AbstractMultiFileInspectionTest : KotlinMultiFileTestCase() {
val inspection = LocalInspectionToolWrapper(Class.forName(config.getString("inspectionClass")).newInstance() as LocalInspectionTool)
val withRuntime = config["withRuntime"]?.asBoolean ?: false
- if (withRuntime) {
- ConfigLibraryUtil.configureKotlinRuntimeAndSdk(myModule, PluginTestCaseBase.mockJdk())
- }
-
val withFullJdk = config["withFullJdk"]?.asBoolean ?: false
+ isMultiModule = config["isMultiModule"]?.asBoolean ?: false
doTest({ _, _ ->
try {
if (withRuntime) {
- ConfigLibraryUtil.configureKotlinRuntimeAndSdk(
- module,
- if (withFullJdk) PluginTestCaseBase.fullJdk() else PluginTestCaseBase.mockJdk()
- )
+ project.allModules().forEach { module ->
+ ConfigLibraryUtil.configureKotlinRuntimeAndSdk(
+ module,
+ if (withFullJdk) PluginTestCaseBase.fullJdk() else PluginTestCaseBase.mockJdk()
+ )
+ }
}
val scope = AnalysisScope(myProject)
@@ -74,7 +73,12 @@ abstract class AbstractMultiFileInspectionTest : KotlinMultiFileTestCase() {
}
finally {
if (withRuntime) {
- ConfigLibraryUtil.unConfigureKotlinRuntimeAndSdk(module, IdeaTestUtil.getMockJdk17())
+ project.allModules().forEach { module ->
+ ConfigLibraryUtil.unConfigureKotlinRuntimeAndSdk(
+ module,
+ if (withFullJdk) PluginTestCaseBase.fullJdk() else PluginTestCaseBase.mockJdk()
+ )
+ }
}
}
},
diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/MultiFileInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/MultiFileInspectionTestGenerated.java
index fd0c7484873..7782a0886ae 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/MultiFileInspectionTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/MultiFileInspectionTestGenerated.java
@@ -42,6 +42,12 @@ public class MultiFileInspectionTestGenerated extends AbstractMultiFileInspectio
doTest(fileName);
}
+ @TestMetadata("kotlinInternalInJava/kotlinInternalInJava.test")
+ public void testKotlinInternalInJava_KotlinInternalInJava() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/multiFileInspections/kotlinInternalInJava/kotlinInternalInJava.test");
+ doTest(fileName);
+ }
+
@TestMetadata("mismatchedProjectAndDirectory/mismatchedProjectAndDirectory.test")
public void testMismatchedProjectAndDirectory_MismatchedProjectAndDirectory() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/multiFileInspections/mismatchedProjectAndDirectory/mismatchedProjectAndDirectory.test");