Add inspection for usages of Kotlin internal declarations in Java
#KT-11393 Fixed
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
This inspection reports usages of Kotlin internal declarations from Java code in different module.
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -2074,6 +2074,14 @@
|
|||||||
language="kotlin"
|
language="kotlin"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.KotlinInternalInJavaInspection"
|
||||||
|
displayName="Usage of Kotlin internal declarations from Java"
|
||||||
|
groupName="Kotlin"
|
||||||
|
enabledByDefault="true"
|
||||||
|
level="ERROR"
|
||||||
|
language="JAVA"
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
<referenceImporter implementation="org.jetbrains.kotlin.idea.quickfix.KotlinReferenceImporter"/>
|
<referenceImporter implementation="org.jetbrains.kotlin.idea.quickfix.KotlinReferenceImporter"/>
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="module" module-name="B" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
internal class SomeInternalClass
|
||||||
+17
@@ -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<Integer> 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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
internal class SomeInternalClassInOtherModule
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
<problems>
|
||||||
|
<problem>
|
||||||
|
<file>test.java</file>
|
||||||
|
<line>3</line>
|
||||||
|
<module>A</module>
|
||||||
|
<package><default></package>
|
||||||
|
<entry_point TYPE="file" FQNAME="test.java" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Usage of Kotlin internal declarations from Java</problem_class>
|
||||||
|
<description>Usage of Kotlin internal declaration from different module</description>
|
||||||
|
</problem>
|
||||||
|
|
||||||
|
<problem>
|
||||||
|
<file>test.java</file>
|
||||||
|
<line>7</line>
|
||||||
|
<module>A</module>
|
||||||
|
<package><default></package>
|
||||||
|
<entry_point TYPE="file" FQNAME="test.java" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Usage of Kotlin internal declarations from Java</problem_class>
|
||||||
|
<description>Usage of Kotlin internal declaration from different module</description>
|
||||||
|
</problem>
|
||||||
|
|
||||||
|
<problem>
|
||||||
|
<file>test.java</file>
|
||||||
|
<line>9</line>
|
||||||
|
<module>A</module>
|
||||||
|
<package><default></package>
|
||||||
|
<entry_point TYPE="file" FQNAME="test.java" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Usage of Kotlin internal declarations from Java</problem_class>
|
||||||
|
<description>Usage of Kotlin internal declaration from different module</description>
|
||||||
|
</problem>
|
||||||
|
|
||||||
|
<problem>
|
||||||
|
<file>test.java</file>
|
||||||
|
<line>11</line>
|
||||||
|
<module>A</module>
|
||||||
|
<package><default></package>
|
||||||
|
<entry_point TYPE="file" FQNAME="test.java" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Usage of Kotlin internal declarations from Java</problem_class>
|
||||||
|
<description>Usage of Kotlin internal declaration from different module</description>
|
||||||
|
</problem>
|
||||||
|
|
||||||
|
<problem>
|
||||||
|
<file>test.java</file>
|
||||||
|
<line>12</line>
|
||||||
|
<module>A</module>
|
||||||
|
<package><default></package>
|
||||||
|
<entry_point TYPE="file" FQNAME="test.java" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Usage of Kotlin internal declarations from Java</problem_class>
|
||||||
|
<description>Usage of Kotlin internal declaration from different module</description>
|
||||||
|
</problem>
|
||||||
|
|
||||||
|
<problem>
|
||||||
|
<file>test.java</file>
|
||||||
|
<line>15</line>
|
||||||
|
<module>A</module>
|
||||||
|
<package><default></package>
|
||||||
|
<entry_point TYPE="file" FQNAME="test.java" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Usage of Kotlin internal declarations from Java</problem_class>
|
||||||
|
<description>Usage of Kotlin internal declaration from different module</description>
|
||||||
|
</problem>
|
||||||
|
|
||||||
|
<problem>
|
||||||
|
<file>test.java</file>
|
||||||
|
<line>15</line>
|
||||||
|
<module>A</module>
|
||||||
|
<package><default></package>
|
||||||
|
<entry_point TYPE="file" FQNAME="test.java" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Usage of Kotlin internal declarations from Java</problem_class>
|
||||||
|
<description>Usage of Kotlin internal declaration from different module</description>
|
||||||
|
</problem>
|
||||||
|
|
||||||
|
</problems>
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"inspectionClass": "org.jetbrains.kotlin.idea.inspections.KotlinInternalInJavaInspection",
|
||||||
|
"withRuntime": "true",
|
||||||
|
"isMultiModule": "true"
|
||||||
|
}
|
||||||
+14
-10
@@ -24,13 +24,13 @@ import com.intellij.codeInspection.LocalInspectionTool
|
|||||||
import com.intellij.codeInspection.ex.InspectionManagerEx
|
import com.intellij.codeInspection.ex.InspectionManagerEx
|
||||||
import com.intellij.codeInspection.ex.LocalInspectionToolWrapper
|
import com.intellij.codeInspection.ex.LocalInspectionToolWrapper
|
||||||
import com.intellij.openapi.util.io.FileUtil
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
import com.intellij.testFramework.IdeaTestUtil
|
|
||||||
import com.intellij.testFramework.InspectionTestUtil
|
import com.intellij.testFramework.InspectionTestUtil
|
||||||
import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl
|
import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl
|
||||||
import org.jetbrains.kotlin.idea.jsonUtils.getString
|
import org.jetbrains.kotlin.idea.jsonUtils.getString
|
||||||
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
|
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
|
||||||
import org.jetbrains.kotlin.idea.test.KotlinMultiFileTestCase
|
import org.jetbrains.kotlin.idea.test.KotlinMultiFileTestCase
|
||||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
||||||
|
import org.jetbrains.kotlin.idea.util.projectStructure.allModules
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
abstract class AbstractMultiFileInspectionTest : KotlinMultiFileTestCase() {
|
abstract class AbstractMultiFileInspectionTest : KotlinMultiFileTestCase() {
|
||||||
@@ -44,19 +44,18 @@ abstract class AbstractMultiFileInspectionTest : KotlinMultiFileTestCase() {
|
|||||||
val inspection = LocalInspectionToolWrapper(Class.forName(config.getString("inspectionClass")).newInstance() as LocalInspectionTool)
|
val inspection = LocalInspectionToolWrapper(Class.forName(config.getString("inspectionClass")).newInstance() as LocalInspectionTool)
|
||||||
|
|
||||||
val withRuntime = config["withRuntime"]?.asBoolean ?: false
|
val withRuntime = config["withRuntime"]?.asBoolean ?: false
|
||||||
if (withRuntime) {
|
|
||||||
ConfigLibraryUtil.configureKotlinRuntimeAndSdk(myModule, PluginTestCaseBase.mockJdk())
|
|
||||||
}
|
|
||||||
|
|
||||||
val withFullJdk = config["withFullJdk"]?.asBoolean ?: false
|
val withFullJdk = config["withFullJdk"]?.asBoolean ?: false
|
||||||
|
isMultiModule = config["isMultiModule"]?.asBoolean ?: false
|
||||||
|
|
||||||
doTest({ _, _ ->
|
doTest({ _, _ ->
|
||||||
try {
|
try {
|
||||||
if (withRuntime) {
|
if (withRuntime) {
|
||||||
ConfigLibraryUtil.configureKotlinRuntimeAndSdk(
|
project.allModules().forEach { module ->
|
||||||
module,
|
ConfigLibraryUtil.configureKotlinRuntimeAndSdk(
|
||||||
if (withFullJdk) PluginTestCaseBase.fullJdk() else PluginTestCaseBase.mockJdk()
|
module,
|
||||||
)
|
if (withFullJdk) PluginTestCaseBase.fullJdk() else PluginTestCaseBase.mockJdk()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val scope = AnalysisScope(myProject)
|
val scope = AnalysisScope(myProject)
|
||||||
@@ -74,7 +73,12 @@ abstract class AbstractMultiFileInspectionTest : KotlinMultiFileTestCase() {
|
|||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
if (withRuntime) {
|
if (withRuntime) {
|
||||||
ConfigLibraryUtil.unConfigureKotlinRuntimeAndSdk(module, IdeaTestUtil.getMockJdk17())
|
project.allModules().forEach { module ->
|
||||||
|
ConfigLibraryUtil.unConfigureKotlinRuntimeAndSdk(
|
||||||
|
module,
|
||||||
|
if (withFullJdk) PluginTestCaseBase.fullJdk() else PluginTestCaseBase.mockJdk()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -42,6 +42,12 @@ public class MultiFileInspectionTestGenerated extends AbstractMultiFileInspectio
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("mismatchedProjectAndDirectory/mismatchedProjectAndDirectory.test")
|
||||||
public void testMismatchedProjectAndDirectory_MismatchedProjectAndDirectory() throws Exception {
|
public void testMismatchedProjectAndDirectory_MismatchedProjectAndDirectory() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/multiFileInspections/mismatchedProjectAndDirectory/mismatchedProjectAndDirectory.test");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/multiFileInspections/mismatchedProjectAndDirectory/mismatchedProjectAndDirectory.test");
|
||||||
|
|||||||
Reference in New Issue
Block a user