[LL API] Add tests for 'FileBasedKotlinDeclarationProvider'

This commit is contained in:
Yan Zhulanow
2023-01-19 18:26:22 +09:00
committed by Space Team
parent 6ba3bcb6b2
commit 562952080e
7 changed files with 280 additions and 0 deletions
@@ -0,0 +1,9 @@
// CLASS: Foo
// CLASS: Foo.Bar
// FUNCTION: /#foo
class Foo {
object Bar
}
fun foo() {}
@@ -0,0 +1,12 @@
// FUNCTION: test/#foo
package test
fun foo() {
fun bar() {
fun baz() {
class Foo
object Bar
}
}
}
@@ -0,0 +1,29 @@
// CLASS: test/Foo
// CLASS: test/Bar
// CLASS: test/Bar.Baz
// CLASS: test/Bar.Boo
// CLASS: test/Bar.Bok
// FUNCTION: test/#foo
// PROPERTY: test/#foo
package test
class Foo
interface Foo
typealias Foo = Foo
enum class Foo
class Bar {
class Baz
object Boo
}
interface Bar {
object Baz
interface Bok
}
fun foo() {}
fun foo(a: Int) {}
val foo: String = "foo"
@@ -0,0 +1,22 @@
// CLASS: test/app/Foo
// CLASS: test/app/Foo.Bar
// CLASS: test/app/Foo.Bar.Baz
// TYPE_ALIAS: test/app/MyString
// FUNCTION: test/app/#foo
// PROPERTY: test/app/#bar
package test.app
interface Foo {
class Bar {
object Baz
}
fun nested() {}
}
typealias MyString = String
fun foo() {}
val bar: String = "bar"
@@ -0,0 +1,154 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.FileBasedKotlinDeclarationProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.AbstractLowLevelApiSingleFileTest
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.configurators.AnalysisApiFirSourceTestConfigurator
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer
import org.jetbrains.kotlin.test.services.TestModuleStructure
import org.jetbrains.kotlin.test.services.TestServices
import kotlin.test.assertContains
import kotlin.test.assertNotNull
abstract class AbstractFileBasedKotlinDeclarationProviderTest : AbstractLowLevelApiSingleFileTest() {
override val configurator = AnalysisApiFirSourceTestConfigurator(analyseInDependentSession = false)
override fun configureTest(builder: TestConfigurationBuilder) {
super.configureTest(builder)
with(builder) {
useDirectives(Directives)
}
}
override fun doTestByFileStructure(ktFile: KtFile, moduleStructure: TestModuleStructure, testServices: TestServices) {
val provider = FileBasedKotlinDeclarationProvider(ktFile)
assertContains(provider.findFilesForFacadeByPackage(ktFile.packageFqName), ktFile)
checkByDirectives(moduleStructure, provider)
checkByVisitor(ktFile, provider)
}
private fun checkByDirectives(moduleStructure: TestModuleStructure, provider: FileBasedKotlinDeclarationProvider) {
for (directive in moduleStructure.allDirectives[Directives.CLASS]) {
val classId = ClassId.fromString(directive)
assert(provider.getAllClassesByClassId(classId).isNotEmpty()) { "Class $classId not found" }
assertNotNull(provider.getClassLikeDeclarationByClassId(classId)) { "Class-like declaration $classId not found" }
}
for (directive in moduleStructure.allDirectives[Directives.TYPE_ALIAS]) {
val classId = ClassId.fromString(directive)
assert(provider.getAllTypeAliasesByClassId(classId).isNotEmpty()) { "Type alias $classId not found" }
assertNotNull(provider.getClassLikeDeclarationByClassId(classId)) { "Class-like declaration $classId not found" }
}
for (directive in moduleStructure.allDirectives[Directives.FUNCTION]) {
val callableId = parseCallableId(directive)
assert(provider.getTopLevelFunctions(callableId).isNotEmpty()) { "Function $callableId not found" }
}
for (directive in moduleStructure.allDirectives[Directives.PROPERTY]) {
val callableId = parseCallableId(directive)
assert(provider.getTopLevelProperties(callableId).isNotEmpty()) { "Property $callableId not found" }
}
}
private fun checkByVisitor(ktFile: KtFile, provider: FileBasedKotlinDeclarationProvider) {
ktFile.accept(object : KtTreeVisitorVoid() {
override fun visitClass(klass: KtClass) {
super.visitClass(klass)
processClassLikeDeclaration(klass)
}
override fun visitTypeAlias(typeAlias: KtTypeAlias) {
super.visitTypeAlias(typeAlias)
processClassLikeDeclaration(typeAlias)
}
private fun processClassLikeDeclaration(declaration: KtClassLikeDeclaration) {
val classId = declaration.getClassId() ?: return
val shortName = classId.shortClassName
if (!classId.isNestedClass) {
assertContains(provider.getTopLevelKotlinClassLikeDeclarationNamesInPackage(classId.packageFqName), shortName)
}
when (declaration) {
is KtClassOrObject -> assertContains(provider.getAllClassesByClassId(classId), declaration)
is KtTypeAlias -> assertContains(provider.getAllTypeAliasesByClassId(classId), declaration)
}
}
override fun visitNamedFunction(function: KtNamedFunction) {
super.visitNamedFunction(function)
processCallableDeclaration(function)
}
override fun visitProperty(property: KtProperty) {
super.visitProperty(property)
processCallableDeclaration(property)
}
private fun processCallableDeclaration(declaration: KtCallableDeclaration) {
val callableId = declaration.callableId ?: return
if (callableId.classId == null) {
assertContains(provider.getTopLevelCallableFiles(callableId), ktFile)
assertContains(provider.getTopLevelCallableNamesInPackage(callableId.packageName), callableId.callableName)
when (declaration) {
is KtFunction -> assertContains(provider.getTopLevelFunctions(callableId), declaration)
is KtProperty -> assertContains(provider.getTopLevelProperties(callableId), declaration)
}
}
}
})
}
object Directives : SimpleDirectivesContainer() {
val CLASS by stringDirective("ClassId of a class or object to be checked for presence")
val TYPE_ALIAS by stringDirective("ClassId of a type alias to be checked for presence")
val FUNCTION by stringDirective("CallableId of a function to be checked for presence")
val PROPERTY by stringDirective("CallableId of a property to be checked for presence")
}
}
private val KtCallableDeclaration.callableId: CallableId?
get() {
val callableName = this.nameAsName ?: return null
when (val owner = PsiTreeUtil.getParentOfType(this, KtDeclaration::class.java, KtFile::class.java)) {
is KtClassOrObject -> {
val classId = owner.getClassId() ?: return null
return CallableId(classId, callableName)
}
is KtFile -> {
return CallableId(owner.packageFqName, callableName)
}
else -> return null
}
}
private fun parseCallableId(rawString: String): CallableId {
val chunks = rawString.split('#')
assert(chunks.size == 2) { "Invalid CallableId string format: $rawString" }
val rawQualifier = chunks[0]
val rawCallableName = chunks[1]
val callableName = Name.identifier(rawCallableName)
return when {
rawQualifier.endsWith('/') -> CallableId(FqName(rawQualifier.dropLast(1).replace('/', '.')), callableName)
else -> CallableId(ClassId.fromString(rawQualifier, false), callableName)
}
}
@@ -0,0 +1,50 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.analysis.api.GenerateAnalysisApiTestsKt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("analysis/low-level-api-fir/testdata/fileBasedDeclarationProvider")
@TestDataPath("$PROJECT_ROOT")
public class FileBasedKotlinDeclarationProviderTestGenerated extends AbstractFileBasedKotlinDeclarationProviderTest {
@Test
public void testAllFilesPresentInFileBasedDeclarationProvider() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/low-level-api-fir/testdata/fileBasedDeclarationProvider"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("defaultPackage.kt")
public void testDefaultPackage() throws Exception {
runTest("analysis/low-level-api-fir/testdata/fileBasedDeclarationProvider/defaultPackage.kt");
}
@Test
@TestMetadata("local.kt")
public void testLocal() throws Exception {
runTest("analysis/low-level-api-fir/testdata/fileBasedDeclarationProvider/local.kt");
}
@Test
@TestMetadata("sameNames.kt")
public void testSameNames() throws Exception {
runTest("analysis/low-level-api-fir/testdata/fileBasedDeclarationProvider/sameNames.kt");
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("analysis/low-level-api-fir/testdata/fileBasedDeclarationProvider/simple.kt");
}
}
@@ -86,6 +86,10 @@ internal fun TestGroupSuite.generateFirLowLevelApiTests() {
testClass<AbstractOutOfContentRootGetOrBuildFirTest> {
model("getOrBuildFir")
}
testClass<AbstractFileBasedKotlinDeclarationProviderTest> {
model("fileBasedDeclarationProvider")
}
}
testGroup(