Implement "reflection not found" inspection and quick fix

This commit is contained in:
Alexander Udalov
2015-03-12 23:14:35 +03:00
parent 094fa2f92b
commit 4b4f6a713a
4 changed files with 133 additions and 0 deletions
@@ -441,6 +441,9 @@ replace.by.reconstructed.type=Replace by ''{0}''
suppress.warnings.family=Suppress Warnings
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
#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>
+7
View File
@@ -868,6 +868,13 @@
enabledByDefault="true"
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"/>
</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()}"
)
}
}
}
}