Merge remote-tracking branch 'origin/master'

This commit is contained in:
Roman Shevchenko
2019-03-05 22:41:44 +01:00
33 changed files with 252 additions and 148 deletions
-2
View File
@@ -1536,10 +1536,8 @@ Function un.onInit
Call un.UninstallFeedback
; Uninstallation was run from installation dir?
IfFileExists "$INSTDIR\IdeaWin32.dll" 0 end_of_uninstall
IfFileExists "$INSTDIR\IdeaWin64.dll" 0 end_of_uninstall
IfFileExists "$INSTDIR\${PRODUCT_EXE_FILE_64}" 0 end_of_uninstall
IfFileExists "$INSTDIR\${PRODUCT_EXE_FILE}" 0 end_of_uninstall
get_reg_key:
SetRegView 32
@@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.debugger.engine;
import com.intellij.debugger.DebuggerBundle;
@@ -253,7 +253,7 @@ public class JVMNameUtil {
@NotNull
public static JVMName getJVMQualifiedName(@NotNull PsiClass psiClass) {
final String name = getNonAnonymousClassName(psiClass);
final String name = getClassVMName(psiClass);
if (name != null) {
return getJVMRawText(name);
}
@@ -32,6 +32,7 @@ import org.intellij.lang.annotations.MagicConstant;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@@ -41,7 +42,7 @@ import java.util.stream.Collectors;
*/
public class MethodCandidateInfo extends CandidateInfo{
public static final RecursionGuard ourOverloadGuard = RecursionManager.createGuard("overload.guard");
public static final ThreadLocal<Map<PsiElement, CurrentCandidateProperties>> CURRENT_CANDIDATE = new ThreadLocal<>();
private static final ThreadLocal<Map<PsiElement, CurrentCandidateProperties>> CURRENT_CANDIDATE = ThreadLocal.withInitial(HashMap::new);
@ApplicabilityLevelConstant private volatile int myApplicabilityLevel;
@ApplicabilityLevelConstant private volatile int myPertinentApplicabilityLevel;
private final PsiElement myArgumentList;
@@ -14,6 +14,21 @@
<style>
.activityChart {
width: 100%;
/*
our data has extraordinary high values (extremes) and it makes item chart not readable (extremes are visible and others column bars are too low),
as solution, amCharts supports breaks (https://www.amcharts.com/demos/column-chart-with-axis-break/),
but it contradicts to our goal - to show that these items are extremes,
so, as solution, we increase chart height to give more space to render bars.
It is ok, as now we use UI Library (ElementUI) and can use Tabs, Collapse and any other component to group charts.
Also, as we use Vue.js and Vue Router, it is one-line to provide dedicated view (/#/components and so on)
*/
height: 500px;
}
.timeLineChart {
width: 100%;
/* in any case time line chart will adjust height according to items */
height: 380px;
}
</style>
@@ -15,26 +15,33 @@ export abstract class BaseChartComponent<T extends ChartManager> extends Vue {
}
mounted() {
this.chartManager = this.createChartManager()
this.renderDataIfAvailable()
}
protected abstract createChartManager(): T
@Watch("measurementData")
// @ts-ignore
private measurementDataChanged(): void {
this.renderDataIfAvailable()
}
/** @final */
protected renderDataIfAvailable(): void {
const data = this.measurementData
if (data != null) {
const chartManager = this.chartManager
if (chartManager != null) {
chartManager.render(data)
}
if (data == null) {
// yes, do not re-render as empty - null value not expected to be set in valid cases
return
}
let chartManager = this.chartManager
if (chartManager == null) {
chartManager = this.createChartManager()
this.chartManager = chartManager
}
chartManager.render(data)
}
beforeDestroy() {
const chartManager = this.chartManager
if (chartManager != null) {
this.chartManager = null
chartManager.dispose()
}
}
}
@@ -5,6 +5,8 @@ import {DataManager} from "@/state/DataManager"
export interface ChartManager {
render(data: DataManager): void
dispose(): void
}
function configureCommonChartSettings(chart: am4charts.XYChart) {
@@ -15,7 +17,6 @@ function configureCommonChartSettings(chart: am4charts.XYChart) {
const cursor = new am4charts.XYCursor()
cursor.lineY.disabled = true
cursor.lineX.disabled = true
// todo y axis for ItemChart doesn't work as expected (not scaled according to current data) because of 2 series for axis (and so, no chart data is set)
cursor.behavior = "zoomXY"
chart.cursor = cursor
}
@@ -30,30 +31,10 @@ export abstract class XYChartManager implements ChartManager {
// this.addDisposeHandler(childHot)
}
/** @override */
dispose(): void {
this.chart.dispose()
}
// module.hot must be passed here explicitly, because module in this context related only to this module
// private addDisposeHandler(hot: __WebpackModuleApi.Hot | null | undefined) {
// if (hot == null) {
// return
// }
//
// hot.dispose(_data => {
// const chart = this.chart
// if (chart == null) {
// return
// }
//
// (this as any).chart = null
// chart.dispose()
// // const exportingMenu = chart.exporting.menu
// // if (exportingMenu != null) {
// // exportingMenu.dispose()
// // }
// })
// }
abstract render(data: DataManager): void
}
@@ -5,7 +5,7 @@
<script lang="ts">
import {Component, Prop, Watch} from "vue-property-decorator"
import {ComponentChartManager, ItemChartManager, ServiceChartManager, TopHitProviderChart} from "./ItemChartManager"
import {ComponentChartManager, ItemChartManager} from "./ItemChartManager"
import {ItemChartType} from "@/charts/ItemChartDescriptor"
import {BaseChartComponent} from "@/charts/BaseChartComponent"
@@ -34,10 +34,13 @@
return new ComponentChartManager(chartContainer)
}
else if (type === "services") {
return new ServiceChartManager(chartContainer)
return new ItemChartManager(chartContainer, ["appServices", "projectServices", "moduleServices"])
}
else if (type === "extensions") {
return new ItemChartManager(chartContainer, ["appExtensions", "projectExtensions", "moduleExtensions"])
}
else if (type === "topHitProviders") {
return new TopHitProviderChart(chartContainer)
return new ItemChartManager(chartContainer, ["appOptionsTopHitProviders", "projectOptionsTopHitProviders"])
}
else {
throw new Error(`Unknown chart type: ${type}`)
@@ -1,6 +1,6 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
export type ItemChartType = "components" | "services" | "topHitProviders"
export type ItemChartType = "components" | "services" | "extensions" | "topHitProviders"
export interface ItemChartDescriptor {
readonly label: string
@@ -8,9 +8,10 @@ export interface ItemChartDescriptor {
}
// not as part of ItemChartManager.ts to reduce scope of changes on change
// (makes sure that hot reloading to not reload all modules where `chartDescriptors` is used - especially `router`)
// (make sure that hot reloading will not reload all modules where `chartDescriptors` is used - especially `router`)
export const chartDescriptors: Array<ItemChartDescriptor> = [
{label: "Components", name: "components"},
{label: "Services", name: "services"},
{label: "Extensions", name: "extensions"},
{label: "Options Top Hit Providers", name: "topHitProviders"},
]
@@ -5,13 +5,18 @@ import {XYChartManager} from "@/charts/ChartManager"
import {DataManager} from "@/state/DataManager"
import {Item} from "@/state/data"
export type ComponentProviderSourceNames = "appComponents" | "projectComponents"
export type ServiceProviderSourceNames = "appServices" | "projectServices"
export type ComponentProviderSourceNames = "appComponents" | "projectComponents" | "moduleComponents"
export type ServiceProviderSourceNames = "appServices" | "projectServices" | "moduleServices"
export type ExtensionProviderSourceNames = "appExtensions" | "projectExtensions" | "moduleExtensions"
export type TopHitProviderSourceNames = "appOptionsTopHitProviders" | "projectOptionsTopHitProviders"
export abstract class ItemChartManager extends XYChartManager {
export class ItemChartManager extends XYChartManager {
// isUseYForName - if true, names are more readable, but not possible to see all components because layout from top to bottom (so, opposite from left to right some data can be out of current screen)
protected constructor(container: HTMLElement, private readonly sourceNames: Array<ComponentProviderSourceNames> | Array<TopHitProviderSourceNames> | Array<ServiceProviderSourceNames>) {
constructor(container: HTMLElement,
private readonly sourceNames: Array<ComponentProviderSourceNames>
| Array<TopHitProviderSourceNames>
| Array<ServiceProviderSourceNames>
| Array<ExtensionProviderSourceNames>) {
super(container, module.hot)
this.configureNameAxis()
@@ -50,14 +55,21 @@ export abstract class ItemChartManager extends XYChartManager {
private configureDurationAxis(): void {
const durationAxis = this.chart.yAxes.push(new am4charts.DurationAxis())
durationAxis.title.text = "Duration"
durationAxis.baseUnit = "millisecond"
// base unit the values are in (https://www.amcharts.com/docs/v4/reference/durationformatter/)
durationAxis.durationFormatter.baseUnit = "millisecond"
durationAxis.durationFormatter.durationFormat = "S"
// do not set strictMinMax because otherwise zooming will not work
// (axis will not reflect currently selected items, but always the whole set and so, will be not convenient to see items with small values)
// durationAxis.strictMinMax = true
// cursor tooltip is distracting
durationAxis.cursorTooltipEnabled = false
// https://www.amcharts.com/docs/v4/concepts/axes/positioning-axis-elements/#Setting_the_density_of_the_the_grid_labels
// default value 40 makes distribution not good
// but for other charts default value suits better...
// decided to not do anything - if you don't like that extremes makes chart not readable - fix these extremes or select desired area (cursor is supported)
}
protected configureSeries(): void {
@@ -69,7 +81,7 @@ export abstract class ItemChartManager extends XYChartManager {
}
// https://www.amcharts.com/docs/v4/concepts/series/#Note_about_Series_data_and_Category_axis
render(data: DataManager) {
render(data: DataManager): void {
const concatenatedData: Array<ClassItem> = []
let colorIndex = 0
const legendData: Array<LegendItem> = []
@@ -83,17 +95,21 @@ export abstract class ItemChartManager extends XYChartManager {
stroke: color,
}
// generate color before - even if no data for this type of items, still color should be the same regardless of current data set
// so, if currently no data for project, but there is data for modules, color for modules should use index 3 and not 2
const items = data.data[sourceName]
if (items == null || items.length === 0) {
continue
}
const legendItem: LegendItem = {
name: (sourceName.startsWith("app") ? "Application" : "Project") + "-level",
name: this.sourceNameToLegendName(sourceName, items.length),
fill: color,
sourceName,
}
legendData.push(legendItem)
applicableSources.add(sourceName)
// generate color before - even if no data for this type of items, still color should be the same regardless of current data set
// so, if currently no data for project, but there is data for modules, color for modules should use index 3 and not 2
const items = data.data[sourceName] || []
for (const item of items) {
concatenatedData.push({
...item,
@@ -123,7 +139,21 @@ export abstract class ItemChartManager extends XYChartManager {
this.chart.data = concatenatedData
}
protected computeRangeMarkers(data: DataManager, items: Array<ClassItem>) {
private sourceNameToLegendName(sourceName: string, itemCount: number): string {
let prefix
if (sourceName.startsWith("app")) {
prefix = "Application"
}
else if (sourceName.startsWith("project")) {
prefix = "Project"
}
else if (sourceName.startsWith("module")) {
prefix = "Module"
}
return `${prefix}-level (${itemCount})`
}
protected computeRangeMarkers(data: DataManager, items: Array<ClassItem>): void {
const nameAxis = this.nameAxis
nameAxis.axisRanges.clear()
for (const guideLineDescriptor of data.computeGuides(items)) {
@@ -131,7 +161,7 @@ export abstract class ItemChartManager extends XYChartManager {
}
}
private createRangeMarker(axis: am4charts.CategoryAxis, item: ClassItem, label: string) {
private createRangeMarker(axis: am4charts.CategoryAxis, item: ClassItem, label: string): void {
const range = axis.axisRanges.create()
range.category = item.shortName
range.label.inside = true
@@ -160,7 +190,7 @@ function getShortName(item: Item): string {
export class ComponentChartManager extends ItemChartManager {
constructor(container: HTMLElement) {
super(container, ["appComponents", "projectComponents"])
super(container, ["appComponents", "projectComponents", "moduleComponents"])
}
// doesn't make sense for components - cannot be outside of ready, and app initialized is clear
@@ -169,18 +199,6 @@ export class ComponentChartManager extends ItemChartManager {
}
}
export class ServiceChartManager extends ItemChartManager {
constructor(container: HTMLElement) {
super(container, ["appServices", "projectServices"])
}
}
export class TopHitProviderChart extends ItemChartManager {
constructor(container: HTMLElement) {
super(container, ["appOptionsTopHitProviders", "projectOptionsTopHitProviders"])
}
}
interface LegendItem {
readonly name: string
readonly sourceName: string
@@ -16,9 +16,15 @@ export interface InputData {
appComponents?: Array<Item>
projectComponents?: Array<Item>
moduleComponents?: Array<Item>
appServices?: Array<Item>
projectServices?: Array<Item>
moduleServices?: Array<Item>
appExtensions?: Array<Item>
projectExtensions?: Array<Item>
moduleExtensions?: Array<Item>
preloadActivities?: Array<Item>
appOptionsTopHitProviders?: Array<Item>
@@ -1,6 +1,6 @@
<!-- Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<template>
<div class="activityChart" ref="chartContainer"></div>
<div class="timeLineChart" ref="chartContainer"></div>
</template>
<script lang="ts">
@@ -11,8 +11,8 @@ import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import java.util.concurrent.atomic.AtomicBoolean
// A way to remove stalled/unused component data.
internal val STALLED_STORAGE_EP = ExtensionPointName<StalledStorageBean>("com.intellij.stalledStorage")
// A way to remove obsolete component data.
internal val OBSOLETE_STORAGE_EP = ExtensionPointName<ObsoleteStorageBean>("com.intellij.obsoleteStorage")
abstract class ComponentStoreWithExtraComponents : ComponentStoreImpl() {
@Suppress("DEPRECATION")
@@ -81,14 +81,14 @@ abstract class ComponentStoreWithExtraComponents : ComponentStoreImpl() {
override fun commitComponents(isForce: Boolean, session: SaveSessionProducerManager, errors: MutableList<Throwable>) {
// ensure that this task will not interrupt regular saving
LOG.runAndLogException {
commitStalledComponents(session, false)
commitObsoleteComponents(session, false)
}
super.commitComponents(isForce, session, errors)
}
internal open fun commitStalledComponents(session: SaveSessionProducerManager, isProjectLevel: Boolean) {
for (bean in STALLED_STORAGE_EP.extensionList) {
internal open fun commitObsoleteComponents(session: SaveSessionProducerManager, isProjectLevel: Boolean) {
for (bean in OBSOLETE_STORAGE_EP.extensionList) {
if (bean.isProjectLevel != isProjectLevel) {
continue
}
@@ -7,7 +7,7 @@ import com.intellij.util.xmlb.annotations.XCollection;
import java.util.List;
final class StalledStorageBean {
final class ObsoleteStorageBean {
@Attribute
public String file;
@@ -353,9 +353,9 @@ private open class ProjectStoreImpl(project: Project, private val pathMacroManag
final override fun createSaveSessionProducerManager() = ProjectSaveSessionProducerManager(project)
final override fun commitStalledComponents(session: SaveSessionProducerManager, isProjectLevel: Boolean) {
final override fun commitObsoleteComponents(session: SaveSessionProducerManager, isProjectLevel: Boolean) {
if (isDirectoryBased) {
super.commitStalledComponents(session, true)
super.commitObsoleteComponents(session, true)
}
}
}
@@ -299,10 +299,10 @@ internal class ApplicationStoreTest {
@Test
fun `remove stalled data`() = runBlocking<Unit> {
val stalledStorageBean = StalledStorageBean()
stalledStorageBean.file = "i_do_not_want_to_be_deleted_but.xml"
stalledStorageBean.components.addAll(listOf("loser1", "loser2", "lucky"))
PlatformTestUtil.maskExtensions(STALLED_STORAGE_EP, listOf(stalledStorageBean), disposableRule.disposable)
val obsoleteStorageBean = ObsoleteStorageBean()
obsoleteStorageBean.file = "i_do_not_want_to_be_deleted_but.xml"
obsoleteStorageBean.components.addAll(listOf("loser1", "loser2", "lucky"))
PlatformTestUtil.maskExtensions(OBSOLETE_STORAGE_EP, listOf(obsoleteStorageBean), disposableRule.disposable)
@State(name = "loser1", storages = [(Storage(value = "i_do_not_want_to_be_deleted_but.xml"))])
class AOther : A()
@@ -325,8 +325,8 @@ internal class ApplicationStoreTest {
componentStore.save()
// all must be saved regardless of stalledStorageBean because we have such components
assertThat(testAppConfig.resolve(stalledStorageBean.file)).isEqualTo("""
// all must be saved regardless of obsoleteStorageBean because we have such components
assertThat(testAppConfig.resolve(obsoleteStorageBean.file)).isEqualTo("""
<application>
<component name="loser1" foo="old" />
<component name="loser2" foo="old?" />
@@ -338,7 +338,7 @@ internal class ApplicationStoreTest {
// first looser is deleted since state equals to default (no committed component data)
componentStore.save()
assertThat(testAppConfig.resolve(stalledStorageBean.file)).isEqualTo("""
assertThat(testAppConfig.resolve(obsoleteStorageBean.file)).isEqualTo("""
<application>
<component name="loser2" foo="old?" />
<component name="lucky" bar="foo" />
@@ -349,7 +349,7 @@ internal class ApplicationStoreTest {
// second looser is deleted since state equals to default (no committed component data)
componentStore.save()
assertThat(testAppConfig.resolve(stalledStorageBean.file)).isEqualTo("""
assertThat(testAppConfig.resolve(obsoleteStorageBean.file)).isEqualTo("""
<application>
<component name="lucky" bar="foo" />
</application>
@@ -358,12 +358,12 @@ internal class ApplicationStoreTest {
@Test
fun `remove stalled data - keep file if another unknown component`() = runBlocking<Unit> {
val stalledStorageBean = StalledStorageBean()
stalledStorageBean.file = "i_will_be_not_deleted.xml"
stalledStorageBean.components.addAll(listOf("Loser"))
PlatformTestUtil.maskExtensions(STALLED_STORAGE_EP, listOf(stalledStorageBean), disposableRule.disposable)
val obsoleteStorageBean = ObsoleteStorageBean()
obsoleteStorageBean.file = "i_will_be_not_deleted.xml"
obsoleteStorageBean.components.addAll(listOf("Loser"))
PlatformTestUtil.maskExtensions(OBSOLETE_STORAGE_EP, listOf(obsoleteStorageBean), disposableRule.disposable)
testAppConfig.resolve(stalledStorageBean.file).write("""
testAppConfig.resolve(obsoleteStorageBean.file).write("""
<application>
<component name="Unknown" data="some data" />
<component name="Loser" foo="old?" />
@@ -372,7 +372,7 @@ internal class ApplicationStoreTest {
componentStore.save()
assertThat(testAppConfig.resolve(stalledStorageBean.file)).isEqualTo("""
assertThat(testAppConfig.resolve(obsoleteStorageBean.file)).isEqualTo("""
<application>
<component name="Unknown" data="some data" />
</application>
@@ -182,16 +182,16 @@ internal class ProjectStoreTest {
""".trimIndent())
it.path
}) { project ->
val stalledStorageBean = StalledStorageBean()
val obsoleteStorageBean = ObsoleteStorageBean()
val storageFileName = "foo.xml"
stalledStorageBean.file = storageFileName
stalledStorageBean.components.addAll(listOf("AppLevelLoser"))
obsoleteStorageBean.file = storageFileName
obsoleteStorageBean.components.addAll(listOf("AppLevelLoser"))
val projectStalledStorageBean = StalledStorageBean()
val projectStalledStorageBean = ObsoleteStorageBean()
projectStalledStorageBean.file = storageFileName
projectStalledStorageBean.isProjectLevel = true
projectStalledStorageBean.components.addAll(listOf("ProjectLevelLoser"))
PlatformTestUtil.maskExtensions(STALLED_STORAGE_EP, listOf(stalledStorageBean, projectStalledStorageBean), project)
PlatformTestUtil.maskExtensions(OBSOLETE_STORAGE_EP, listOf(obsoleteStorageBean, projectStalledStorageBean), project)
val componentStore = project.stateStore
@@ -204,7 +204,7 @@ internal class ProjectStoreTest {
componentStore.save()
assertThat(Paths.get(project.stateStore.storageManager.expandMacros(PROJECT_CONFIG_DIR)).resolve(stalledStorageBean.file)).isEqualTo("""
assertThat(Paths.get(project.stateStore.storageManager.expandMacros(PROJECT_CONFIG_DIR)).resolve(obsoleteStorageBean.file)).isEqualTo("""
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AppLevelLoser" foo="old?" />
@@ -44,6 +44,8 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static com.intellij.util.pico.DefaultPicoContainer.getMeasureTokenLevel;
public abstract class ComponentManagerImpl extends UserDataHolderBase implements ComponentManagerEx, Disposable {
private static final Logger LOG = Logger.getInstance("#com.intellij.components.ComponentManager");
@@ -481,9 +483,7 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
return instance;
}
// if it will be module component, then get rid of such component instead of measurement
boolean appComponent = ComponentManagerImpl.this instanceof Application;
StartUpMeasurer.MeasureToken measureToken = StartUpMeasurer.start(appComponent ? Activities.APP_COMPONENT : Activities.PROJECT_COMPONENT);
StartUpMeasurer.MeasureToken measureToken = StartUpMeasurer.start(Activities.COMPONENT, getMeasureTokenLevel(picoContainer));
instance = super.getComponentInstance(picoContainer);
if (myInitializing) {
@@ -10,6 +10,8 @@ import com.intellij.openapi.util.EmptyRunnable;
import com.intellij.openapi.util.Pair;
import com.intellij.util.ArrayFactory;
import com.intellij.util.ArrayUtil;
import com.intellij.util.StartUpMeasurer;
import com.intellij.util.StartUpMeasurer.Activities;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.OpenTHashSet;
import org.jdom.Element;
@@ -25,6 +27,8 @@ import java.util.function.BiPredicate;
import java.util.function.Predicate;
import java.util.stream.Stream;
import static com.intellij.util.pico.DefaultPicoContainer.getMeasureTokenLevel;
/**
* @author AKireyev
*/
@@ -272,6 +276,8 @@ public abstract class ExtensionPointImpl<T> implements ExtensionPoint<T> {
}
assertNotReadOnlyMode();
StartUpMeasurer.MeasureToken measureToken = StartUpMeasurer.start(Activities.EXTENSION, getMeasureTokenLevel(myPicoContainer));
int totalSize = myAdapters.size();
Class<T> extensionClass = getExtensionClass();
T[] result = ArrayUtil.newArray(extensionClass, totalSize);
@@ -281,7 +287,6 @@ public abstract class ExtensionPointImpl<T> implements ExtensionPoint<T> {
// check before to avoid any "restore" work if already cancelled
CHECK_CANCELED.run();
processingAdaptersNow = true;
try {
List<ExtensionComponentAdapter> adapters = myAdapters;
@@ -332,6 +337,9 @@ public abstract class ExtensionPointImpl<T> implements ExtensionPoint<T> {
if (extensionIndex != result.length) {
result = Arrays.copyOf(result, extensionIndex);
}
// don't count ProcessCanceledException as valid action to measure (later special category can be introduced if needed)
measureToken.endWithThreshold(extensionClass);
return result;
}
finally {
@@ -3,6 +3,7 @@ package com.intellij.util.pico;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.SmartList;
import com.intellij.util.StartUpMeasurer;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.FList;
import gnu.trove.THashSet;
@@ -403,4 +404,18 @@ public class DefaultPicoContainer implements MutablePicoContainer {
public String toString() {
return "DefaultPicoContainer" + (getParent() == null ? " (root)" : " (parent="+getParent()+")");
}
@NotNull
public static StartUpMeasurer.Level getMeasureTokenLevel(@NotNull PicoContainer picoContainer) {
PicoContainer parent = picoContainer.getParent();
if (parent == null) {
return StartUpMeasurer.Level.APPLICATION;
}
else if (parent.getParent() == null) {
return StartUpMeasurer.Level.PROJECT;
}
else {
return StartUpMeasurer.Level.MODULE;
}
}
}
@@ -38,6 +38,7 @@ import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ExceptionUtil;
import com.intellij.util.ExceptionUtilRt;
import com.intellij.util.PathUtil;
import com.intellij.util.concurrency.Semaphore;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.io.PathKt;
@@ -268,7 +269,7 @@ public abstract class ExternalSystemTestCase extends UsefulTestCase {
@SystemIndependent
protected String path(@NotNull String relativePath) {
return file(relativePath).getPath();
return PathUtil.toSystemIndependentName(file(relativePath).getPath());
}
protected File file(@NotNull String relativePath) {
@@ -86,12 +86,16 @@ class StartUpPerformanceReporter : StartupActivity, DumbAware {
private fun logStats(end: Long, activationNumber: Int) {
val items = mutableListOf<Item>()
val activities = THashMap<String, MutableList<Item>>()
StartUpMeasurer.processAndClear(Consumer { item ->
if (item.name.first() == '_') {
activities.getOrPut(item.name) { mutableListOf() }.add(item)
fun addActivity(name: String) {
activities.getOrPut(name) { mutableListOf() }.add(item)
}
else {
items.add(item)
when {
item.name.first() == '_' -> addActivity(item.name)
item.level != null -> addActivity("${item.level!!.jsonFieldNamePrefix}${item.name.capitalize()}")
else -> items.add(item)
}
})
@@ -161,9 +165,10 @@ class StartUpPerformanceReporter : StartupActivity, DumbAware {
}
private fun activityNameToJsonFieldName(name: String): String {
val firstIndex = if (name.startsWith('_')) 1 else 0
return when {
name.last() == 'y' -> name.substring(1, name.length - 1) + "ies"
else -> name.substring(1) + 's'
name.last() == 'y' -> name.substring(firstIndex, name.length - 1) + "ies"
else -> name.substring(firstIndex) + 's'
}
}
@@ -41,6 +41,8 @@ import java.util.List;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import static com.intellij.util.pico.DefaultPicoContainer.getMeasureTokenLevel;
public final class ServiceManagerImpl implements Disposable {
private static final Logger LOG = Logger.getInstance(ServiceManagerImpl.class);
@@ -231,9 +233,7 @@ public final class ServiceManagerImpl implements Disposable {
@NotNull
private Object createAndInitialize(@NotNull PicoContainer container) {
// if it will be module service, then get rid of such component instead of measurement
boolean appComponent = myComponentManager instanceof Application;
StartUpMeasurer.MeasureToken measureToken = StartUpMeasurer.start(appComponent ? Activities.APP_SERVICE : Activities.PROJECT_SERVICE);
StartUpMeasurer.MeasureToken measureToken = StartUpMeasurer.start(Activities.SERVICE, getMeasureTokenLevel(container));
Object instance = getDelegate().getComponentInstance(container);
if (instance instanceof Disposable) {
Disposer.register(myComponentManager, (Disposable)instance);
@@ -348,6 +348,6 @@
<extensionPoint qualifiedName="com.intellij.search.traverseUiHelper" interface="com.intellij.ide.ui.search.TraverseUIHelper"/>
<extensionPoint name="stalledStorage" beanClass="com.intellij.configurationStore.StalledStorageBean"/>
<extensionPoint name="obsoleteStorage" beanClass="com.intellij.configurationStore.ObsoleteStorageBean"/>
</extensionPoints>
</idea-plugin>
@@ -600,28 +600,28 @@
<rawEditorTypedHandler implementationClass="com.intellij.openapi.editor.impl.EditorFactoryImpl$MyRawTypedHandler"/>
<stalledStorage file="statistics.toolbar.clicks.xml">
<obsoleteStorage file="statistics.toolbar.clicks.xml">
<components>
<component>ToolbarClicksCollector</component>
</components>
</stalledStorage>
<stalledStorage file="statistics.main_menu.xml">
</obsoleteStorage>
<obsoleteStorage file="statistics.main_menu.xml">
<components>
<component>MainMenuCollector</component>
</components>
</stalledStorage>
<stalledStorage file="statistics.shortcuts.xml">
</obsoleteStorage>
<obsoleteStorage file="statistics.shortcuts.xml">
<components>
<component>ShortcutsCollector</component>
</components>
</stalledStorage>
<stalledStorage file="statistics.application.usages.xml">
</obsoleteStorage>
<obsoleteStorage file="statistics.application.usages.xml">
<components>
<component>StatisticsApplicationUsages</component>
<component>UsageTrigger</component>
</components>
</stalledStorage>
<stalledStorage file="usage.statistics.xml">
</obsoleteStorage>
<obsoleteStorage file="usage.statistics.xml">
<components>
<component>StatisticsApplicationUsages</component>
<component>UsageTrigger</component>
@@ -634,18 +634,18 @@
<component>ActionsCollector</component>
<component>FUSApplicationUsageTrigger</component>
</components>
</stalledStorage>
</obsoleteStorage>
<stalledStorage file="usage.statistics.xml" isProjectLevel="true">
<obsoleteStorage file="usage.statistics.xml" isProjectLevel="true">
<components>
<component>FUSProjectUsageTrigger</component>
</components>
</stalledStorage>
<stalledStorage file="workspace.xml" isProjectLevel="true">
</obsoleteStorage>
<obsoleteStorage file="workspace.xml" isProjectLevel="true">
<components>
<component>FUSProjectUsageTrigger</component>
</components>
</stalledStorage>
</obsoleteStorage>
<postStartupActivity implementation="com.intellij.ide.StartUpPerformanceReporter" order="last"/>
</extensions>
@@ -42,13 +42,27 @@ public final class StartUpMeasurer {
public static final String LOAD_MODULES = "module loading";
}
// ExtensionAreas not available for ExtensionPointImpl
public enum Level {
APPLICATION("app"), PROJECT("project"), MODULE("module");
private final String jsonFieldNamePrefix;
Level(@NotNull String jsonFieldNamePrefix) {
this.jsonFieldNamePrefix = jsonFieldNamePrefix;
}
@NotNull
public String getJsonFieldNamePrefix() {
return jsonFieldNamePrefix;
}
}
// non-sequential and repeated items
public static final class Activities {
public static final String APP_COMPONENT = "_appComponent";
public static final String PROJECT_COMPONENT = "_projectComponent";
public static final String APP_SERVICE = "_appService";
public static final String PROJECT_SERVICE = "_projectService";
public static final String COMPONENT = "component";
public static final String SERVICE = "service";
public static final String EXTENSION = "extension";
public static final String PRELOAD_ACTIVITY = "_preloadActivity";
@@ -66,12 +80,17 @@ public final class StartUpMeasurer {
@NotNull
public static MeasureToken start(@NotNull String name, @Nullable String description) {
return new Item(name, description);
return new Item(name, description, null);
}
@NotNull
public static MeasureToken start(@NotNull String name) {
return new Item(name, null);
return new Item(name, null, null);
}
@NotNull
public static MeasureToken start(@NotNull String name, @NotNull Level level) {
return new Item(name, null, level);
}
public static void processAndClear(@NotNull Consumer<Item> consumer) {
@@ -95,15 +114,19 @@ public final class StartUpMeasurer {
// null doesn't mean root - not obligated to set parent, only as hint
private final Item parent;
private Item(@Nullable String name, @Nullable String description) {
this(name, description, System.nanoTime(), null);
@Nullable
private final Level myLevel;
private Item(@Nullable String name, @Nullable String description, @Nullable Level level) {
this(name, description, System.nanoTime(), null, level);
}
private Item(@Nullable String name, @Nullable String description, long start, @Nullable Item parent) {
private Item(@Nullable String name, @Nullable String description, long start, @Nullable Item parent, @Nullable Level level) {
this.name = name;
this.description = StringUtil.nullize(description);
this.start = start;
this.parent = parent;
myLevel = level;
}
@Nullable
@@ -111,12 +134,17 @@ public final class StartUpMeasurer {
return parent;
}
@Nullable
public Level getLevel() {
return myLevel;
}
// and how do we can sort correctly, when parent item equals to child (start and end) and also there is another child with start equals to end?
// so, parent added to API but as it was not enough, decided to measure time in nanoseconds instead of ms to mitigate such situations
@Override
@NotNull
public Item startChild(@NotNull String name) {
return new Item(name, null, System.nanoTime(), this);
return new Item(name, null, System.nanoTime(), this, null);
}
@NotNull
@@ -208,6 +208,13 @@ public class PluginXmlDomInspection extends BasicDomElementsInspection<IdeaPlugi
if (!hasRealPluginId(ideaPlugin)) return;
String id = ideaPlugin.getId().getStringValue();
if (id != null &&
(StringUtil.startsWith(id, "com.android.") ||
id.equals("org.jetbrains.android"))) {
return;
}
XmlTag xmlTag = ideaPlugin.getXmlTag();
if (xmlTag == null) return;
@@ -0,0 +1,5 @@
<idea-plugin>
<id>com.android.something</id>
<version>1</version>
<vendor>JB is not required due to ID</vendor>
</idea-plugin>
@@ -397,6 +397,10 @@ class PluginXmlFunctionalTest extends JavaCodeInsightFixtureTestCase {
testHighlightingInIdeaProject("pluginWithJetBrainsAndMeAsVendor.xml")
}
void testPluginXmlInIdeaProjectWithAndroidId() {
testHighlightingInIdeaProject("pluginWithAndroidIdVendor.xml")
}
void testSpecifyJetBrainsAsVendorQuickFix() {
PsiUtil.markAsIdeaProject(project, true)
try {
@@ -1,9 +1,9 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.devkit.inspections.missingApi
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.devkit.kotlin.inspections.missingApi
import com.intellij.testFramework.TestDataPath
import org.jetbrains.idea.devkit.inspections.missingApi.project.PluginProjectWithIdeaJdkDescriptor
import org.jetbrains.idea.devkit.inspections.missingApi.project.PluginProjectWithIdeaLibraryDescriptor
import org.jetbrains.idea.devkit.kotlin.inspections.missingApi.project.PluginProjectWithIdeaJdkDescriptor
import org.jetbrains.idea.devkit.kotlin.inspections.missingApi.project.PluginProjectWithIdeaLibraryDescriptor
@TestDataPath("\$CONTENT_ROOT/testData/inspections/missingApi")
abstract class JavaMissingRecentApiInspectionTestBase : MissingRecentApiInspectionTestBase() {
@@ -1,9 +1,8 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.devkit.kotlin.inspections.missingApi
import org.jetbrains.idea.devkit.inspections.missingApi.MissingRecentApiInspectionTestBase
import org.jetbrains.idea.devkit.inspections.missingApi.project.PluginProjectWithIdeaJdkDescriptor
import org.jetbrains.idea.devkit.inspections.missingApi.project.PluginProjectWithIdeaLibraryDescriptor
import org.jetbrains.idea.devkit.kotlin.inspections.missingApi.project.PluginProjectWithIdeaJdkDescriptor
import org.jetbrains.idea.devkit.kotlin.inspections.missingApi.project.PluginProjectWithIdeaLibraryDescriptor
abstract class KotlinMissingRecentApiInspectionTestBase : MissingRecentApiInspectionTestBase() {
@@ -1,5 +1,5 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.devkit.inspections.missingApi
package org.jetbrains.idea.devkit.kotlin.inspections.missingApi
import com.intellij.codeInsight.AnnotationUtil
import com.intellij.openapi.roots.JavaModuleExternalPaths
@@ -9,8 +9,10 @@ import com.intellij.psi.search.GlobalSearchScope
import com.intellij.testFramework.TestDataPath
import org.jetbrains.idea.devkit.DevkitJavaTestsUtil
import org.jetbrains.idea.devkit.inspections.PluginModuleTestCase
import org.jetbrains.idea.devkit.inspections.missingApi.project.PluginProjectWithIdeaJdkDescriptor
import org.jetbrains.idea.devkit.inspections.missingApi.project.PluginProjectWithIdeaLibraryDescriptor
import org.jetbrains.idea.devkit.inspections.missingApi.MissingRecentApiInspection
import org.jetbrains.idea.devkit.inspections.missingApi.MissingRecentApiVisitor
import org.jetbrains.idea.devkit.kotlin.inspections.missingApi.project.PluginProjectWithIdeaJdkDescriptor
import org.jetbrains.idea.devkit.kotlin.inspections.missingApi.project.PluginProjectWithIdeaLibraryDescriptor
/**
* Base class for tests of [MissingRecentApiInspection] on Java and Kotlin sources.
@@ -1,5 +1,5 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.devkit.inspections.missingApi.project
package org.jetbrains.idea.devkit.kotlin.inspections.missingApi.project
import com.intellij.openapi.application.PathManager
import com.intellij.openapi.application.runWriteAction
@@ -1,5 +1,5 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.devkit.inspections.missingApi.project
package org.jetbrains.idea.devkit.kotlin.inspections.missingApi.project
import com.intellij.openapi.application.PathManager
import com.intellij.openapi.application.runReadAction