Do not invalidate package caches on generic events, KT-25264
This commit is contained in:
@@ -924,7 +924,7 @@ fun main(args: Array<String>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
testClass<AbstractCompletionCharFilterTest> {
|
testClass<AbstractCompletionCharFilterTest> {
|
||||||
model("handlers/charFilter")
|
model("handlers/charFilter", pattern = KT_WITHOUT_DOTS_IN_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
testClass<AbstractMultiFileJvmBasicCompletionTest> {
|
testClass<AbstractMultiFileJvmBasicCompletionTest> {
|
||||||
@@ -1219,7 +1219,7 @@ fun main(args: Array<String>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
testClass<AbstractPerformanceCompletionCharFilterTest> {
|
testClass<AbstractPerformanceCompletionCharFilterTest> {
|
||||||
model("handlers/charFilter", testMethod = "doPerfTest")
|
model("handlers/charFilter", testMethod = "doPerfTest", pattern = KT_WITHOUT_DOTS_IN_NAME)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
|||||||
+14
-17
@@ -6,7 +6,6 @@
|
|||||||
package org.jetbrains.kotlin.idea.caches
|
package org.jetbrains.kotlin.idea.caches
|
||||||
|
|
||||||
import com.intellij.ProjectTopics
|
import com.intellij.ProjectTopics
|
||||||
import com.intellij.openapi.Disposable
|
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
import com.intellij.openapi.components.ServiceManager
|
import com.intellij.openapi.components.ServiceManager
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
@@ -87,7 +86,7 @@ class KotlinPackageContentModificationListener(private val project: Project) {
|
|||||||
class KotlinPackageStatementPsiTreeChangePreprocessor(private val project: Project) : PsiTreeChangePreprocessor {
|
class KotlinPackageStatementPsiTreeChangePreprocessor(private val project: Project) : PsiTreeChangePreprocessor {
|
||||||
override fun treeChanged(event: PsiTreeChangeEventImpl) {
|
override fun treeChanged(event: PsiTreeChangeEventImpl) {
|
||||||
val eFile = event.file ?: event.child as? PsiFile
|
val eFile = event.file ?: event.child as? PsiFile
|
||||||
if (eFile == null) LOG.debugIfEnabled(project, "Got PsiEvent: $event without file", true)
|
if (eFile == null) LOG.debugIfEnabled(project, true) { "Got PsiEvent: $event without file" }
|
||||||
val file = eFile as? KtFile ?: return
|
val file = eFile as? KtFile ?: return
|
||||||
|
|
||||||
when (event.code) {
|
when (event.code) {
|
||||||
@@ -96,7 +95,7 @@ class KotlinPackageStatementPsiTreeChangePreprocessor(private val project: Proje
|
|||||||
PsiTreeChangeEventImpl.PsiEventType.CHILD_REPLACED,
|
PsiTreeChangeEventImpl.PsiEventType.CHILD_REPLACED,
|
||||||
PsiTreeChangeEventImpl.PsiEventType.CHILD_REMOVED -> {
|
PsiTreeChangeEventImpl.PsiEventType.CHILD_REMOVED -> {
|
||||||
val child = event.child ?: run {
|
val child = event.child ?: run {
|
||||||
LOG.debugIfEnabled(project, "Got PsiEvent: $event without child", true)
|
LOG.debugIfEnabled(project, true) { "Got PsiEvent: $event without child" }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (child.getParentOfType<KtPackageDirective>(false) != null)
|
if (child.getParentOfType<KtPackageDirective>(false) != null)
|
||||||
@@ -104,10 +103,10 @@ class KotlinPackageStatementPsiTreeChangePreprocessor(private val project: Proje
|
|||||||
}
|
}
|
||||||
PsiTreeChangeEventImpl.PsiEventType.CHILDREN_CHANGED -> {
|
PsiTreeChangeEventImpl.PsiEventType.CHILDREN_CHANGED -> {
|
||||||
val parent = event.parent ?: run {
|
val parent = event.parent ?: run {
|
||||||
LOG.debugIfEnabled(project, "Got PsiEvent: $event without parent", true)
|
LOG.debugIfEnabled(project, true) { "Got PsiEvent: $event without parent" }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (parent.getChildrenOfType<KtPackageDirective>().any())
|
if (!event.isGenericChange && (parent.getChildrenOfType<KtPackageDirective>().any() || parent is KtPackageDirective))
|
||||||
ServiceManager.getService(project, PerModulePackageCacheService::class.java).notifyPackageChange(file)
|
ServiceManager.getService(project, PerModulePackageCacheService::class.java).notifyPackageChange(file)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
@@ -244,7 +243,7 @@ class PerModulePackageCacheService(private val project: Project) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun invalidateCacheForModuleSourceInfo(moduleSourceInfo: ModuleSourceInfo) {
|
private fun invalidateCacheForModuleSourceInfo(moduleSourceInfo: ModuleSourceInfo) {
|
||||||
LOG.debugIfEnabled(project, "Invalidated cache for $moduleSourceInfo", false)
|
LOG.debugIfEnabled(project) { "Invalidated cache for $moduleSourceInfo" }
|
||||||
val perSourceInfoData = cache[moduleSourceInfo.module] ?: return
|
val perSourceInfoData = cache[moduleSourceInfo.module] ?: return
|
||||||
val dataForSourceInfo = perSourceInfoData[moduleSourceInfo] ?: return
|
val dataForSourceInfo = perSourceInfoData[moduleSourceInfo] ?: return
|
||||||
dataForSourceInfo.clear()
|
dataForSourceInfo.clear()
|
||||||
@@ -264,14 +263,14 @@ class PerModulePackageCacheService(private val project: Project) {
|
|||||||
if (sourceRootUrls.any { url ->
|
if (sourceRootUrls.any { url ->
|
||||||
vfile.containedInOrContains(url)
|
vfile.containedInOrContains(url)
|
||||||
}) {
|
}) {
|
||||||
LOG.debugIfEnabled(project, "Invalidated cache for $module")
|
LOG.debugIfEnabled(project) { "Invalidated cache for $module" }
|
||||||
data.clear()
|
data.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val infoByVirtualFile = getModuleInfoByVirtualFile(project, vfile)
|
val infoByVirtualFile = getModuleInfoByVirtualFile(project, vfile)
|
||||||
if (infoByVirtualFile == null || infoByVirtualFile !is ModuleSourceInfo) {
|
if (infoByVirtualFile == null || infoByVirtualFile !is ModuleSourceInfo) {
|
||||||
LOG.debugIfEnabled(project, "Skip $vfile as it has mismatched ModuleInfo=$infoByVirtualFile")
|
LOG.debugIfEnabled(project) { "Skip $vfile as it has mismatched ModuleInfo=$infoByVirtualFile" }
|
||||||
}
|
}
|
||||||
(infoByVirtualFile as? ModuleSourceInfo)?.let {
|
(infoByVirtualFile as? ModuleSourceInfo)?.let {
|
||||||
invalidateCacheForModuleSourceInfo(it)
|
invalidateCacheForModuleSourceInfo(it)
|
||||||
@@ -283,13 +282,13 @@ class PerModulePackageCacheService(private val project: Project) {
|
|||||||
|
|
||||||
pendingKtFileChanges.processPending { file ->
|
pendingKtFileChanges.processPending { file ->
|
||||||
if (file.virtualFile != null && file.virtualFile !in projectScope) {
|
if (file.virtualFile != null && file.virtualFile !in projectScope) {
|
||||||
LOG.debugIfEnabled(project, "Skip $file without vFile, or not in scope: ${file.virtualFile?.let { it !in projectScope }}")
|
LOG.debugIfEnabled(project) { "Skip $file without vFile, or not in scope: ${file.virtualFile?.let { it !in projectScope }}" }
|
||||||
return@processPending
|
return@processPending
|
||||||
}
|
}
|
||||||
val nullableModuleInfo = file.getNullableModuleInfo()
|
val nullableModuleInfo = file.getNullableModuleInfo()
|
||||||
(nullableModuleInfo as? ModuleSourceInfo)?.let { invalidateCacheForModuleSourceInfo(it) }
|
(nullableModuleInfo as? ModuleSourceInfo)?.let { invalidateCacheForModuleSourceInfo(it) }
|
||||||
if (nullableModuleInfo == null || nullableModuleInfo !is ModuleSourceInfo) {
|
if (nullableModuleInfo == null || nullableModuleInfo !is ModuleSourceInfo) {
|
||||||
LOG.debugIfEnabled(project, "Skip $file as it has mismatched ModuleInfo=$nullableModuleInfo")
|
LOG.debugIfEnabled(project) { "Skip $file as it has mismatched ModuleInfo=$nullableModuleInfo" }
|
||||||
}
|
}
|
||||||
implicitPackagePrefixCache.update(file)
|
implicitPackagePrefixCache.update(file)
|
||||||
}
|
}
|
||||||
@@ -329,7 +328,7 @@ class PerModulePackageCacheService(private val project: Project) {
|
|||||||
|
|
||||||
return cacheForCurrentModuleInfo.getOrPut(packageFqName) {
|
return cacheForCurrentModuleInfo.getOrPut(packageFqName) {
|
||||||
val packageExists = PackageIndexUtil.packageExists(packageFqName, moduleInfo.contentScope(), project)
|
val packageExists = PackageIndexUtil.packageExists(packageFqName, moduleInfo.contentScope(), project)
|
||||||
LOG.debugIfEnabled(project, "Computed cache value for $packageFqName in $moduleInfo is $packageExists")
|
LOG.debugIfEnabled(project) { "Computed cache value for $packageFqName in $moduleInfo is $packageExists" }
|
||||||
packageExists
|
packageExists
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -351,16 +350,14 @@ class PerModulePackageCacheService(private val project: Project) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Logger.debugIfEnabled(project: Project, withCurrentTrace: Boolean = false, message: () -> String) {
|
||||||
|
|
||||||
|
|
||||||
private fun Logger.debugIfEnabled(project: Project, message: String, withCurrentTrace: Boolean = false) {
|
|
||||||
if (ApplicationManager.getApplication().isUnitTestMode && project.DEBUG_LOG_ENABLE_PerModulePackageCache) {
|
if (ApplicationManager.getApplication().isUnitTestMode && project.DEBUG_LOG_ENABLE_PerModulePackageCache) {
|
||||||
|
val msg = message()
|
||||||
if (withCurrentTrace) {
|
if (withCurrentTrace) {
|
||||||
val e = Exception().apply { fillInStackTrace() }
|
val e = Exception().apply { fillInStackTrace() }
|
||||||
this.debug(message, e)
|
this.debug(msg, e)
|
||||||
} else {
|
} else {
|
||||||
this.debug(message)
|
this.debug(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
package org.jetbrains.annotations
|
||||||
|
|
||||||
|
@Retention(AnnotationRetention.BINARY)
|
||||||
|
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.LOCAL_VARIABLE, AnnotationTarget.FIELD)
|
||||||
|
public annotation class PropertyKey(public val resourceBundle: String)
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
foobar = 0
|
||||||
|
foo.bar = 1
|
||||||
|
bar.baz = 2
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import org.jetbrains.annotations.PropertyKey
|
||||||
|
|
||||||
|
fun message(@PropertyKey(resourceBundle = "MessageBundle1.dependency") key: String) = key
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
message("<caret>")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ELEMENT: foo.bar
|
||||||
|
// CHARS: 'foo\n'
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import org.jetbrains.annotations.PropertyKey
|
||||||
|
|
||||||
|
fun message(@PropertyKey(resourceBundle = "MessageBundle1.dependency") key: String) = key
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
message("foo.bar")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ELEMENT: foo.bar
|
||||||
|
// CHARS: 'foo\n'
|
||||||
+14
-7
@@ -24,6 +24,7 @@ abstract class AbstractCompletionHandlerTest(private val defaultCompletionType:
|
|||||||
private val ELEMENT_TEXT_PREFIX = "ELEMENT_TEXT:"
|
private val ELEMENT_TEXT_PREFIX = "ELEMENT_TEXT:"
|
||||||
private val TAIL_TEXT_PREFIX = "TAIL_TEXT:"
|
private val TAIL_TEXT_PREFIX = "TAIL_TEXT:"
|
||||||
private val COMPLETION_CHAR_PREFIX = "CHAR:"
|
private val COMPLETION_CHAR_PREFIX = "CHAR:"
|
||||||
|
private val COMPLETION_CHARS_PREFIX = "CHARS:"
|
||||||
private val CODE_STYLE_SETTING_PREFIX = "CODE_STYLE_SETTING:"
|
private val CODE_STYLE_SETTING_PREFIX = "CODE_STYLE_SETTING:"
|
||||||
|
|
||||||
protected open fun doTest(testPath: String) {
|
protected open fun doTest(testPath: String) {
|
||||||
@@ -42,12 +43,10 @@ abstract class AbstractCompletionHandlerTest(private val defaultCompletionType:
|
|||||||
val itemText = InTextDirectivesUtils.findStringWithPrefixes(fileText, ELEMENT_TEXT_PREFIX)
|
val itemText = InTextDirectivesUtils.findStringWithPrefixes(fileText, ELEMENT_TEXT_PREFIX)
|
||||||
val tailText = InTextDirectivesUtils.findStringWithPrefixes(fileText, TAIL_TEXT_PREFIX)
|
val tailText = InTextDirectivesUtils.findStringWithPrefixes(fileText, TAIL_TEXT_PREFIX)
|
||||||
|
|
||||||
val completionCharString = InTextDirectivesUtils.findStringWithPrefixes(fileText, COMPLETION_CHAR_PREFIX)
|
val completionChars = completionChars(
|
||||||
val completionChar = when(completionCharString) {
|
char = InTextDirectivesUtils.findStringWithPrefixes(fileText, COMPLETION_CHAR_PREFIX),
|
||||||
"\\n", null -> '\n'
|
chars = InTextDirectivesUtils.findStringWithPrefixes(fileText, COMPLETION_CHARS_PREFIX)
|
||||||
"\\t" -> '\t'
|
)
|
||||||
else -> completionCharString.singleOrNull() ?: error("Incorrect completion char: \"$completionCharString\"")
|
|
||||||
}
|
|
||||||
|
|
||||||
val completionType = ExpectedCompletionUtils.getCompletionType(fileText) ?: defaultCompletionType
|
val completionType = ExpectedCompletionUtils.getCompletionType(fileText) ?: defaultCompletionType
|
||||||
|
|
||||||
@@ -70,7 +69,15 @@ abstract class AbstractCompletionHandlerTest(private val defaultCompletionType:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
doTestWithTextLoaded(completionType, invocationCount, lookupString, itemText, tailText, completionChar, File(testPath).name + ".after")
|
doTestWithTextLoaded(
|
||||||
|
completionType,
|
||||||
|
invocationCount,
|
||||||
|
lookupString,
|
||||||
|
itemText,
|
||||||
|
tailText,
|
||||||
|
completionChars,
|
||||||
|
File(testPath).name + ".after"
|
||||||
|
)
|
||||||
} finally {
|
} finally {
|
||||||
if (configured) {
|
if (configured) {
|
||||||
rollbackCompilerOptions(project, module)
|
rollbackCompilerOptions(project, module)
|
||||||
|
|||||||
+1
-1
@@ -31,7 +31,7 @@ class BasicCompletionHandlerTest : CompletionHandlerTestBase(){
|
|||||||
|
|
||||||
private fun doTest(time: Int, lookupString: String?, itemText: String?, tailText: String?, completionChar: Char) {
|
private fun doTest(time: Int, lookupString: String?, itemText: String?, tailText: String?, completionChar: Char) {
|
||||||
fixture.configureByFile(fileName())
|
fixture.configureByFile(fileName())
|
||||||
doTestWithTextLoaded(CompletionType.BASIC, time, lookupString, itemText, tailText, completionChar, fileName() + ".after")
|
doTestWithTextLoaded(CompletionType.BASIC, time, lookupString, itemText, tailText, completionChar.toString(), fileName() + ".after")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testClassCompletionImport() = doTest(2, "SortedSet", null, '\n')
|
fun testClassCompletionImport() = doTest(2, "SortedSet", null, '\n')
|
||||||
|
|||||||
+6
-1
@@ -26,7 +26,7 @@ public class CompletionCharFilterTestGenerated extends AbstractCompletionCharFil
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testAllFilesPresentInCharFilter() throws Exception {
|
public void testAllFilesPresentInCharFilter() throws Exception {
|
||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/handlers/charFilter"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/handlers/charFilter"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("Colon.kt")
|
@TestMetadata("Colon.kt")
|
||||||
@@ -144,6 +144,11 @@ public class CompletionCharFilterTestGenerated extends AbstractCompletionCharFil
|
|||||||
runTest("idea/idea-completion/testData/handlers/charFilter/LParenth.kt");
|
runTest("idea/idea-completion/testData/handlers/charFilter/LParenth.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("MessageBundle1.kt")
|
||||||
|
public void testMessageBundle1() throws Exception {
|
||||||
|
runTest("idea/idea-completion/testData/handlers/charFilter/MessageBundle1.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("NamedParameter1.kt")
|
@TestMetadata("NamedParameter1.kt")
|
||||||
public void testNamedParameter1() throws Exception {
|
public void testNamedParameter1() throws Exception {
|
||||||
runTest("idea/idea-completion/testData/handlers/charFilter/NamedParameter1.kt");
|
runTest("idea/idea-completion/testData/handlers/charFilter/NamedParameter1.kt");
|
||||||
|
|||||||
+23
-9
@@ -20,26 +20,40 @@ abstract class CompletionHandlerTestBase() : KotlinLightCodeInsightFixtureTestCa
|
|||||||
get() = myFixture
|
get() = myFixture
|
||||||
|
|
||||||
protected fun doTestWithTextLoaded(
|
protected fun doTestWithTextLoaded(
|
||||||
completionType: CompletionType,
|
completionType: CompletionType,
|
||||||
time: Int,
|
time: Int,
|
||||||
lookupString: String?,
|
lookupString: String?,
|
||||||
itemText: String?,
|
itemText: String?,
|
||||||
tailText: String?,
|
tailText: String?,
|
||||||
completionChar: Char,
|
completionChars: String,
|
||||||
afterFilePath: String
|
afterFilePath: String
|
||||||
) {
|
) {
|
||||||
|
for (idx in 0 until completionChars.length - 1) {
|
||||||
|
fixture.type(completionChars[idx])
|
||||||
|
}
|
||||||
|
|
||||||
fixture.complete(completionType, time)
|
fixture.complete(completionType, time)
|
||||||
|
|
||||||
if (lookupString != null || itemText != null || tailText != null) {
|
if (lookupString != null || itemText != null || tailText != null) {
|
||||||
val item = getExistentLookupElement(lookupString, itemText, tailText)
|
val item = getExistentLookupElement(lookupString, itemText, tailText)
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
selectItem(item, completionChar)
|
selectItem(item, completionChars.last())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fixture.checkResultByFile(afterFilePath)
|
fixture.checkResultByFile(afterFilePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fun completionChars(char: String?, chars: String?): String =
|
||||||
|
when (char) {
|
||||||
|
null -> when (chars) {
|
||||||
|
null -> "\n"
|
||||||
|
else -> chars.replace("\\n", "\n").replace("\\t", "\t")
|
||||||
|
}
|
||||||
|
"\\n" -> "\n"
|
||||||
|
"\\t" -> "\t"
|
||||||
|
else -> char.single().toString() ?: error("Incorrect completion char: \"$char\"")
|
||||||
|
}
|
||||||
|
|
||||||
protected fun getExistentLookupElement(lookupString: String?, itemText: String?, tailText: String?): LookupElement? {
|
protected fun getExistentLookupElement(lookupString: String?, itemText: String?, tailText: String?): LookupElement? {
|
||||||
val lookup = LookupManager.getInstance(project)?.activeLookup as LookupImpl? ?: return null
|
val lookup = LookupManager.getInstance(project)?.activeLookup as LookupImpl? ?: return null
|
||||||
val items = lookup.items
|
val items = lookup.items
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ fun CodeInsightTestFixture.configureWithExtraFile(path: String, vararg extraName
|
|||||||
val fileName = File(path).name
|
val fileName = File(path).name
|
||||||
|
|
||||||
val noExtensionPath = FileUtil.getNameWithoutExtension(fileName)
|
val noExtensionPath = FileUtil.getNameWithoutExtension(fileName)
|
||||||
val extensions = arrayOf("kt", "java")
|
val extensions = arrayOf("kt", "java", "properties")
|
||||||
val extraPaths: List<String> = extraNameParts
|
val extraPaths: List<String> = extraNameParts
|
||||||
.flatMap { extensions.map { ext -> "$noExtensionPath$it.$ext" } }
|
.flatMap { extensions.map { ext -> "$noExtensionPath$it.$ext" } }
|
||||||
.mapNotNull { File(testDataPath, it).takeIf { it.exists() }?.name }
|
.mapNotNull { File(testDataPath, it).takeIf { it.exists() }?.name }
|
||||||
|
|||||||
+17
-12
@@ -22,7 +22,7 @@ import org.junit.AfterClass
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* inspired by @see AbstractCompletionHandlerTest
|
* inspired by @see AbstractCompletionHandlerTests
|
||||||
*/
|
*/
|
||||||
abstract class AbstractPerformanceCompletionHandlerTests(
|
abstract class AbstractPerformanceCompletionHandlerTests(
|
||||||
private val defaultCompletionType: CompletionType,
|
private val defaultCompletionType: CompletionType,
|
||||||
@@ -34,6 +34,7 @@ abstract class AbstractPerformanceCompletionHandlerTests(
|
|||||||
private val ELEMENT_TEXT_PREFIX = "ELEMENT_TEXT:"
|
private val ELEMENT_TEXT_PREFIX = "ELEMENT_TEXT:"
|
||||||
private val TAIL_TEXT_PREFIX = "TAIL_TEXT:"
|
private val TAIL_TEXT_PREFIX = "TAIL_TEXT:"
|
||||||
private val COMPLETION_CHAR_PREFIX = "CHAR:"
|
private val COMPLETION_CHAR_PREFIX = "CHAR:"
|
||||||
|
private val COMPLETION_CHARS_PREFIX = "CHARS:"
|
||||||
private val CODE_STYLE_SETTING_PREFIX = "CODE_STYLE_SETTING:"
|
private val CODE_STYLE_SETTING_PREFIX = "CODE_STYLE_SETTING:"
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -74,12 +75,10 @@ abstract class AbstractPerformanceCompletionHandlerTests(
|
|||||||
val itemText = InTextDirectivesUtils.findStringWithPrefixes(fileText, ELEMENT_TEXT_PREFIX)
|
val itemText = InTextDirectivesUtils.findStringWithPrefixes(fileText, ELEMENT_TEXT_PREFIX)
|
||||||
val tailText = InTextDirectivesUtils.findStringWithPrefixes(fileText, TAIL_TEXT_PREFIX)
|
val tailText = InTextDirectivesUtils.findStringWithPrefixes(fileText, TAIL_TEXT_PREFIX)
|
||||||
|
|
||||||
val completionCharString = InTextDirectivesUtils.findStringWithPrefixes(fileText, COMPLETION_CHAR_PREFIX)
|
val completionChars = completionChars(
|
||||||
val completionChar = when(completionCharString) {
|
char = InTextDirectivesUtils.findStringWithPrefixes(fileText, COMPLETION_CHAR_PREFIX),
|
||||||
"\\n", null -> '\n'
|
chars = InTextDirectivesUtils.findStringWithPrefixes(fileText, COMPLETION_CHARS_PREFIX)
|
||||||
"\\t" -> '\t'
|
)
|
||||||
else -> completionCharString.singleOrNull() ?: error("Incorrect completion char: \"$completionCharString\"")
|
|
||||||
}
|
|
||||||
|
|
||||||
val completionType = ExpectedCompletionUtils.getCompletionType(fileText) ?: defaultCompletionType
|
val completionType = ExpectedCompletionUtils.getCompletionType(fileText) ?: defaultCompletionType
|
||||||
|
|
||||||
@@ -102,7 +101,7 @@ abstract class AbstractPerformanceCompletionHandlerTests(
|
|||||||
}
|
}
|
||||||
|
|
||||||
doPerfTestWithTextLoaded(
|
doPerfTestWithTextLoaded(
|
||||||
testPath, completionType, invocationCount, lookupString, itemText, tailText, completionChar
|
testPath, completionType, invocationCount, lookupString, itemText, tailText, completionChars
|
||||||
)
|
)
|
||||||
} finally {
|
} finally {
|
||||||
if (configured) {
|
if (configured) {
|
||||||
@@ -120,7 +119,7 @@ abstract class AbstractPerformanceCompletionHandlerTests(
|
|||||||
lookupString: String?,
|
lookupString: String?,
|
||||||
itemText: String?,
|
itemText: String?,
|
||||||
tailText: String?,
|
tailText: String?,
|
||||||
completionChar: Char
|
completionChars: String
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val testName = getTestName(false)
|
val testName = getTestName(false)
|
||||||
@@ -132,7 +131,7 @@ abstract class AbstractPerformanceCompletionHandlerTests(
|
|||||||
setUpFixture(testPath)
|
setUpFixture(testPath)
|
||||||
},
|
},
|
||||||
test = {
|
test = {
|
||||||
perfTestCore(completionType, time, lookupString, itemText, tailText, completionChar)
|
perfTestCore(completionType, time, lookupString, itemText, tailText, completionChars)
|
||||||
},
|
},
|
||||||
tearDown = {
|
tearDown = {
|
||||||
runWriteAction {
|
runWriteAction {
|
||||||
@@ -147,14 +146,20 @@ abstract class AbstractPerformanceCompletionHandlerTests(
|
|||||||
lookupString: String?,
|
lookupString: String?,
|
||||||
itemText: String?,
|
itemText: String?,
|
||||||
tailText: String?,
|
tailText: String?,
|
||||||
completionChar: Char
|
completionChars: String
|
||||||
) {
|
) {
|
||||||
|
completionChars?.let {
|
||||||
|
for (idx in 0 until it.length - 1) {
|
||||||
|
fixture.type(it[idx])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fixture.complete(completionType, time)
|
fixture.complete(completionType, time)
|
||||||
|
|
||||||
if (lookupString != null || itemText != null || tailText != null) {
|
if (lookupString != null || itemText != null || tailText != null) {
|
||||||
val item = getExistentLookupElement(lookupString, itemText, tailText)
|
val item = getExistentLookupElement(lookupString, itemText, tailText)
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
selectItem(item, completionChar)
|
selectItem(item, completionChars.last())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-5
@@ -103,6 +103,16 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fun warmUpProject(stats: Stats) {
|
||||||
|
val project = innerPerfOpenProject("helloKotlin", stats, "warm-up")
|
||||||
|
try {
|
||||||
|
val perfHighlightFile = perfHighlightFile(project, "src/HelloMain.kt", stats, "warm-up")
|
||||||
|
assertTrue("kotlin project has been not imported properly", perfHighlightFile.isNotEmpty())
|
||||||
|
} finally {
|
||||||
|
closeProject(project)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun tearDown() {
|
override fun tearDown() {
|
||||||
RunAll(
|
RunAll(
|
||||||
ThrowableRunnable { super.tearDown() },
|
ThrowableRunnable { super.tearDown() },
|
||||||
@@ -122,6 +132,9 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
|||||||
return if (lastIndexOf >= 0) fileName.substring(lastIndexOf + 1) else fileName
|
return if (lastIndexOf >= 0) fileName.substring(lastIndexOf + 1) else fileName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fun perfOpenKotlinProject(stats: Stats) =
|
||||||
|
perfOpenProject("perfTestProject", stats = stats, path = "..")
|
||||||
|
|
||||||
protected fun perfOpenProject(name: String, stats: Stats, path: String = "idea/testData/perfTest") {
|
protected fun perfOpenProject(name: String, stats: Stats, path: String = "idea/testData/perfTest") {
|
||||||
myProject = innerPerfOpenProject(name, stats, path = path, note = "")
|
myProject = innerPerfOpenProject(name, stats, path = path, note = "")
|
||||||
}
|
}
|
||||||
@@ -291,8 +304,8 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
|||||||
stats: Stats,
|
stats: Stats,
|
||||||
note: String = ""
|
note: String = ""
|
||||||
): List<HighlightInfo> {
|
): List<HighlightInfo> {
|
||||||
var highlightInfos: List<HighlightInfo> = emptyList()
|
return highlightFile {
|
||||||
IdentifierHighlighterPassFactory.doWithHighlightingEnabled {
|
var highlightInfos: List<HighlightInfo> = emptyList()
|
||||||
stats.perfTest<EditorFile, List<HighlightInfo>>(
|
stats.perfTest<EditorFile, List<HighlightInfo>>(
|
||||||
testName = "highlighting ${if (note.isNotEmpty()) "$note " else ""}${simpleFilename(fileName)}",
|
testName = "highlighting ${if (note.isNotEmpty()) "$note " else ""}${simpleFilename(fileName)}",
|
||||||
setUp = {
|
setUp = {
|
||||||
@@ -309,9 +322,21 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
|||||||
PsiManager.getInstance(project).dropPsiCaches()
|
PsiManager.getInstance(project).dropPsiCaches()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
highlightInfos
|
||||||
}
|
}
|
||||||
//println("${"-".repeat(40)}\n$fileName ->\n${highlightInfos.joinToString("\n")}\n")
|
}
|
||||||
|
|
||||||
|
fun highlightFile(psiFile: PsiFile): List<HighlightInfo> {
|
||||||
|
return highlightFile {
|
||||||
|
highlightFile(myProject!!, psiFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun highlightFile(block: () -> List<HighlightInfo>): List<HighlightInfo> {
|
||||||
|
var highlightInfos: List<HighlightInfo> = emptyList()
|
||||||
|
IdentifierHighlighterPassFactory.doWithHighlightingEnabled {
|
||||||
|
highlightInfos = block()
|
||||||
|
}
|
||||||
return highlightInfos
|
return highlightInfos
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,7 +417,7 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun openFileInEditor(project: Project, name: String): EditorFile {
|
fun openFileInEditor(project: Project, name: String): EditorFile {
|
||||||
val fileDocumentManager = FileDocumentManager.getInstance()
|
val fileDocumentManager = FileDocumentManager.getInstance()
|
||||||
val fileEditorManager = FileEditorManager.getInstance(project)
|
val fileEditorManager = FileEditorManager.getInstance(project)
|
||||||
|
|
||||||
@@ -421,6 +446,6 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
|||||||
return virtualFile!!.toPsiFile(project)!!
|
return virtualFile!!.toPsiFile(project)!!
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class EditorFile(val psiFile: PsiFile, val document: Document)
|
data class EditorFile(val psiFile: PsiFile, val document: Document)
|
||||||
|
|
||||||
}
|
}
|
||||||
+6
-1
@@ -26,7 +26,7 @@ public class PerformanceCompletionCharFilterTestGenerated extends AbstractPerfor
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testAllFilesPresentInCharFilter() throws Exception {
|
public void testAllFilesPresentInCharFilter() throws Exception {
|
||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/handlers/charFilter"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/handlers/charFilter"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("Colon.kt")
|
@TestMetadata("Colon.kt")
|
||||||
@@ -144,6 +144,11 @@ public class PerformanceCompletionCharFilterTestGenerated extends AbstractPerfor
|
|||||||
runTest("idea/idea-completion/testData/handlers/charFilter/LParenth.kt");
|
runTest("idea/idea-completion/testData/handlers/charFilter/LParenth.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("MessageBundle1.kt")
|
||||||
|
public void testMessageBundle1() throws Exception {
|
||||||
|
runTest("idea/idea-completion/testData/handlers/charFilter/MessageBundle1.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("NamedParameter1.kt")
|
@TestMetadata("NamedParameter1.kt")
|
||||||
public void testNamedParameter1() throws Exception {
|
public void testNamedParameter1() throws Exception {
|
||||||
runTest("idea/idea-completion/testData/handlers/charFilter/NamedParameter1.kt");
|
runTest("idea/idea-completion/testData/handlers/charFilter/NamedParameter1.kt");
|
||||||
|
|||||||
@@ -35,10 +35,7 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() {
|
|||||||
super.setUp()
|
super.setUp()
|
||||||
// warm up: open simple small project
|
// warm up: open simple small project
|
||||||
if (!warmedUp) {
|
if (!warmedUp) {
|
||||||
val project = innerPerfOpenProject("helloKotlin", hwStats, "warm-up")
|
warmUpProject(hwStats)
|
||||||
val perfHighlightFile = perfHighlightFile(project, "src/HelloMain.kt", hwStats, "warm-up")
|
|
||||||
assertTrue("kotlin project has been not imported properly", perfHighlightFile.isNotEmpty())
|
|
||||||
closeProject(project)
|
|
||||||
|
|
||||||
warmedUp = true
|
warmedUp = true
|
||||||
}
|
}
|
||||||
@@ -58,7 +55,7 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() {
|
|||||||
tcSuite("Kotlin project") {
|
tcSuite("Kotlin project") {
|
||||||
val stats = Stats("kotlin project")
|
val stats = Stats("kotlin project")
|
||||||
stats.use {
|
stats.use {
|
||||||
perfOpenProject("perfTestProject", stats = it, path = "..")
|
perfOpenKotlinProject(it)
|
||||||
|
|
||||||
perfHighlightFile("compiler/psi/src/org/jetbrains/kotlin/psi/KtFile.kt", stats = it)
|
perfHighlightFile("compiler/psi/src/org/jetbrains/kotlin/psi/KtFile.kt", stats = it)
|
||||||
|
|
||||||
@@ -71,7 +68,7 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() {
|
|||||||
tcSuite("Kotlin project highlight build gradle") {
|
tcSuite("Kotlin project highlight build gradle") {
|
||||||
val stats = Stats("kotlin project highlight build gradle")
|
val stats = Stats("kotlin project highlight build gradle")
|
||||||
stats.use {
|
stats.use {
|
||||||
perfOpenProject("perfTestProject", stats = it, path = "..")
|
perfOpenKotlinProject(it)
|
||||||
|
|
||||||
enableAnnotatorsAndLoadDefinitions()
|
enableAnnotatorsAndLoadDefinitions()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user