code review

This commit is contained in:
Dmitry Jemerov
2016-01-21 12:39:20 +01:00
parent 4910b06f2c
commit 84d507b770
10 changed files with 66 additions and 59 deletions
+2 -2
View File
@@ -23,7 +23,7 @@
<implementation-class>org.jetbrains.kotlin.idea.compiler.KotlinCompilerManager</implementation-class> <implementation-class>org.jetbrains.kotlin.idea.compiler.KotlinCompilerManager</implementation-class>
</component> </component>
<component> <component>
<implementation-class>org.jetbrains.kotlin.idea.configuration.ui.NonConfiguredKotlinProjectComponent</implementation-class> <implementation-class>org.jetbrains.kotlin.idea.configuration.ui.KotlinConfigurationCheckerComponent</implementation-class>
</component> </component>
<component> <component>
<implementation-class>org.jetbrains.kotlin.idea.highlighter.KotlinBeforeResolveHighlightingPass$Factory</implementation-class> <implementation-class>org.jetbrains.kotlin.idea.highlighter.KotlinBeforeResolveHighlightingPass$Factory</implementation-class>
@@ -576,7 +576,7 @@
<editorNotificationProvider implementation="org.jetbrains.kotlin.idea.versions.UnsupportedAbiVersionNotificationPanelProvider"/> <editorNotificationProvider implementation="org.jetbrains.kotlin.idea.versions.UnsupportedAbiVersionNotificationPanelProvider"/>
<editorNotificationProvider implementation="org.jetbrains.kotlin.idea.highlighter.ErrorDuringFileAnalyzeNotificationProvider"/> <editorNotificationProvider implementation="org.jetbrains.kotlin.idea.highlighter.ErrorDuringFileAnalyzeNotificationProvider"/>
<editorNotificationProvider implementation="org.jetbrains.kotlin.idea.configuration.KotlinSetupSDKNotificationProvider"/> <editorNotificationProvider implementation="org.jetbrains.kotlin.idea.configuration.KotlinSetupEnvironmentNotificationProvider"/>
<psi.treeChangePreprocessor implementation="org.jetbrains.kotlin.asJava.KotlinCodeBlockModificationListener"/> <psi.treeChangePreprocessor implementation="org.jetbrains.kotlin.asJava.KotlinCodeBlockModificationListener"/>
@@ -25,14 +25,15 @@ import org.jetbrains.kotlin.idea.configuration.KotlinModuleTypeManager;
public class KotlinModuleTypeManagerImpl extends KotlinModuleTypeManager { public class KotlinModuleTypeManagerImpl extends KotlinModuleTypeManager {
@Override @Override
public boolean isAndroidGradleModule(@NotNull Module module) { public boolean isAndroidGradleModule(@NotNull Module module) {
// We don't want to depend on the Android-Gradle plugin return hasAndroidFacet(module) && isGradleModule(module);
// See com.android.tools.idea.gradle.util.Projects.isGradleProject() }
boolean hasAndroidFacet = false;
private static boolean hasAndroidFacet(@NotNull Module module) {
for (Facet facet : FacetManager.getInstance(module).getAllFacets()) { for (Facet facet : FacetManager.getInstance(module).getAllFacets()) {
if (facet.getName().equals("Android")) { if (facet.getName().equals("Android")) {
hasAndroidFacet = true; return true;
} }
} }
return hasAndroidFacet && isGradleModule(module); return false;
} }
} }
@@ -21,6 +21,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.Messages import com.intellij.openapi.ui.Messages
import org.jetbrains.kotlin.idea.configuration.* import org.jetbrains.kotlin.idea.configuration.*
import org.jetbrains.kotlin.idea.util.projectStructure.allModules
import org.jetbrains.kotlin.js.resolve.JsPlatform import org.jetbrains.kotlin.js.resolve.JsPlatform
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
import org.jetbrains.kotlin.utils.ifEmpty import org.jetbrains.kotlin.utils.ifEmpty
@@ -21,11 +21,11 @@ import com.intellij.notification.NotificationType
import com.intellij.notification.Notifications import com.intellij.notification.Notifications
import com.intellij.openapi.extensions.Extensions import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.module.Module import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.search.FileTypeIndex import com.intellij.psi.search.FileTypeIndex
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.util.projectStructure.allModules
import org.jetbrains.kotlin.utils.ifEmpty import org.jetbrains.kotlin.utils.ifEmpty
fun isProjectConfigured(project: Project): Boolean { fun isProjectConfigured(project: Project): Boolean {
@@ -33,8 +33,6 @@ fun isProjectConfigured(project: Project): Boolean {
return modules.all { isModuleConfigured(it) } return modules.all { isModuleConfigured(it) }
} }
fun Project.allModules() = ModuleManager.getInstance(this).modules.toList()
fun isModuleConfigured(module: Module): Boolean { fun isModuleConfigured(module: Module): Boolean {
val configurators = getApplicableConfigurators(module) val configurators = getApplicableConfigurators(module)
return configurators.any { it.isConfigured(module) } return configurators.any { it.isConfigured(module) }
@@ -94,8 +92,9 @@ fun getNonConfiguredModulesWithKotlinFiles(project: Project, configurator: Kotli
fun getNonConfiguredModules(project: Project, excludeModules: Collection<Module> = emptyList()): Collection<Module> { fun getNonConfiguredModules(project: Project, excludeModules: Collection<Module> = emptyList()): Collection<Module> {
val modulesWithKotlinFiles = getModulesWithKotlinFiles(project) - excludeModules val modulesWithKotlinFiles = getModulesWithKotlinFiles(project) - excludeModules
val ableToRunConfigurators = getAbleToRunConfigurators(project)
return modulesWithKotlinFiles.filter { module -> return modulesWithKotlinFiles.filter { module ->
getAbleToRunConfigurators(project).any { !it.isConfigured(module) } ableToRunConfigurators.any { !it.isConfigured(module) }
} }
} }
@@ -44,7 +44,7 @@ import org.jetbrains.kotlin.idea.versions.UnsupportedAbiVersionNotificationPanel
import org.jetbrains.kotlin.idea.versions.createComponentActionLabel import org.jetbrains.kotlin.idea.versions.createComponentActionLabel
// Code is partially copied from com.intellij.codeInsight.daemon.impl.SetupSDKNotificationProvider // Code is partially copied from com.intellij.codeInsight.daemon.impl.SetupSDKNotificationProvider
class KotlinSetupSDKNotificationProvider( class KotlinSetupEnvironmentNotificationProvider(
private val myProject: Project, private val myProject: Project,
notifications: EditorNotifications) : EditorNotifications.Provider<EditorNotificationPanel>(), DumbAware { notifications: EditorNotifications) : EditorNotifications.Provider<EditorNotificationPanel>(), DumbAware {
@@ -19,19 +19,19 @@ package org.jetbrains.kotlin.idea.configuration.ui;
import com.intellij.notification.NotificationDisplayType; import com.intellij.notification.NotificationDisplayType;
import com.intellij.notification.NotificationsConfiguration; import com.intellij.notification.NotificationsConfiguration;
import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.components.AbstractProjectComponent;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.startup.StartupManager;
import org.jetbrains.kotlin.idea.configuration.ConfigureKotlinInProjectUtilsKt; import org.jetbrains.kotlin.idea.configuration.ConfigureKotlinInProjectUtilsKt;
import org.jetbrains.kotlin.idea.versions.OutdatedKotlinRuntimeNotificationKt; import org.jetbrains.kotlin.idea.versions.OutdatedKotlinRuntimeCheckerKt;
import org.jetbrains.kotlin.idea.versions.VersionedLibrary;
import java.util.List; import java.util.List;
public class NonConfiguredKotlinProjectComponent extends AbstractProjectComponent { public class KotlinConfigurationCheckerComponent extends AbstractProjectComponent {
public static final String CONFIGURE_NOTIFICATION_GROUP_ID = "Configure Kotlin in Project"; public static final String CONFIGURE_NOTIFICATION_GROUP_ID = "Configure Kotlin in Project";
protected NonConfiguredKotlinProjectComponent(Project project) { protected KotlinConfigurationCheckerComponent(Project project) {
super(project); super(project);
NotificationsConfiguration.getNotificationsConfiguration(). NotificationsConfiguration.getNotificationsConfiguration().
@@ -48,8 +48,13 @@ public class NonConfiguredKotlinProjectComponent extends AbstractProjectComponen
DumbService.getInstance(myProject).smartInvokeLater(new Runnable() { DumbService.getInstance(myProject).smartInvokeLater(new Runnable() {
@Override @Override
public void run() { public void run() {
List<Module> modulesWithOutdatedRuntime = OutdatedKotlinRuntimeNotificationKt.checkOutdatedKotlinRuntime(myProject); List<VersionedLibrary> libraries = OutdatedKotlinRuntimeCheckerKt.findOutdatedKotlinLibraries(myProject);
ConfigureKotlinInProjectUtilsKt.showConfigureKotlinNotificationIfNeeded(myProject, modulesWithOutdatedRuntime); if (!libraries.isEmpty()) {
OutdatedKotlinRuntimeCheckerKt.notifyOutdatedKotlinRuntime(myProject, libraries);
}
ConfigureKotlinInProjectUtilsKt.showConfigureKotlinNotificationIfNeeded(myProject,
OutdatedKotlinRuntimeCheckerKt
.collectModulesWithOutdatedRuntime(libraries));
} }
}); });
} }
@@ -26,7 +26,7 @@ import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.idea.configuration.ConfigureKotlinInProjectUtilsKt; import org.jetbrains.kotlin.idea.configuration.ConfigureKotlinInProjectUtilsKt;
import org.jetbrains.kotlin.idea.configuration.KotlinProjectConfigurator; import org.jetbrains.kotlin.idea.configuration.KotlinProjectConfigurator;
import org.jetbrains.kotlin.idea.configuration.ui.NonConfiguredKotlinProjectComponent; import org.jetbrains.kotlin.idea.configuration.ui.KotlinConfigurationCheckerComponent;
import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkEvent;
import java.util.Collection; import java.util.Collection;
@@ -41,7 +41,7 @@ public class ConfigureKotlinNotification extends Notification {
@NotNull final Project project, @NotNull final Project project,
@NotNull final List<Module> excludeModules @NotNull final List<Module> excludeModules
) { ) {
super(NonConfiguredKotlinProjectComponent.CONFIGURE_NOTIFICATION_GROUP_ID, TITLE, getNotificationString(project,excludeModules), super(KotlinConfigurationCheckerComponent.CONFIGURE_NOTIFICATION_GROUP_ID, TITLE, getNotificationString(project, excludeModules),
NotificationType.WARNING, new NotificationListener() { NotificationType.WARNING, new NotificationListener() {
@Override @Override
public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) { public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) {
@@ -16,12 +16,16 @@
package org.jetbrains.kotlin.idea.util.projectStructure package org.jetbrains.kotlin.idea.util.projectStructure
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.module.Module import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.OrderEnumerator import com.intellij.openapi.roots.OrderEnumerator
import java.io.File
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.roots.OrderRootType import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.vfs.VfsUtil
import java.io.File
fun Project.allModules() = ModuleManager.getInstance(this).modules.toList()
fun Module.findLibrary(predicate: (Library) -> Boolean): Library? = OrderEnumerator.orderEntries(this).findLibrary(predicate) fun Module.findLibrary(predicate: (Library) -> Boolean): Library? = OrderEnumerator.orderEntries(this).findLibrary(predicate)
@@ -59,7 +59,7 @@ fun getLibraryRootsWithAbiIncompatibleKotlinClasses(module: Module): Collection<
fun getLibraryRootsWithAbiIncompatibleForKotlinJs(module: Module): Collection<VirtualFile> { fun getLibraryRootsWithAbiIncompatibleForKotlinJs(module: Module): Collection<VirtualFile> {
return getLibraryRootsWithAbiIncompatibleVersion( return getLibraryRootsWithAbiIncompatibleVersion(
module, KotlinJavaScriptAbiVersionIndex, module, KotlinJavaScriptAbiVersionIndex,
{ version -> !KotlinJavascriptMetadataUtils.isAbiVersionCompatible(version.minor) }) // TODO: support major.minor.patch version in JS metadata { version -> !KotlinJavascriptMetadataUtils.isAbiVersionCompatible(version.minor) }) // TODO: support major.minor.patch version in JS metadata
} }
@@ -35,9 +35,9 @@ import org.jetbrains.kotlin.idea.util.application.runWriteAction
import java.io.IOException import java.io.IOException
import javax.swing.event.HyperlinkEvent import javax.swing.event.HyperlinkEvent
private data class VersionedLibrary(val library: Library, val version: String?) data class VersionedLibrary(val library: Library, val version: String?, val usedInModules: Collection<Module>)
fun checkOutdatedKotlinRuntime(project: Project): List<Module> { fun findOutdatedKotlinLibraries(project: Project): List<VersionedLibrary> {
val pluginVersion = KotlinPluginUtil.getPluginVersion() val pluginVersion = KotlinPluginUtil.getPluginVersion()
if ("@snapshot@" == pluginVersion) return emptyList() // plugin is run from sources, can't compare versions if ("@snapshot@" == pluginVersion) return emptyList() // plugin is run from sources, can't compare versions
@@ -46,13 +46,35 @@ fun checkOutdatedKotlinRuntime(project: Project): List<Module> {
return emptyList() return emptyList()
} }
val versionedOutdatedLibraries = findOutdatedKotlinLibraries(project) val outdatedLibraries = arrayListOf<VersionedLibrary>()
if (versionedOutdatedLibraries.isEmpty()) {
return emptyList() for ((library, modules) in findAllUsedLibraries(project).entrySet()) {
val libraryVersionProperties =
LibraryPresentationProviderUtil.getLibraryProperties(JavaRuntimePresentationProvider.getInstance(), library) ?:
LibraryPresentationProviderUtil.getLibraryProperties(JSLibraryStdPresentationProvider.getInstance(), library) ?:
continue
val libraryVersion = libraryVersionProperties.versionString
val runtimeVersion = bundledRuntimeVersion()
val isOutdated = isRuntimeOutdated(libraryVersion, runtimeVersion)
if (isOutdated) {
outdatedLibraries.add(VersionedLibrary(library, libraryVersion, modules))
}
} }
val message: String = if (versionedOutdatedLibraries.size == 1) { return outdatedLibraries
val versionedLibrary = versionedOutdatedLibraries.keys.first() }
fun collectModulesWithOutdatedRuntime(libraries: List<VersionedLibrary>): List<Module> =
libraries.flatMap { it.usedInModules }
fun notifyOutdatedKotlinRuntime(project: Project, outdatedLibraries: Collection<VersionedLibrary>) {
val pluginVersion = KotlinPluginUtil.getPluginVersion()
val message: String = if (outdatedLibraries.size == 1) {
val versionedLibrary = outdatedLibraries.first()
val version = versionedLibrary.version val version = versionedLibrary.version
val readableVersion = version ?: "unknown" val readableVersion = version ?: "unknown"
@@ -63,7 +85,7 @@ fun checkOutdatedKotlinRuntime(project: Project): List<Module> {
"<p><a href=\"update\">Update Runtime</a> <a href=\"ignore\">Ignore</a></p>" "<p><a href=\"update\">Update Runtime</a> <a href=\"ignore\">Ignore</a></p>"
} }
else { else {
val libraryNames = versionedOutdatedLibraries.keys.joinToString { it.library.name!! } val libraryNames = outdatedLibraries.joinToString { it.library.name!! }
"<p>Version of Kotlin runtime is outdated in several libraries ($libraryNames). Plugin version is $pluginVersion.</p>" + "<p>Version of Kotlin runtime is outdated in several libraries ($libraryNames). Plugin version is $pluginVersion.</p>" +
"<p>Runtime libraries should be updated to avoid compatibility problems.</p>" + "<p>Runtime libraries should be updated to avoid compatibility problems.</p>" +
@@ -75,7 +97,7 @@ fun checkOutdatedKotlinRuntime(project: Project): List<Module> {
NotificationType.WARNING, NotificationListener { notification, event -> NotificationType.WARNING, NotificationListener { notification, event ->
if (event.eventType == HyperlinkEvent.EventType.ACTIVATED) { if (event.eventType == HyperlinkEvent.EventType.ACTIVATED) {
if ("update" == event.description) { if ("update" == event.description) {
val outdatedLibraries = findOutdatedKotlinLibraries(project).map { it.key.library } val outdatedLibraries = findOutdatedKotlinLibraries(project).map { it.library }
updateLibraries(project, outdatedLibraries) updateLibraries(project, outdatedLibraries)
suggestDeleteKotlinJsIfNeeded(project, outdatedLibraries) suggestDeleteKotlinJsIfNeeded(project, outdatedLibraries)
} }
@@ -88,11 +110,9 @@ fun checkOutdatedKotlinRuntime(project: Project): List<Module> {
notification.expire() notification.expire()
} }
}), project) }), project)
return versionedOutdatedLibraries.flatMap { it.value }
} }
private fun deleteKotlinJs(project: Project) { fun deleteKotlinJs(project: Project) {
ApplicationManager.getApplication().invokeLater { ApplicationManager.getApplication().invokeLater {
runWriteAction { runWriteAction {
val kotlinJsFile = project.baseDir.findFileByRelativePath("script/kotlin.js") ?: return@runWriteAction val kotlinJsFile = project.baseDir.findFileByRelativePath("script/kotlin.js") ?: return@runWriteAction
@@ -152,29 +172,6 @@ private fun suggestDeleteKotlinJsIfNeeded(project: Project, outdatedLibraries: C
private val SUPPRESSED_PROPERTY_NAME = "oudtdated.runtime.suppressed.plugin.version" private val SUPPRESSED_PROPERTY_NAME = "oudtdated.runtime.suppressed.plugin.version"
private val OUTDATED_RUNTIME_GROUP_DISPLAY_ID = "Outdated Kotlin Runtime" private val OUTDATED_RUNTIME_GROUP_DISPLAY_ID = "Outdated Kotlin Runtime"
private fun findOutdatedKotlinLibraries(project: Project): Map<VersionedLibrary, Collection<Module>> {
val outdatedLibraries = hashMapOf<VersionedLibrary, Collection<Module>>()
for ((library, modules) in findAllUsedLibraries(project).entrySet()) {
val libraryVersionProperties =
LibraryPresentationProviderUtil.getLibraryProperties(JavaRuntimePresentationProvider.getInstance(), library) ?:
LibraryPresentationProviderUtil.getLibraryProperties(JSLibraryStdPresentationProvider.getInstance(), library) ?:
continue
val libraryVersion = libraryVersionProperties.versionString
val runtimeVersion = bundledRuntimeVersion()
val isOutdated = isRuntimeOutdated(libraryVersion, runtimeVersion)
if (isOutdated) {
outdatedLibraries[VersionedLibrary(library, libraryVersion)] = modules
}
}
return outdatedLibraries
}
fun isRuntimeOutdated(libraryVersion: String?, runtimeVersion: String): Boolean { fun isRuntimeOutdated(libraryVersion: String?, runtimeVersion: String): Boolean {
return libraryVersion == null || libraryVersion.startsWith("internal-") != runtimeVersion.startsWith("internal-") || return libraryVersion == null || libraryVersion.startsWith("internal-") != runtimeVersion.startsWith("internal-") ||
VersionComparatorUtil.compare(runtimeVersion, libraryVersion) > 0 VersionComparatorUtil.compare(runtimeVersion, libraryVersion) > 0