Implement "reflection not found" inspection and quick fix
This commit is contained in:
@@ -441,6 +441,9 @@ replace.by.reconstructed.type=Replace by ''{0}''
|
|||||||
suppress.warnings.family=Suppress Warnings
|
suppress.warnings.family=Suppress Warnings
|
||||||
suppress.warning.for=Suppress ''{0}'' for {1} {2}
|
suppress.warning.for=Suppress ''{0}'' for {1} {2}
|
||||||
|
|
||||||
|
reflection.not.found=Reflection not found in the classpath
|
||||||
|
add.reflection.to.classpath=Add kotlin-reflect.jar to the classpath
|
||||||
|
|
||||||
# Kotlin Compiler Settings Tab
|
# Kotlin Compiler Settings Tab
|
||||||
|
|
||||||
#Common
|
#Common
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
This inspection reports expressions which use reflection features in the module which doesn't have a dependency on kotlin-reflect.jar.
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -868,6 +868,13 @@
|
|||||||
enabledByDefault="true"
|
enabledByDefault="true"
|
||||||
level="WARNING"
|
level="WARNING"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.ReflectionNotFoundInspection"
|
||||||
|
displayName="Reflection not found"
|
||||||
|
groupName="Kotlin"
|
||||||
|
enabledByDefault="true"
|
||||||
|
level="WARNING"
|
||||||
|
/>
|
||||||
<project.converterProvider implementation="org.jetbrains.kotlin.idea.converters.JetRunConfigurationSettingsFormatConverterProvider"/>
|
<project.converterProvider implementation="org.jetbrains.kotlin.idea.converters.JetRunConfigurationSettingsFormatConverterProvider"/>
|
||||||
|
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 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.LocalQuickFix
|
||||||
|
import com.intellij.codeInspection.ProblemDescriptor
|
||||||
|
import com.intellij.codeInspection.ProblemHighlightType
|
||||||
|
import com.intellij.codeInspection.ProblemsHolder
|
||||||
|
import com.intellij.openapi.extensions.Extensions
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.roots.OrderRootType
|
||||||
|
import com.intellij.openapi.vfs.VfsUtil
|
||||||
|
import com.intellij.openapi.vfs.VfsUtilCore
|
||||||
|
import com.intellij.psi.PsiElementVisitor
|
||||||
|
import org.jetbrains.kotlin.idea.JetBundle
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.ConfigureKotlinInProjectUtils
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.KotlinJavaModuleConfigurator
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.KotlinProjectConfigurator
|
||||||
|
import org.jetbrains.kotlin.idea.framework.JavaRuntimePresentationProvider
|
||||||
|
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||||
|
import org.jetbrains.kotlin.idea.versions.KotlinRuntimeLibraryUtil
|
||||||
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
|
import org.jetbrains.kotlin.psi.JetDoubleColonExpression
|
||||||
|
import org.jetbrains.kotlin.psi.JetFile
|
||||||
|
import org.jetbrains.kotlin.psi.JetVisitorVoid
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies
|
||||||
|
import org.jetbrains.kotlin.utils.PathUtil
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||||
|
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
public class ReflectionNotFoundInspection : AbstractKotlinInspection() {
|
||||||
|
override fun runForWholeFile() = true
|
||||||
|
|
||||||
|
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
|
||||||
|
val file = holder.getFile()
|
||||||
|
val reportProblem =
|
||||||
|
file is JetFile &&
|
||||||
|
ProjectRootsUtil.isInProjectSource(file) &&
|
||||||
|
file.findModuleDescriptor().findClassAcrossModuleDependencies(JvmAbi.REFLECTION_FACTORY_IMPL) == null
|
||||||
|
|
||||||
|
return object : JetVisitorVoid() {
|
||||||
|
private fun createQuickFix(): LocalQuickFix? {
|
||||||
|
val pluginReflectJar = PathUtil.getKotlinPathsForIdeaPlugin().getReflectPath()
|
||||||
|
if (pluginReflectJar.exists()) {
|
||||||
|
val configurator =
|
||||||
|
Extensions.getExtensions(KotlinProjectConfigurator.EP_NAME).firstIsInstanceOrNull<KotlinJavaModuleConfigurator>()
|
||||||
|
|
||||||
|
if (configurator != null) {
|
||||||
|
return AddReflectJarQuickFix(configurator, pluginReflectJar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDoubleColonExpression(expression: JetDoubleColonExpression) {
|
||||||
|
if (reportProblem) {
|
||||||
|
holder.registerProblem(
|
||||||
|
expression.getDoubleColonTokenReference(),
|
||||||
|
JetBundle.message("reflection.not.found"),
|
||||||
|
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
|
||||||
|
*(createQuickFix().singletonOrEmptyList().copyToArray())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AddReflectJarQuickFix(
|
||||||
|
val configurator: KotlinJavaModuleConfigurator,
|
||||||
|
val pluginReflectJar: File
|
||||||
|
) : LocalQuickFix {
|
||||||
|
override fun getName() = JetBundle.message("add.reflection.to.classpath")
|
||||||
|
|
||||||
|
override fun getFamilyName() = getName()
|
||||||
|
|
||||||
|
override fun applyFix(project: Project, descriptor: ProblemDescriptor?) {
|
||||||
|
for (library in KotlinRuntimeLibraryUtil.findKotlinLibraries(project)) {
|
||||||
|
val runtimeJar = JavaRuntimePresentationProvider.getRuntimeJar(library) ?: continue
|
||||||
|
if (JavaRuntimePresentationProvider.getReflectJar(library) != null) continue
|
||||||
|
|
||||||
|
val model = library.getModifiableModel()
|
||||||
|
|
||||||
|
val libFilesDir = VfsUtilCore.virtualToIoFile(runtimeJar).getParent()
|
||||||
|
val reflectIoFile = File(libFilesDir, PathUtil.KOTLIN_JAVA_REFLECT_JAR)
|
||||||
|
if (reflectIoFile.exists()) {
|
||||||
|
model.addRoot(VfsUtil.getUrlForLibraryRoot(reflectIoFile), OrderRootType.CLASSES)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val copied = configurator.copyFileToDir(pluginReflectJar, libFilesDir)!!
|
||||||
|
model.addRoot(VfsUtil.getUrlForLibraryRoot(copied), OrderRootType.CLASSES)
|
||||||
|
}
|
||||||
|
|
||||||
|
model.commit()
|
||||||
|
|
||||||
|
ConfigureKotlinInProjectUtils.showInfoNotification(
|
||||||
|
"${PathUtil.KOTLIN_JAVA_REFLECT_JAR} was added to the library ${library.getName()}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user