From 2ca163a37513d5264e9e38416e04519a3d99f170 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Sun, 28 Aug 2016 01:25:37 +0300 Subject: [PATCH] Better testing via logging of performed operations --- .../destructuringDeclarationUsages.kt | 66 +++++++++++++++++-- .../handlers/KotlinFindMemberUsagesHandler.kt | 7 +- .../componentFunForGenericType1.log | 7 ++ .../componentFunForGenericType2.log | 9 +++ .../conventions/components/dataClass.log | 53 +++++++++++++++ .../components/dataClassComponentByRef.log | 5 ++ .../components/dataClassFromStdlib.log | 1 + .../components/extensionComponentFun.log | 10 +++ .../components/memberComponentFun.log | 11 ++++ ...kotlinComponentFunctionParameterUsages.log | 4 ++ .../findUsages/AbstractFindUsagesTest.java | 26 ++++++-- 11 files changed, 185 insertions(+), 14 deletions(-) create mode 100644 idea/testData/findUsages/kotlin/conventions/components/componentFunForGenericType1.log create mode 100644 idea/testData/findUsages/kotlin/conventions/components/componentFunForGenericType2.log create mode 100644 idea/testData/findUsages/kotlin/conventions/components/dataClass.log create mode 100644 idea/testData/findUsages/kotlin/conventions/components/dataClassComponentByRef.log create mode 100644 idea/testData/findUsages/kotlin/conventions/components/dataClassFromStdlib.log create mode 100644 idea/testData/findUsages/kotlin/conventions/components/extensionComponentFun.log create mode 100644 idea/testData/findUsages/kotlin/conventions/components/memberComponentFun.log create mode 100644 idea/testData/findUsages/kotlin/findParameterUsages/kotlinComponentFunctionParameterUsages.log diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/destructuringDeclarationUsages.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/destructuringDeclarationUsages.kt index 5a2d07089a7..84602806594 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/destructuringDeclarationUsages.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/destructuringDeclarationUsages.kt @@ -38,6 +38,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde +import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinRequestResultProcessor import org.jetbrains.kotlin.idea.search.restrictToKotlinSources @@ -61,7 +62,9 @@ enum class DestructuringDeclarationUsageSearch { ALWAYS_SMART, ALWAYS_PLAIN, PLAIN_WHEN_NEEDED } +// for tests var destructuringDeclarationUsageSearchMode = if (ApplicationManager.getApplication().isUnitTestMode) ALWAYS_SMART else PLAIN_WHEN_NEEDED +var destructuringDeclarationUsageSearchLog: MutableList? = null //TODO: check if it's too expensive @@ -108,7 +111,8 @@ fun findDestructuringDeclarationUsages( ktDeclaration, scope, consumer, - plainSearchHandler = { searchScope -> doPlainSearch(ktDeclaration, searchScope, optimizer) } + plainSearchHandler = { searchScope -> doPlainSearch(ktDeclaration, searchScope, optimizer) }, + testLog = destructuringDeclarationUsageSearchLog ).run() } @@ -124,13 +128,15 @@ private class Processor( private val target: KtDeclaration, private val searchScope: SearchScope, private val consumer: Processor, - private val plainSearchHandler: (SearchScope) -> Unit + plainSearchHandler: (SearchScope) -> Unit, + private val testLog: MutableList? ) { - private val project = target.project + private val plainSearchHandler: (SearchScope) -> Unit = { scope -> + testLog?.add("Used plain search in ${scope.logPresentation()}") + plainSearchHandler(scope) + } - // we don't need to search usages of declarations in Java because Java doesn't have implicitly typed declarations so such usages cannot affect Kotlin code - //TODO: what about Scala and other JVM-languages? - private val declarationUsageScope = GlobalSearchScope.projectScope(project).restrictToKotlinSources() + private val project = target.project // note: a Task must define equals & hashCode! private interface Task { @@ -159,8 +165,10 @@ private class Processor( val parameters = ClassInheritorsSearch.SearchParameters(psiClass, GlobalSearchScope.allScope(project), true, true, false) val classesToSearch = listOf(psiClass) + ClassInheritorsSearch.search(parameters).findAll() + testLog?.add("Searched inheritors of ${psiClass.logPresentation()}") for (classToSearch in classesToSearch) { + testLog?.add("Searched references to ${classToSearch.logPresentation()}") ReferencesSearch.search(classToSearch).forEach(Processor processor@ { reference -> //TODO: see KT-13607 if (processDataClassUsage(reference)) return@processor true @@ -211,7 +219,11 @@ private class Processor( private fun addCallableDeclarationToProcess(declaration: PsiElement, kind: CallableToProcessKind) { data class ProcessCallableUsagesTask(val declaration: PsiElement, val kind: CallableToProcessKind) : Task { override fun perform() { - ReferencesSearch.search(declaration, declarationUsageScope).forEach { reference -> + // we don't need to search usages of declarations in Java because Java doesn't have implicitly typed declarations so such usages cannot affect Kotlin code + //TODO: what about Scala and other JVM-languages? + val scope = GlobalSearchScope.projectScope(project).restrictToKotlinSources() + testLog?.add("Searched references to ${declaration.logPresentation()} in Kotlin files") + ReferencesSearch.search(declaration, scope).forEach { reference -> when (kind) { CallableToProcessKind.HAS_DATA_CLASS_TYPE -> { if (reference is KtDestructuringDeclarationReference) { @@ -247,6 +259,7 @@ private class Processor( override fun perform() { //TODO: what about other JVM languages? val scope = GlobalSearchScope.getScopeRestrictedByFileTypes(GlobalSearchScope.projectScope(project), JavaFileType.INSTANCE) + testLog?.add("Searched references to ${psiClass.logPresentation()} in java files") ReferencesSearch.search(psiClass, scope).forEach { reference -> // check if the reference is method parameter type val parameter = ((reference as? PsiJavaCodeReferenceElement)?.parent as? PsiTypeElement)?.parent as? PsiParameter @@ -563,4 +576,43 @@ private class Processor( else -> false } } + + private fun PsiElement.logPresentation(): String? { + val fqName = getKotlinFqName()?.asString() + ?: (this as? KtNamedDeclaration)?.name + return when (this) { + is PsiMethod, is KtFunction -> fqName + "()" + is KtParameter -> "parameter ${this.name} in ${this.ownerFunction?.logPresentation()}" + else -> fqName + } + } + + private fun SearchScope.logPresentation(): String { + return when (this) { + searchScope -> "whole search scope" + + is LocalSearchScope -> { + scope + .map { element -> + " " + when (element) { + is KtFunctionLiteral -> element.text + is KtWhenEntry -> { + if (element.isElse) + "KtWhenEntry \"else\"" + else + "KtWhenEntry \"" + element.conditions.joinToString(", ") { it.text } + "\"" + } + is KtNamedDeclaration -> element.node.elementType.toString() + ":" + element.name + else -> element.toString() + } + } + .toList() + .sorted() + .joinToString("\n", "LocalSearchScope:\n") + } + + else -> this.displayName + } + + } } diff --git a/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/KotlinFindMemberUsagesHandler.kt b/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/KotlinFindMemberUsagesHandler.kt index d7d03e41884..1076a671074 100644 --- a/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/KotlinFindMemberUsagesHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/KotlinFindMemberUsagesHandler.kt @@ -131,9 +131,10 @@ abstract class KotlinFindMemberUsagesHandler val uniqueProcessor = CommonProcessors.UniqueProcessor(processor) if (options.isUsages) { - val searchParameters = KotlinReferencesSearchParameters(element, - scope = options.searchScope, - kotlinOptions = createKotlinReferencesSearchOptions(options)) + // we disable searchForComponentConventions for ReferencesSearch because they will be searched by MethodReferencesSearch + val kotlinSearchOptions = createKotlinReferencesSearchOptions(options) + .copy(searchForComponentConventions = false) + val searchParameters = KotlinReferencesSearchParameters(element, options.searchScope, kotlinOptions = kotlinSearchOptions) with(applyQueryFilters(element, options, ReferencesSearch.search(searchParameters))) { if (!forEach(referenceProcessor)) return false diff --git a/idea/testData/findUsages/kotlin/conventions/components/componentFunForGenericType1.log b/idea/testData/findUsages/kotlin/conventions/components/componentFunForGenericType1.log new file mode 100644 index 00000000000..3a15116da7b --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/components/componentFunForGenericType1.log @@ -0,0 +1,7 @@ +Searched inheritors of X +Searched references to X +Searched references to f() in Kotlin files +Used plain search in LocalSearchScope: + CLASS:X + FUN:component1 + FUN:component2 \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/components/componentFunForGenericType2.log b/idea/testData/findUsages/kotlin/conventions/components/componentFunForGenericType2.log new file mode 100644 index 00000000000..cc43ac3947c --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/components/componentFunForGenericType2.log @@ -0,0 +1,9 @@ +Searched inheritors of X +Searched references to X +Searched references to f() in Kotlin files +Used plain search in LocalSearchScope: + CLASS:X + FUN:component1 + FUN:component1 + FUN:component2 + FUN:component2 \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/components/dataClass.log b/idea/testData/findUsages/kotlin/conventions/components/dataClass.log new file mode 100644 index 00000000000..4efc9664a70 --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/components/dataClass.log @@ -0,0 +1,53 @@ +Searched inheritors of pack.A +Searched inheritors of pack.B +Searched inheritors of pack.C +Searched references to JavaClass.getA() in Kotlin files +Searched references to JavaClass.takeSAM() in Kotlin files +Searched references to JavaSAM in java files +Searched references to a in Kotlin files +Searched references to a in Kotlin files +Searched references to a1 in Kotlin files +Searched references to f() in Kotlin files +Searched references to g() in Kotlin files +Searched references to h() in Kotlin files +Searched references to list in Kotlin files +Searched references to listOfA() in Kotlin files +Searched references to pack.A +Searched references to pack.B +Searched references to pack.C +Searched references to pack.C.component1() in Kotlin files +Searched references to pack4.takeExtFun() in Kotlin files +Searched references to pack4.takeFun1() in Kotlin files +Searched references to pack4.takeFun2() in Kotlin files +Searched references to pack4.takeFun3() in Kotlin files +Searched references to pack4.takeFuns() in Kotlin files +Searched references to pack5.v in Kotlin files +Searched references to parameter a in B() in Kotlin files +Searched references to parameter a in null in Kotlin files +Searched references to parameter b in pack.f() in Kotlin files +Searched references to parameter c in pack.f() in Kotlin files +Searched references to parameter p in pack4.foo() in Kotlin files +Searched references to parameter p in pack4.takeExtFun() in Kotlin files +Searched references to parameter p in pack4.takeFun1() in Kotlin files +Searched references to parameter p in pack4.takeFun2() in Kotlin files +Searched references to parameter p in pack4.takeFun3() in Kotlin files +Searched references to parameter p in pack4.takeFuns() in Kotlin files +Used plain search in LocalSearchScope: + CLASS:A + FUN:ext1 + FUN:ext1 + FUN:x + KtWhenEntry "else" + KtWhenEntry "is A" + { a, n -> val (x, y) = a!! } + { val (x, y ) = it } + { val (x, y) = it } + { val (x, y) = it } + { val (x, y) = it } + { val (x, y) = it } + { val (x, y) = it[0] } + { val (x, y) = this } +Used plain search in LocalSearchScope: + CLASS:B +Used plain search in LocalSearchScope: + CLASS:C \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/components/dataClassComponentByRef.log b/idea/testData/findUsages/kotlin/conventions/components/dataClassComponentByRef.log new file mode 100644 index 00000000000..b43c5e95f2a --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/components/dataClassComponentByRef.log @@ -0,0 +1,5 @@ +Searched inheritors of A +Searched references to A +Searched references to a in Kotlin files +Used plain search in LocalSearchScope: + CLASS:A \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/components/dataClassFromStdlib.log b/idea/testData/findUsages/kotlin/conventions/components/dataClassFromStdlib.log new file mode 100644 index 00000000000..63b8d7f9bbd --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/components/dataClassFromStdlib.log @@ -0,0 +1 @@ +Used plain search in whole search scope \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/components/extensionComponentFun.log b/idea/testData/findUsages/kotlin/conventions/components/extensionComponentFun.log new file mode 100644 index 00000000000..75dc0acccd6 --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/components/extensionComponentFun.log @@ -0,0 +1,10 @@ +Searched inheritors of X +Searched references to X +Searched references to Y +Searched references to f() in Kotlin files +Used plain search in LocalSearchScope: + CLASS:X + CLASS:Y + FUN:component1 + FUN:component2 + FUN:ext \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/components/memberComponentFun.log b/idea/testData/findUsages/kotlin/conventions/components/memberComponentFun.log new file mode 100644 index 00000000000..7d11d970bdf --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/components/memberComponentFun.log @@ -0,0 +1,11 @@ +Searched inheritors of X +Searched references to X +Searched references to Y +Searched references to Z +Searched references to f() in Kotlin files +Searched references to g() in Kotlin files +Searched references to h() in Kotlin files +Used plain search in LocalSearchScope: + CLASS:X + CLASS:Y + CLASS:Z \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/findParameterUsages/kotlinComponentFunctionParameterUsages.log b/idea/testData/findUsages/kotlin/findParameterUsages/kotlinComponentFunctionParameterUsages.log new file mode 100644 index 00000000000..ecc261cfe93 --- /dev/null +++ b/idea/testData/findUsages/kotlin/findParameterUsages/kotlinComponentFunctionParameterUsages.log @@ -0,0 +1,4 @@ +Searched inheritors of test.KotlinDataClass +Searched references to test.KotlinDataClass +Used plain search in LocalSearchScope: + CLASS:KotlinDataClass diff --git a/idea/tests/org/jetbrains/kotlin/findUsages/AbstractFindUsagesTest.java b/idea/tests/org/jetbrains/kotlin/findUsages/AbstractFindUsagesTest.java index 7f2259e7d36..b80cfe4071c 100644 --- a/idea/tests/org/jetbrains/kotlin/findUsages/AbstractFindUsagesTest.java +++ b/idea/tests/org/jetbrains/kotlin/findUsages/AbstractFindUsagesTest.java @@ -58,6 +58,7 @@ import org.jetbrains.kotlin.idea.findUsages.KotlinClassFindUsagesOptions; import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesHandlerFactory; import org.jetbrains.kotlin.idea.findUsages.KotlinFunctionFindUsagesOptions; import org.jetbrains.kotlin.idea.findUsages.KotlinPropertyFindUsagesOptions; +import org.jetbrains.kotlin.idea.search.usagesSearch.DestructuringDeclarationUsagesKt; import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase; import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor; import org.jetbrains.kotlin.idea.test.PluginTestCaseBase; @@ -69,9 +70,7 @@ import org.jetbrains.kotlin.test.KotlinTestUtils; import java.io.File; import java.io.FilenameFilter; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; +import java.util.*; public abstract class AbstractFindUsagesTest extends KotlinLightCodeInsightFixtureTestCase { @@ -399,7 +398,22 @@ public abstract class AbstractFindUsagesTest extends KotlinLightCodeInsightFixtu ) throws ClassNotFoundException, InstantiationException, IllegalAccessException { boolean highlightingMode = InTextDirectivesUtils.isDirectiveDefined(mainFileText, "// HIGHLIGHTING"); - Collection usageInfos = findUsages(caretElement, options, highlightingMode); + Collection usageInfos; + String log = null; + try { + DestructuringDeclarationUsagesKt.setDestructuringDeclarationUsageSearchLog(new ArrayList()); + + usageInfos = findUsages(caretElement, options, highlightingMode); + } + finally { + List logList = DestructuringDeclarationUsagesKt.getDestructuringDeclarationUsageSearchLog(); + assert logList != null; + DestructuringDeclarationUsagesKt.setDestructuringDeclarationUsageSearchLog(null); + if (logList.size() > 0) { + Collections.sort(logList); + log = StringUtil.join(logList, "\n"); + } + } Collection filteringRules = instantiateClasses(mainFileText, "// FILTERING_RULES: "); final Collection groupingRules = instantiateClasses(mainFileText, "// GROUPING_RULES: "); @@ -458,6 +472,10 @@ public abstract class AbstractFindUsagesTest extends KotlinLightCodeInsightFixtu Collection finalUsages = Ordering.natural().sortedCopy(Collections2.transform(filteredUsages, convertToString)); KotlinTestUtils.assertEqualsToFile(new File(rootPath, prefix + "results.txt"), StringUtil.join(finalUsages, "\n")); + + if (log != null) { + KotlinTestUtils.assertEqualsToFile(new File(rootPath, prefix + "log"), log); + } } protected Collection findUsages(