From 3eaa41d59aee42e9b3fc3a69c7a4f50e7e9ad4c5 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Sun, 12 May 2024 20:46:24 +0200 Subject: [PATCH] IJPL-149476 convert InspectopediaExtractor to language with modern API GitOrigin-RevId: 9721f95f85456710dd49deb96d54f65e1da40e0e --- .../extractor/InspectopediaExtractor.kt | 379 +++++++++--------- 1 file changed, 191 insertions(+), 188 deletions(-) diff --git a/platform/inspect/src/com/intellij/inspectopedia/extractor/InspectopediaExtractor.kt b/platform/inspect/src/com/intellij/inspectopedia/extractor/InspectopediaExtractor.kt index 0257e26e4289..4d99a728ca22 100644 --- a/platform/inspect/src/com/intellij/inspectopedia/extractor/InspectopediaExtractor.kt +++ b/platform/inspect/src/com/intellij/inspectopedia/extractor/InspectopediaExtractor.kt @@ -1,244 +1,247 @@ -// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.inspectopedia.extractor; +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +@file:Suppress("ReplacePutWithAssignment") -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.MapperFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.databind.json.JsonMapper; -import com.intellij.codeInspection.InspectionEP; -import com.intellij.codeInspection.InspectionProfileEntry; -import com.intellij.codeInspection.ex.*; -import com.intellij.codeInspection.options.*; -import com.intellij.ide.plugins.PluginManager; -import com.intellij.inspectopedia.extractor.data.Inspection; -import com.intellij.inspectopedia.extractor.data.OptionsPanelInfo; -import com.intellij.inspectopedia.extractor.data.Plugin; -import com.intellij.inspectopedia.extractor.data.Plugins; -import com.intellij.inspectopedia.extractor.utils.HtmlUtils; -import com.intellij.openapi.application.ApplicationInfo; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ApplicationStarter; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectManager; -import com.intellij.openapi.util.text.HtmlChunk; -import com.intellij.profile.codeInspection.InspectionProjectProfileManager; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +package com.intellij.inspectopedia.extractor -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.*; -import java.util.stream.Collectors; +import com.fasterxml.jackson.core.JsonProcessingException +import com.fasterxml.jackson.databind.MapperFeature +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.SerializationFeature +import com.fasterxml.jackson.databind.json.JsonMapper +import com.intellij.codeInspection.ex.InspectionMetaInformationService +import com.intellij.codeInspection.options.* +import com.intellij.ide.plugins.IdeaPluginDescriptor +import com.intellij.ide.plugins.PluginManager +import com.intellij.inspectopedia.extractor.InspectopediaExtractor.Companion.getMyText +import com.intellij.inspectopedia.extractor.data.Inspection +import com.intellij.inspectopedia.extractor.data.OptionsPanelInfo +import com.intellij.inspectopedia.extractor.data.Plugin +import com.intellij.inspectopedia.extractor.data.Plugins +import com.intellij.inspectopedia.extractor.utils.HtmlUtils +import com.intellij.openapi.application.ApplicationInfo +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.ApplicationStarter +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.project.ProjectManager +import com.intellij.profile.codeInspection.InspectionProjectProfileManager +import com.intellij.util.containers.ContainerUtil +import java.io.IOException +import java.nio.file.Files +import java.nio.file.Path +import java.util.* +import java.util.function.Function +import java.util.stream.Collectors -final class InspectopediaExtractor implements ApplicationStarter { - private static final Logger LOG = Logger.getInstance(InspectopediaExtractor.class); - private static final Map ASSETS = new HashMap<>(); +private class InspectopediaExtractor : ApplicationStarter { + private val assets: MutableMap = HashMap() - static { - JsonMapper jsonMapper = JsonMapper.builder() + init { + val jsonMapper = JsonMapper.builder() .enable(SerializationFeature.INDENT_OUTPUT) .enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY) - .build(); - ASSETS.put("json", jsonMapper); + .build() + assets.put("json", jsonMapper) } - @Override - public void main(@NotNull List args) { - final int size = args.size(); + override fun main(args: List) { + val size = args.size if (size != 2) { - LOG.error("Usage: inspectopedia-generator "); - System.exit(-1); + LOG.error("Usage: inspectopedia-generator ") + System.exit(-1) } - ApplicationInfo appInfo = ApplicationInfo.getInstance(); - String IDE_CODE = appInfo.getBuild().getProductCode().toLowerCase(Locale.getDefault()); - String IDE_NAME = appInfo.getVersionName(); - String IDE_VERSION = appInfo.getShortVersion(); - String ASSET_FILENAME = IDE_CODE + "-inspections."; + val appInfo = ApplicationInfo.getInstance() + val IDE_CODE = appInfo.build.productCode.lowercase(Locale.getDefault()) + val IDE_NAME = appInfo.versionName + val IDE_VERSION = appInfo.shortVersion + val ASSET_FILENAME = "$IDE_CODE-inspections." - final String outputDirectory = args.get(1); - final Path rootOutputPath = Path.of(outputDirectory).toAbsolutePath(); - final Path outputPath = rootOutputPath.resolve(IDE_CODE); + val outputDirectory = args[1] + val rootOutputPath = Path.of(outputDirectory).toAbsolutePath() + val outputPath = rootOutputPath.resolve(IDE_CODE) try { - Files.createDirectories(outputPath); + Files.createDirectories(outputPath) } - catch (IOException e) { - LOG.error("Output directory does not exist and could not be created"); - System.exit(-1); + catch (e: IOException) { + LOG.error("Output directory does not exist and could not be created") + System.exit(-1) } if (!Files.exists(outputPath) || !Files.isDirectory(outputPath) || !Files.isWritable(outputPath)) { - LOG.error("Output path is invalid"); - System.exit(-1); + LOG.error("Output path is invalid") + System.exit(-1) } try { - final Project project = ProjectManager.getInstance().getDefaultProject(); + val project = ProjectManager.getInstance().defaultProject - LOG.info("Using project " + project.getName() + ", default: " + project.isDefault()); - final InspectionProjectProfileManager inspectionManager = InspectionProjectProfileManager.getInstance(project); - final List scopeToolStates = inspectionManager.getCurrentProfile().getAllTools(); + LOG.info("Using project " + project.name + ", default: " + project.isDefault) + val inspectionManager = InspectionProjectProfileManager.getInstance(project) + val scopeToolStates = inspectionManager.currentProfile.allTools - final Map availablePlugins = Arrays.stream(PluginManager.getPlugins()).map( - pluginDescriptor -> new Plugin(pluginDescriptor.getPluginId().getIdString(), pluginDescriptor.getName(), - pluginDescriptor.getVersion())).distinct() - .collect(Collectors.toMap(Plugin::getId, plugin -> plugin)); + val availablePlugins = Arrays.stream( + PluginManager.getPlugins()).map { pluginDescriptor: IdeaPluginDescriptor -> + Plugin(pluginDescriptor.pluginId.idString, pluginDescriptor.name, + pluginDescriptor.version) + }.distinct() + .collect(Collectors.toMap( + Function { obj: Plugin -> obj.getId() }, Function { plugin: Plugin -> plugin })) - availablePlugins.put(IDE_NAME, new Plugin(IDE_NAME, IDE_NAME, IDE_VERSION)); + availablePlugins[IDE_NAME] = Plugin(IDE_NAME, IDE_NAME, IDE_VERSION) - final InspectionMetaInformationService - service = ApplicationManager.getApplication().getService(InspectionMetaInformationService.class); + val service = ApplicationManager.getApplication().getService( + InspectionMetaInformationService::class.java) - final MetaInformationState inspectionsExtraState = service == null ? null : (MetaInformationState)service.getState(null); + val inspectionsExtraState = if (service == null) null else service.getState(null) - for (final ScopeToolState scopeToolState : scopeToolStates) { + for (scopeToolState in scopeToolStates) { + val wrapper = scopeToolState.tool + val extension = wrapper.extension + val pluginId = extension?.pluginDescriptor?.pluginId?.idString ?: IDE_NAME + val originalDescription = wrapper.loadDescription() + val description = originalDescription?.split("".toRegex())?.dropLastWhile { it.isEmpty() }?.toTypedArray() + ?: arrayOf("") - final InspectionToolWrapper wrapper = scopeToolState.getTool(); - final InspectionEP extension = wrapper.getExtension(); - final String pluginId = extension == null ? IDE_NAME : extension.getPluginDescriptor().getPluginId().getIdString(); - final String originalDescription = wrapper.loadDescription(); - final String[] description = originalDescription == null ? new String[]{""} : originalDescription.split(""); - - List panelInfo = null; + var panelInfo: List? = null try { - InspectionProfileEntry tool = wrapper.getTool(); - final OptPane panel = tool.getOptionsPane(); + val tool = wrapper.tool + val panel = tool.optionsPane - if (!panel.equals(OptPane.EMPTY)) { - LOG.info("Saving options panel for " + wrapper.getShortName()); - panelInfo = retrievePanelStructure(panel, tool.getOptionController()); + if (panel != OptPane.EMPTY) { + LOG.info("Saving options panel for " + wrapper.shortName) + panelInfo = retrievePanelStructure(panel, tool.optionController) } } - catch (Throwable t) { - LOG.info("Cannot create options panel " + wrapper.getShortName(), t); + catch (t: Throwable) { + LOG.info("Cannot create options panel " + wrapper.shortName, t) } - final MetaInformation metaInformation = inspectionsExtraState == null ? null : inspectionsExtraState.getInspections().get(wrapper.getID()); - final List cweIds = metaInformation == null ? null : metaInformation.getCweIds(); + val metaInformation = inspectionsExtraState?.inspections?.get(wrapper.id) + val cweIds = metaInformation?.cweIds - final String language = wrapper.getLanguage(); - final String briefDescription = HtmlUtils.cleanupHtml(description[0], language); - final String extendedDescription = description.length > 1 ? HtmlUtils.cleanupHtml(description[1], language) : null; - final Inspection inspection = new Inspection(wrapper.getShortName(), wrapper.getDisplayName(), wrapper.getDefaultLevel().getName(), - language, briefDescription, - extendedDescription, Arrays.asList(wrapper.getGroupPath()), wrapper.applyToDialects(), - wrapper.isCleanupTool(), wrapper.isEnabledByDefault(), panelInfo, cweIds); + val language = wrapper.language + val briefDescription = HtmlUtils.cleanupHtml(description[0], language) + val extendedDescription = if (description.size > 1) HtmlUtils.cleanupHtml( + description[1], language) + else null + val inspection = Inspection(wrapper.shortName, wrapper.displayName, wrapper.defaultLevel.name, + language, briefDescription, + extendedDescription, Arrays.asList(*wrapper.groupPath), wrapper.applyToDialects(), + wrapper.isCleanupTool, wrapper.isEnabledByDefault, panelInfo, cweIds) - availablePlugins.get(pluginId).addInspection(inspection); + availablePlugins[pluginId]!!.addInspection(inspection) } - var sortedPlugins = availablePlugins.values().stream() - .sorted(Comparator.comparing(Plugin::getId)) - .peek(plugin -> { - plugin.inspections.sort(null); - }).toList(); - final Plugins pluginsData = new Plugins(sortedPlugins, IDE_CODE, IDE_NAME, IDE_VERSION); + val sortedPlugins = availablePlugins.values.stream() + .sorted(Comparator.comparing { obj: Plugin -> obj.getId() }) + .peek { plugin: Plugin -> + plugin.inspections.sort(null) + }.toList() + val pluginsData = Plugins(sortedPlugins, IDE_CODE, IDE_NAME, IDE_VERSION) - for (final String ext : ASSETS.keySet()) { - String data = ""; + for (ext in assets.keys) { + var data: String? = "" try { - data = ASSETS.get(ext).writeValueAsString(pluginsData); + data = assets[ext]!!.writeValueAsString(pluginsData) } - catch (JsonProcessingException e) { - LOG.error("Cannot serialize " + ext.toUpperCase(Locale.getDefault()), e); - System.exit(-1); + catch (e: JsonProcessingException) { + LOG.error("Cannot serialize " + ext.uppercase(Locale.getDefault()), e) + System.exit(-1) } - final Path outPath = outputPath.resolve(ASSET_FILENAME + ext); + val outPath = outputPath.resolve(ASSET_FILENAME + ext) try { - Files.writeString(outPath, data); + Files.writeString(outPath, data) } - catch (IOException e) { - LOG.error("Cannot write " + outPath, e); - System.exit(-1); + catch (e: IOException) { + LOG.error("Cannot write $outPath", e) + System.exit(-1) } - LOG.info("Inspections info saved in " + outPath); + LOG.info("Inspections info saved in $outPath") } } - catch (Exception e) { - LOG.error(e.getMessage(), e); - System.exit(-1); + catch (e: Exception) { + LOG.error(e.message, e) + System.exit(-1) } - System.exit(0); + System.exit(0) } +} - private static @Nullable LocMessage getMyText(final @NotNull OptComponent cmp) { - if (cmp instanceof OptCheckbox checkbox) { - return checkbox.label(); - } - else if (cmp instanceof OptString string) { - return string.splitLabel(); - } - else if (cmp instanceof OptNumber number) { - return number.splitLabel(); - } - else if (cmp instanceof OptExpandableString expandableString) { - return expandableString.label(); - } - else if (cmp instanceof OptStringList list) { - return list.label(); - } - else if (cmp instanceof OptTable table) { - return table.label(); - } - else if (cmp instanceof OptTableColumn column) { - return column.name(); - } - else if (cmp instanceof OptTab tab) { - return tab.label(); - } - else if (cmp instanceof OptDropdown dropdown) { - return dropdown.splitLabel(); - } - else if (cmp instanceof OptGroup group) { - return group.label(); - } - else if (cmp instanceof OptSettingLink link) { - return link.displayName(); - } - else { - return null; - } - } +private val LOG = logger() - private static @NotNull List<@NotNull OptionsPanelInfo> retrievePanelStructure(@NotNull OptPane pane, - @NotNull OptionController controller) { - List children = new ArrayList<>(); - for (OptRegularComponent component : pane.components()) { - children.add(retrievePanelStructure(component, controller)); - } - return children; +private fun getMyText(cmp: OptComponent): LocMessage? { + return if (cmp is OptCheckbox) { + cmp.label } + else if (cmp is OptString) { + cmp.splitLabel + } + else if (cmp is OptNumber) { + cmp.splitLabel + } + else if (cmp is OptExpandableString) { + cmp.label + } + else if (cmp is OptStringList) { + cmp.label + } + else if (cmp is OptTable) { + cmp.label + } + else if (cmp is OptTableColumn) { + cmp.name + } + else if (cmp is OptTab) { + cmp.label + } + else if (cmp is OptDropdown) { + cmp.splitLabel + } + else if (cmp is OptGroup) { + cmp.label + } + else if (cmp is OptSettingLink) { + cmp.displayName + } + else { + null + } +} - private static @NotNull OptionsPanelInfo retrievePanelStructure(@NotNull OptComponent component, @NotNull OptionController controller) { - final OptionsPanelInfo result = new OptionsPanelInfo(); - result.type = component.getClass().getSimpleName(); - result.value = component instanceof OptControl control ? controller.getOption(control.bindId()) : null; - if (component instanceof OptDropdown dropdown) { - if (result.value != null) { - OptDropdown.Option option = dropdown.findOption(result.value); - result.value = option == null ? null : option.label().label(); - } - result.content = ContainerUtil.map(dropdown.options(), opt -> opt.label().label()); - } - LocMessage text = getMyText(component); - result.text = text == null ? null : text.label(); - if (component instanceof OptDescribedComponent describedComponent) { - HtmlChunk description = describedComponent.description(); - result.description = description == null ? null : description.toString(); - } - List children = new ArrayList<>(); - for (OptComponent child : component.children()) { - children.add(retrievePanelStructure(child, controller)); - } - if (!children.isEmpty()) { - result.children = children; - } - return result; +private fun retrievePanelStructure(pane: OptPane, + controller: OptionController): List { + val children: MutableList = ArrayList() + for (component in pane.components) { + children.add(retrievePanelStructure(component, controller)) } + return children +} + +private fun retrievePanelStructure(component: OptComponent, controller: OptionController): OptionsPanelInfo { + val result = OptionsPanelInfo() + result.type = component.javaClass.simpleName + result.value = if (component is OptControl) controller.getOption(component.bindId()) else null + if (component is OptDropdown) { + if (result.value != null) { + val option = component.findOption(result.value) + result.value = option?.label?.label() + } + result.content = ContainerUtil.map(component.options) { opt: OptDropdown.Option -> opt.label.label() } + } + val text = getMyText(component) + result.text = text?.label() + if (component is OptDescribedComponent) { + val description = component.description() + result.description = description?.toString() + } + val children: MutableList = ArrayList() + for (child in component.children()) { + children.add(retrievePanelStructure(child, controller)) + } + if (!children.isEmpty()) { + result.children = children + } + return result } \ No newline at end of file