From 11c50a48bad6fa035911d36c5b2431b27af33a45 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Fri, 31 Dec 2021 19:36:53 +0300 Subject: [PATCH] Analysis API: add isSubclassOf tests --- .../Fe10IsSubclassOfTestGenerated.java | 42 ++++++++++++ .../FirIsSubclassOfTestGenerated.java | 42 ++++++++++++ ...ExpressionMarkersSourceFilePreprocessor.kt | 64 +++++++++++++++---- .../AbstractIsSubclassOfTest.kt | 37 +++++++++++ .../isSubclassOf/localClasses.kt | 5 ++ .../isSubclassOf/localClasses.txt | 2 + .../tests/analysis/api/analysisApi.kt | 5 ++ 7 files changed, 183 insertions(+), 14 deletions(-) create mode 100644 analysis/analysis-api-fe10/tests/org/jetbrains/kotlin/analysis/api/fe10/components/symbolDeclarationOverridesProvider/Fe10IsSubclassOfTestGenerated.java create mode 100644 analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/symbolDeclarationOverridesProvider/FirIsSubclassOfTestGenerated.java create mode 100644 analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/components/symbolDeclarationOverridesProvider/AbstractIsSubclassOfTest.kt create mode 100644 analysis/analysis-api/testData/components/symbolDeclarationOverridesProvider/isSubclassOf/localClasses.kt create mode 100644 analysis/analysis-api/testData/components/symbolDeclarationOverridesProvider/isSubclassOf/localClasses.txt diff --git a/analysis/analysis-api-fe10/tests/org/jetbrains/kotlin/analysis/api/fe10/components/symbolDeclarationOverridesProvider/Fe10IsSubclassOfTestGenerated.java b/analysis/analysis-api-fe10/tests/org/jetbrains/kotlin/analysis/api/fe10/components/symbolDeclarationOverridesProvider/Fe10IsSubclassOfTestGenerated.java new file mode 100644 index 00000000000..1b526e2f061 --- /dev/null +++ b/analysis/analysis-api-fe10/tests/org/jetbrains/kotlin/analysis/api/fe10/components/symbolDeclarationOverridesProvider/Fe10IsSubclassOfTestGenerated.java @@ -0,0 +1,42 @@ +/* + * Copyright 2010-2021 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.api.fe10.components.symbolDeclarationOverridesProvider; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.analysis.api.impl.barebone.test.FrontendApiTestConfiguratorService; +import org.jetbrains.kotlin.analysis.api.descriptors.test.KtFe10FrontendApiTestConfiguratorService; +import org.jetbrains.kotlin.analysis.api.impl.base.test.components.symbolDeclarationOverridesProvider.AbstractIsSubclassOfTest; +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 GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("analysis/analysis-api/testData/components/symbolDeclarationOverridesProvider/isSubclassOf") +@TestDataPath("$PROJECT_ROOT") +public class Fe10IsSubclassOfTestGenerated extends AbstractIsSubclassOfTest { + @NotNull + @Override + public FrontendApiTestConfiguratorService getConfigurator() { + return KtFe10FrontendApiTestConfiguratorService.INSTANCE; + } + + @Test + public void testAllFilesPresentInIsSubclassOf() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/symbolDeclarationOverridesProvider/isSubclassOf"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("localClasses.kt") + public void testLocalClasses() throws Exception { + runTest("analysis/analysis-api/testData/components/symbolDeclarationOverridesProvider/isSubclassOf/localClasses.kt"); + } +} diff --git a/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/symbolDeclarationOverridesProvider/FirIsSubclassOfTestGenerated.java b/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/symbolDeclarationOverridesProvider/FirIsSubclassOfTestGenerated.java new file mode 100644 index 00000000000..899de34415c --- /dev/null +++ b/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/symbolDeclarationOverridesProvider/FirIsSubclassOfTestGenerated.java @@ -0,0 +1,42 @@ +/* + * Copyright 2010-2021 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.api.fir.components.symbolDeclarationOverridesProvider; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.analysis.api.impl.barebone.test.FrontendApiTestConfiguratorService; +import org.jetbrains.kotlin.analysis.api.fir.FirFrontendApiTestConfiguratorService; +import org.jetbrains.kotlin.analysis.api.impl.base.test.components.symbolDeclarationOverridesProvider.AbstractIsSubclassOfTest; +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 GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("analysis/analysis-api/testData/components/symbolDeclarationOverridesProvider/isSubclassOf") +@TestDataPath("$PROJECT_ROOT") +public class FirIsSubclassOfTestGenerated extends AbstractIsSubclassOfTest { + @NotNull + @Override + public FrontendApiTestConfiguratorService getConfigurator() { + return FirFrontendApiTestConfiguratorService.INSTANCE; + } + + @Test + public void testAllFilesPresentInIsSubclassOf() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/symbolDeclarationOverridesProvider/isSubclassOf"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("localClasses.kt") + public void testLocalClasses() throws Exception { + runTest("analysis/analysis-api/testData/components/symbolDeclarationOverridesProvider/isSubclassOf/localClasses.kt"); + } +} diff --git a/analysis/analysis-api-impl-barebone/tests/org/jetbrains/kotlin/analysis/api/impl/barebone/test/ExpressionMarkersSourceFilePreprocessor.kt b/analysis/analysis-api-impl-barebone/tests/org/jetbrains/kotlin/analysis/api/impl/barebone/test/ExpressionMarkersSourceFilePreprocessor.kt index 1d9af71d22b..0e3ef4a1543 100644 --- a/analysis/analysis-api-impl-barebone/tests/org/jetbrains/kotlin/analysis/api/impl/barebone/test/ExpressionMarkersSourceFilePreprocessor.kt +++ b/analysis/analysis-api-impl-barebone/tests/org/jetbrains/kotlin/analysis/api/impl/barebone/test/ExpressionMarkersSourceFilePreprocessor.kt @@ -41,17 +41,22 @@ internal class ExpressionMarkersSourceFilePreprocessor(testServices: TestService } private fun processCaretExpression(file: TestFile, content: String): String { - val startCaretPosition = content.indexOfOrNull(TAGS.CARET) ?: return content - - testServices.expressionMarkerProvider.addCaret(file, startCaretPosition) - return content - .replace(TAGS.CARET, "") + var result = content + var match = TAGS.CARET_REGEXP.find(result) + while (match != null) { + val startCaretPosition = match.range.first + val tag = match.groups[2]?.value + testServices.expressionMarkerProvider.addCaret(file, tag, startCaretPosition) + result = result.removeRange(match.range) + match = TAGS.CARET_REGEXP.find(result) + } + return result } object TAGS { const val OPENING_EXPRESSION_TAG = "" const val CLOSING_EXPRESSION_TAG = "" - const val CARET = "" + val CARET_REGEXP = "".toRegex() } } @@ -59,25 +64,29 @@ class ExpressionMarkerProvider : TestService { private val selected = mutableMapOf() @PrivateForInline - val atCaret = mutableMapOf() + val carets = CaretProvider() fun addSelectedExpression(file: TestFile, range: TextRange) { selected[file.relativePath] = range } @OptIn(PrivateForInline::class) - fun addCaret(file: TestFile, caret: Int) { - atCaret[file.relativePath] = caret + fun addCaret(file: TestFile, caretTag: String?, caretOffset: Int) { + carets.addCaret(file.name, caretTag, caretOffset) } @OptIn(PrivateForInline::class) - fun getCaretPosition(file: KtFile): Int { - return atCaret[file.name] - ?: error("No caret found in file") + fun getCaretPosition(file: KtFile, caretTag: String? = null): Int { + return carets.getCaretOffset(file.name, caretTag) + ?: run { + val caretName = "caret${caretTag?.let { "_$it" }.orEmpty()}" + error("No <$caretName> found in file") + } + } - inline fun getElementOfTypAtCaret(file: KtFile): P { - val offset = getCaretPosition(file) + inline fun getElementOfTypAtCaret(file: KtFile, caretName: String? = null): P { + val offset = getCaretPosition(file, caretName) return file.findElementAt(offset) ?.parentOfType

() ?: error("No expression found at caret") @@ -98,6 +107,33 @@ class ExpressionMarkerProvider : TestService { .dropLastWhile { it is PsiWhiteSpace } } +@PrivateForInline +class CaretProvider { + private val caretToFile = mutableMapOf() + + fun getCaretOffset(filename: String, caretTag: String?): Int? { + val cartsInFile = caretToFile[filename] ?: return null + return cartsInFile.getCaretOffsetByTag(caretTag) + } + + fun addCaret(filename: String, caretTag: String?, caretOffset: Int) { + val cartsInFile = caretToFile.getOrPut(filename) { CaretsInFile() } + cartsInFile.addCaret(caretTag, caretOffset) + } + + private class CaretsInFile { + private val carets = mutableMapOf() + + fun getCaretOffsetByTag(tag: String?): Int? { + return carets[tag.orEmpty()] + } + + fun addCaret(caretTag: String?, caretOffset: Int) { + carets[caretTag.orEmpty()] = caretOffset + } + } +} + val TestServices.expressionMarkerProvider: ExpressionMarkerProvider by TestServices.testServiceAccessor() fun String.indexOfOrNull(substring: String) = diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/components/symbolDeclarationOverridesProvider/AbstractIsSubclassOfTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/components/symbolDeclarationOverridesProvider/AbstractIsSubclassOfTest.kt new file mode 100644 index 00000000000..41d90364dfa --- /dev/null +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/components/symbolDeclarationOverridesProvider/AbstractIsSubclassOfTest.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2010-2021 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.api.impl.base.test.components.symbolDeclarationOverridesProvider + +import org.jetbrains.kotlin.analysis.api.impl.barebone.test.expressionMarkerProvider +import org.jetbrains.kotlin.analysis.api.impl.base.test.test.framework.AbstractHLApiSingleModuleTest +import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.test.model.TestModule +import org.jetbrains.kotlin.test.services.TestServices +import org.jetbrains.kotlin.test.services.assertions + +abstract class AbstractIsSubclassOfTest : AbstractHLApiSingleModuleTest() { + override fun doTestByFileStructure(ktFiles: List, module: TestModule, testServices: TestServices) { + val subClass = testServices.expressionMarkerProvider.getElementOfTypAtCaret(ktFiles.first(), "sub") + val superClass = testServices.expressionMarkerProvider.getElementOfTypAtCaret(ktFiles.first(), "super") + + val actual = executeOnPooledThreadInReadAction { + analyseForTest(subClass) { + val subClassSymbol = subClass.getClassOrObjectSymbol() + val superClassSymbol = superClass.getClassOrObjectSymbol() + + val isSubClass = subClassSymbol.isSubClassOf(superClassSymbol) + val isDirectSubClass = subClassSymbol.isDirectSubClassOf(superClassSymbol) + + buildString { + appendLine("IS_SUBCLASS: $isSubClass") + appendLine("IS_DIRECT_SUBCLASS: $isDirectSubClass") + } + } + } + testServices.assertions.assertEqualsToTestDataFileSibling(actual) + } +} \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/symbolDeclarationOverridesProvider/isSubclassOf/localClasses.kt b/analysis/analysis-api/testData/components/symbolDeclarationOverridesProvider/isSubclassOf/localClasses.kt new file mode 100644 index 00000000000..74807b27809 --- /dev/null +++ b/analysis/analysis-api/testData/components/symbolDeclarationOverridesProvider/isSubclassOf/localClasses.kt @@ -0,0 +1,5 @@ +fun foo() { + open class A + + open class T : A() +} diff --git a/analysis/analysis-api/testData/components/symbolDeclarationOverridesProvider/isSubclassOf/localClasses.txt b/analysis/analysis-api/testData/components/symbolDeclarationOverridesProvider/isSubclassOf/localClasses.txt new file mode 100644 index 00000000000..d624aa1c04d --- /dev/null +++ b/analysis/analysis-api/testData/components/symbolDeclarationOverridesProvider/isSubclassOf/localClasses.txt @@ -0,0 +1,2 @@ +IS_SUBCLASS: true +IS_DIRECT_SUBCLASS: true diff --git a/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/analysisApi.kt b/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/analysisApi.kt index 6efa657f90e..979370d8645 100644 --- a/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/analysisApi.kt +++ b/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/analysisApi.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.analysis.api.impl.base.test.components.expressionTyp import org.jetbrains.kotlin.analysis.api.impl.base.test.components.expressionTypeProvider.AbstractExpectedExpressionTypeTest import org.jetbrains.kotlin.analysis.api.impl.base.test.components.expressionTypeProvider.AbstractHLExpressionTypeTest import org.jetbrains.kotlin.analysis.api.impl.base.test.components.smartCastProvider.AbstractHLSmartCastInfoTest +import org.jetbrains.kotlin.analysis.api.impl.base.test.components.symbolDeclarationOverridesProvider.AbstractIsSubclassOfTest import org.jetbrains.kotlin.analysis.api.impl.base.test.components.symbolDeclarationOverridesProvider.AbstractOverriddenDeclarationProviderTest import org.jetbrains.kotlin.analysis.api.impl.base.test.components.symbolDeclarationRenderer.AbstractRendererTest import org.jetbrains.kotlin.analysis.api.impl.base.test.components.typeCreator.AbstractTypeParameterTypeTest @@ -195,6 +196,10 @@ private fun TestGroupSuite.generateAnalysisApiComponentsTests() { test(AbstractOverriddenDeclarationProviderTest::class) { model("overriddenSymbols") } + + test(AbstractIsSubclassOfTest::class) { + model("isSubclassOf") + } } component("symbolDeclarationRenderer") {