From e5095a60ba26384a0a302f5660203d4d66b2d23a Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Sun, 19 Nov 2023 00:28:05 -0800 Subject: [PATCH] K2 UAST: lookup properties in the containing class, not companion object ...because properties in the companion object are materialized in the containing class. ^KTIJ-27684 fixed --- ...roviderMultiModuleBinaryTestGenerated.java | 42 +++++++++++++++++++ .../propertiesInCompanionObject.kt | 35 ++++++++++++++++ .../propertiesInCompanionObject.txt | 2 + .../propertiesInCompanionObject_JvmField.kt | 35 ++++++++++++++++ .../propertiesInCompanionObject_JvmField.txt | 2 + .../propertiesInCompanionObject_JvmStatic.kt | 35 ++++++++++++++++ .../propertiesInCompanionObject_JvmStatic.txt | 2 + .../propertiesInNamedCompanionObject.kt | 35 ++++++++++++++++ .../propertiesInNamedCompanionObject.txt | 2 + ...opertiesInNamedCompanionObject_JvmField.kt | 35 ++++++++++++++++ ...pertiesInNamedCompanionObject_JvmField.txt | 2 + ...pertiesInNamedCompanionObject_JvmStatic.kt | 35 ++++++++++++++++ ...ertiesInNamedCompanionObject_JvmStatic.txt | 2 + .../multiModuleBinary/propertiesInObject.kt | 26 ++++++++++++ .../multiModuleBinary/propertiesInObject.txt | 2 + .../DecompiledPsiDeclarationProvider.kt | 12 ++++-- ...cPsiDeclarationFromBinaryModuleProvider.kt | 25 +++++++---- 17 files changed, 319 insertions(+), 10 deletions(-) create mode 100644 analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject.kt create mode 100644 analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject.txt create mode 100644 analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject_JvmField.kt create mode 100644 analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject_JvmField.txt create mode 100644 analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject_JvmStatic.kt create mode 100644 analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject_JvmStatic.txt create mode 100644 analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject.kt create mode 100644 analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject.txt create mode 100644 analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject_JvmField.kt create mode 100644 analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject_JvmField.txt create mode 100644 analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject_JvmStatic.kt create mode 100644 analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject_JvmStatic.txt create mode 100644 analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInObject.kt create mode 100644 analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInObject.txt diff --git a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/psiDeclarationProvider/FirStandaloneNormalAnalysisLibraryBinaryModulePsiDeclarationProviderMultiModuleBinaryTestGenerated.java b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/psiDeclarationProvider/FirStandaloneNormalAnalysisLibraryBinaryModulePsiDeclarationProviderMultiModuleBinaryTestGenerated.java index 8308000d24f..89367821ac8 100644 --- a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/psiDeclarationProvider/FirStandaloneNormalAnalysisLibraryBinaryModulePsiDeclarationProviderMultiModuleBinaryTestGenerated.java +++ b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/psiDeclarationProvider/FirStandaloneNormalAnalysisLibraryBinaryModulePsiDeclarationProviderMultiModuleBinaryTestGenerated.java @@ -51,4 +51,46 @@ public class FirStandaloneNormalAnalysisLibraryBinaryModulePsiDeclarationProvide public void testMultifileFacade() throws Exception { runTest("analysis/analysis-api/testData/standalone/multiModuleBinary/multifileFacade.kt"); } + + @Test + @TestMetadata("propertiesInCompanionObject.kt") + public void testPropertiesInCompanionObject() throws Exception { + runTest("analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject.kt"); + } + + @Test + @TestMetadata("propertiesInCompanionObject_JvmField.kt") + public void testPropertiesInCompanionObject_JvmField() throws Exception { + runTest("analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject_JvmField.kt"); + } + + @Test + @TestMetadata("propertiesInCompanionObject_JvmStatic.kt") + public void testPropertiesInCompanionObject_JvmStatic() throws Exception { + runTest("analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject_JvmStatic.kt"); + } + + @Test + @TestMetadata("propertiesInNamedCompanionObject.kt") + public void testPropertiesInNamedCompanionObject() throws Exception { + runTest("analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject.kt"); + } + + @Test + @TestMetadata("propertiesInNamedCompanionObject_JvmField.kt") + public void testPropertiesInNamedCompanionObject_JvmField() throws Exception { + runTest("analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject_JvmField.kt"); + } + + @Test + @TestMetadata("propertiesInNamedCompanionObject_JvmStatic.kt") + public void testPropertiesInNamedCompanionObject_JvmStatic() throws Exception { + runTest("analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject_JvmStatic.kt"); + } + + @Test + @TestMetadata("propertiesInObject.kt") + public void testPropertiesInObject() throws Exception { + runTest("analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInObject.kt"); + } } diff --git a/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject.kt b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject.kt new file mode 100644 index 00000000000..36280273a1c --- /dev/null +++ b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject.kt @@ -0,0 +1,35 @@ +// MODULE: lib + +// FILE: some/Dependency.kt +package some + +interface Flag + +class Dependency { + companion object { + @JvmField val JVM_FIELD_FLAG: Flag<*> = TODO() + @JvmStatic val JVM_STATIC_FLAG: Flag<*> = TODO() + val VAL_FLAG: Flag<*> = TODO() + var varFlag: Flag<*> = TODO() + } +} + +val DEPENDENCY_TOP_LEVEL_VAL_FLAG: Flag<*> = TODO() + +// MODULE: app +// DEPENDENCY: lib Binary +// FILE: main.kt + +package some + +private fun consumeFlag(p: Flag<*>) { + println(p) +} + +fun test() { + consumeFlag(Dependency.JVM_FIELD_FLAG) + consumeFlag(Dependency.JVM_STATIC_FLAG) + consumeFlag(Dependency.VAL_FLAG) + consumeFlag(Dependency.varFlag) + consumeFlag(DEPENDENCY_TOP_LEVEL_VAL_FLAG) +} \ No newline at end of file diff --git a/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject.txt b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject.txt new file mode 100644 index 00000000000..eea29538a4b --- /dev/null +++ b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject.txt @@ -0,0 +1,2 @@ +Resolved to: +PsiField:VAL_FLAG diff --git a/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject_JvmField.kt b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject_JvmField.kt new file mode 100644 index 00000000000..bdb77180bf1 --- /dev/null +++ b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject_JvmField.kt @@ -0,0 +1,35 @@ +// MODULE: lib + +// FILE: some/Dependency.kt +package some + +interface Flag + +class Dependency { + companion object { + @JvmField val JVM_FIELD_FLAG: Flag<*> = TODO() + @JvmStatic val JVM_STATIC_FLAG: Flag<*> = TODO() + val VAL_FLAG: Flag<*> = TODO() + var varFlag: Flag<*> = TODO() + } +} + +val DEPENDENCY_TOP_LEVEL_VAL_FLAG: Flag<*> = TODO() + +// MODULE: app +// DEPENDENCY: lib Binary +// FILE: main.kt + +package some + +private fun consumeFlag(p: Flag<*>) { + println(p) +} + +fun test() { + consumeFlag(Dependency.JVM_FIELD_FLAG) + consumeFlag(Dependency.JVM_STATIC_FLAG) + consumeFlag(Dependency.VAL_FLAG) + consumeFlag(Dependency.varFlag) + consumeFlag(DEPENDENCY_TOP_LEVEL_VAL_FLAG) +} \ No newline at end of file diff --git a/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject_JvmField.txt b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject_JvmField.txt new file mode 100644 index 00000000000..316a2ead2d8 --- /dev/null +++ b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject_JvmField.txt @@ -0,0 +1,2 @@ +Resolved to: +PsiField:JVM_FIELD_FLAG diff --git a/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject_JvmStatic.kt b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject_JvmStatic.kt new file mode 100644 index 00000000000..0803739afe6 --- /dev/null +++ b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject_JvmStatic.kt @@ -0,0 +1,35 @@ +// MODULE: lib + +// FILE: some/Dependency.kt +package some + +interface Flag + +class Dependency { + companion object { + @JvmField val JVM_FIELD_FLAG: Flag<*> = TODO() + @JvmStatic val JVM_STATIC_FLAG: Flag<*> = TODO() + val VAL_FLAG: Flag<*> = TODO() + var varFlag: Flag<*> = TODO() + } +} + +val DEPENDENCY_TOP_LEVEL_VAL_FLAG: Flag<*> = TODO() + +// MODULE: app +// DEPENDENCY: lib Binary +// FILE: main.kt + +package some + +private fun consumeFlag(p: Flag<*>) { + println(p) +} + +fun test() { + consumeFlag(Dependency.JVM_FIELD_FLAG) + consumeFlag(Dependency.JVM_STATIC_FLAG) + consumeFlag(Dependency.VAL_FLAG) + consumeFlag(Dependency.varFlag) + consumeFlag(DEPENDENCY_TOP_LEVEL_VAL_FLAG) +} \ No newline at end of file diff --git a/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject_JvmStatic.txt b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject_JvmStatic.txt new file mode 100644 index 00000000000..ef4977acf61 --- /dev/null +++ b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInCompanionObject_JvmStatic.txt @@ -0,0 +1,2 @@ +Resolved to: +PsiField:JVM_STATIC_FLAG \ No newline at end of file diff --git a/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject.kt b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject.kt new file mode 100644 index 00000000000..a0c335a47bb --- /dev/null +++ b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject.kt @@ -0,0 +1,35 @@ +// MODULE: lib + +// FILE: some/Dependency.kt +package some + +interface Flag + +class Dependency { + companion object Named { + @JvmField val JVM_FIELD_FLAG: Flag<*> = TODO() + @JvmStatic val JVM_STATIC_FLAG: Flag<*> = TODO() + val VAL_FLAG: Flag<*> = TODO() + var varFlag: Flag<*> = TODO() + } +} + +val DEPENDENCY_TOP_LEVEL_VAL_FLAG: Flag<*> = TODO() + +// MODULE: app +// DEPENDENCY: lib Binary +// FILE: main.kt + +package some + +private fun consumeFlag(p: Flag<*>) { + println(p) +} + +fun test() { + consumeFlag(Dependency.JVM_FIELD_FLAG) + consumeFlag(Dependency.JVM_STATIC_FLAG) + consumeFlag(Dependency.VAL_FLAG) + consumeFlag(Dependency.varFlag) + consumeFlag(DEPENDENCY_TOP_LEVEL_VAL_FLAG) +} \ No newline at end of file diff --git a/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject.txt b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject.txt new file mode 100644 index 00000000000..eea29538a4b --- /dev/null +++ b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject.txt @@ -0,0 +1,2 @@ +Resolved to: +PsiField:VAL_FLAG diff --git a/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject_JvmField.kt b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject_JvmField.kt new file mode 100644 index 00000000000..6650b30151f --- /dev/null +++ b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject_JvmField.kt @@ -0,0 +1,35 @@ +// MODULE: lib + +// FILE: some/Dependency.kt +package some + +interface Flag + +class Dependency { + companion object Named { + @JvmField val JVM_FIELD_FLAG: Flag<*> = TODO() + @JvmStatic val JVM_STATIC_FLAG: Flag<*> = TODO() + val VAL_FLAG: Flag<*> = TODO() + var varFlag: Flag<*> = TODO() + } +} + +val DEPENDENCY_TOP_LEVEL_VAL_FLAG: Flag<*> = TODO() + +// MODULE: app +// DEPENDENCY: lib Binary +// FILE: main.kt + +package some + +private fun consumeFlag(p: Flag<*>) { + println(p) +} + +fun test() { + consumeFlag(Dependency.JVM_FIELD_FLAG) + consumeFlag(Dependency.JVM_STATIC_FLAG) + consumeFlag(Dependency.VAL_FLAG) + consumeFlag(Dependency.varFlag) + consumeFlag(DEPENDENCY_TOP_LEVEL_VAL_FLAG) +} \ No newline at end of file diff --git a/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject_JvmField.txt b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject_JvmField.txt new file mode 100644 index 00000000000..316a2ead2d8 --- /dev/null +++ b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject_JvmField.txt @@ -0,0 +1,2 @@ +Resolved to: +PsiField:JVM_FIELD_FLAG diff --git a/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject_JvmStatic.kt b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject_JvmStatic.kt new file mode 100644 index 00000000000..30700b20fea --- /dev/null +++ b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject_JvmStatic.kt @@ -0,0 +1,35 @@ +// MODULE: lib + +// FILE: some/Dependency.kt +package some + +interface Flag + +class Dependency { + companion object Named { + @JvmField val JVM_FIELD_FLAG: Flag<*> = TODO() + @JvmStatic val JVM_STATIC_FLAG: Flag<*> = TODO() + val VAL_FLAG: Flag<*> = TODO() + var varFlag: Flag<*> = TODO() + } +} + +val DEPENDENCY_TOP_LEVEL_VAL_FLAG: Flag<*> = TODO() + +// MODULE: app +// DEPENDENCY: lib Binary +// FILE: main.kt + +package some + +private fun consumeFlag(p: Flag<*>) { + println(p) +} + +fun test() { + consumeFlag(Dependency.JVM_FIELD_FLAG) + consumeFlag(Dependency.JVM_STATIC_FLAG) + consumeFlag(Dependency.VAL_FLAG) + consumeFlag(Dependency.varFlag) + consumeFlag(DEPENDENCY_TOP_LEVEL_VAL_FLAG) +} \ No newline at end of file diff --git a/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject_JvmStatic.txt b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject_JvmStatic.txt new file mode 100644 index 00000000000..ef4977acf61 --- /dev/null +++ b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInNamedCompanionObject_JvmStatic.txt @@ -0,0 +1,2 @@ +Resolved to: +PsiField:JVM_STATIC_FLAG \ No newline at end of file diff --git a/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInObject.kt b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInObject.kt new file mode 100644 index 00000000000..456161204dc --- /dev/null +++ b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInObject.kt @@ -0,0 +1,26 @@ +// MODULE: lib + +// FILE: some/DependencyObject.kt +package some + +interface Flag + +object DependencyObject { + val VAL_FLAG: Flag<*> = TODO() + var varFlag: Flag<*> = TODO() +} + +// MODULE: app +// DEPENDENCY: lib Binary +// FILE: main.kt + +package some + +private fun consumeFlag(p: Flag<*>) { + println(p) +} + +fun test() { + consumeFlag(DependencyObject.VAL_FLAG) + consumeFlag(DependencyObject.varFlag) +} \ No newline at end of file diff --git a/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInObject.txt b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInObject.txt new file mode 100644 index 00000000000..8602cf2f28d --- /dev/null +++ b/analysis/analysis-api/testData/standalone/multiModuleBinary/propertiesInObject.txt @@ -0,0 +1,2 @@ +Resolved to: +PsiField:varFlag diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/DecompiledPsiDeclarationProvider.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/DecompiledPsiDeclarationProvider.kt index 605ed7dcba5..550be9ac990 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/DecompiledPsiDeclarationProvider.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/DecompiledPsiDeclarationProvider.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.analysis.providers import com.intellij.openapi.project.Project import com.intellij.psi.PsiElement +import com.intellij.psi.PsiField import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.symbols.* @@ -58,10 +59,15 @@ object DecompiledPsiDeclarationProvider { project: Project ): PsiElement? { return variableLikeSymbol.callableIdIfNonLocal?.let { - project.createPsiDeclarationProvider(variableLikeSymbol.scope(project)) + val candidates = project.createPsiDeclarationProvider(variableLikeSymbol.scope(project)) ?.getProperties(it) - // TODO: needs to pick field/getter/setter accordingly? - ?.firstOrNull() + if (candidates?.size == 1) + candidates.single() + else { + // Weigh [PsiField] + candidates?.firstOrNull { psiMember -> psiMember is PsiField } + ?: candidates?.firstOrNull() + } } } diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticPsiDeclarationFromBinaryModuleProvider.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticPsiDeclarationFromBinaryModuleProvider.kt index 02bade2aed7..0032aa02082 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticPsiDeclarationFromBinaryModuleProvider.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticPsiDeclarationFromBinaryModuleProvider.kt @@ -91,10 +91,12 @@ private class KotlinStaticPsiDeclarationFromBinaryModuleProvider( return listOfNotNull(javaFileManager.findClass(classId.asFqNameString(), scope)) } - // TODO(dimonchik0036): support 'is' accessor override fun getProperties(callableId: CallableId): Collection { val classes = callableId.classId?.let { classId -> - getClassesByClassId(classId) + val classFromCurrentClassId = getClassesByClassId(classId) + // property in companion object is actually materialized at the containing class. + val classFromOuterClassID = classId.outerClassId?.let { getClassesByClassId(it) } ?: emptyList() + classFromCurrentClassId + classFromOuterClassID } ?: clsClassImplsInPackage(callableId.packageName) return classes.flatMap { psiClass -> psiClass.children @@ -102,17 +104,26 @@ private class KotlinStaticPsiDeclarationFromBinaryModuleProvider( .filter { psiMember -> if (psiMember !is PsiMethod && psiMember !is PsiField) return@filter false val name = psiMember.name ?: return@filter false + val id = callableId.callableName.identifier // PsiField a.k.a. backing field - name == callableId.callableName.identifier || - // PsiMethod, i.e., accessors - (name.startsWith("get") || name.startsWith("set")) && + if (name == id) return@filter true + // PsiMethod, i.e., accessors + val nameWithoutPrefix = name.nameWithoutAccessorPrefix ?: return@filter false + // E.g., getJVM_FIELD -> JVM_FIELD + nameWithoutPrefix == id || // E.g., getFooBar -> FooBar -> fooBar - (name.substring(3).decapitalizeSmart().endsWith(callableId.callableName.identifier)) - + nameWithoutPrefix.decapitalizeSmart().endsWith(id) } }.toList() } + private val String.nameWithoutAccessorPrefix: String? + get() = when { + this.startsWith("get") || this.startsWith("set") -> substring(3) + this.startsWith("is") -> substring(2) + else -> null + } + override fun getFunctions(callableId: CallableId): Collection { val classes = callableId.classId?.let { classId -> getClassesByClassId(classId)