Analysis API: add isSubclassOf tests
This commit is contained in:
+42
@@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
+42
@@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
+50
-14
@@ -41,17 +41,22 @@ internal class ExpressionMarkersSourceFilePreprocessor(testServices: TestService
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun processCaretExpression(file: TestFile, content: String): String {
|
private fun processCaretExpression(file: TestFile, content: String): String {
|
||||||
val startCaretPosition = content.indexOfOrNull(TAGS.CARET) ?: return content
|
var result = content
|
||||||
|
var match = TAGS.CARET_REGEXP.find(result)
|
||||||
testServices.expressionMarkerProvider.addCaret(file, startCaretPosition)
|
while (match != null) {
|
||||||
return content
|
val startCaretPosition = match.range.first
|
||||||
.replace(TAGS.CARET, "")
|
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 {
|
object TAGS {
|
||||||
const val OPENING_EXPRESSION_TAG = "<expr>"
|
const val OPENING_EXPRESSION_TAG = "<expr>"
|
||||||
const val CLOSING_EXPRESSION_TAG = "</expr>"
|
const val CLOSING_EXPRESSION_TAG = "</expr>"
|
||||||
const val CARET = "<caret>"
|
val CARET_REGEXP = "<caret(_(\\w+))?>".toRegex()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,25 +64,29 @@ class ExpressionMarkerProvider : TestService {
|
|||||||
private val selected = mutableMapOf<String, TextRange>()
|
private val selected = mutableMapOf<String, TextRange>()
|
||||||
|
|
||||||
@PrivateForInline
|
@PrivateForInline
|
||||||
val atCaret = mutableMapOf<String, Int>()
|
val carets = CaretProvider()
|
||||||
|
|
||||||
fun addSelectedExpression(file: TestFile, range: TextRange) {
|
fun addSelectedExpression(file: TestFile, range: TextRange) {
|
||||||
selected[file.relativePath] = range
|
selected[file.relativePath] = range
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(PrivateForInline::class)
|
@OptIn(PrivateForInline::class)
|
||||||
fun addCaret(file: TestFile, caret: Int) {
|
fun addCaret(file: TestFile, caretTag: String?, caretOffset: Int) {
|
||||||
atCaret[file.relativePath] = caret
|
carets.addCaret(file.name, caretTag, caretOffset)
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(PrivateForInline::class)
|
@OptIn(PrivateForInline::class)
|
||||||
fun getCaretPosition(file: KtFile): Int {
|
fun getCaretPosition(file: KtFile, caretTag: String? = null): Int {
|
||||||
return atCaret[file.name]
|
return carets.getCaretOffset(file.name, caretTag)
|
||||||
?: error("No caret found in file")
|
?: run {
|
||||||
|
val caretName = "caret${caretTag?.let { "_$it" }.orEmpty()}"
|
||||||
|
error("No <$caretName> found in file")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified P : KtElement> getElementOfTypAtCaret(file: KtFile): P {
|
inline fun <reified P : KtElement> getElementOfTypAtCaret(file: KtFile, caretName: String? = null): P {
|
||||||
val offset = getCaretPosition(file)
|
val offset = getCaretPosition(file, caretName)
|
||||||
return file.findElementAt(offset)
|
return file.findElementAt(offset)
|
||||||
?.parentOfType<P>()
|
?.parentOfType<P>()
|
||||||
?: error("No expression found at caret")
|
?: error("No expression found at caret")
|
||||||
@@ -98,6 +107,33 @@ class ExpressionMarkerProvider : TestService {
|
|||||||
.dropLastWhile { it is PsiWhiteSpace }
|
.dropLastWhile { it is PsiWhiteSpace }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PrivateForInline
|
||||||
|
class CaretProvider {
|
||||||
|
private val caretToFile = mutableMapOf<String, CaretsInFile>()
|
||||||
|
|
||||||
|
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<String, Int>()
|
||||||
|
|
||||||
|
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()
|
val TestServices.expressionMarkerProvider: ExpressionMarkerProvider by TestServices.testServiceAccessor()
|
||||||
|
|
||||||
fun String.indexOfOrNull(substring: String) =
|
fun String.indexOfOrNull(substring: String) =
|
||||||
|
|||||||
+37
@@ -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<KtFile>, module: TestModule, testServices: TestServices) {
|
||||||
|
val subClass = testServices.expressionMarkerProvider.getElementOfTypAtCaret<KtClassOrObject>(ktFiles.first(), "sub")
|
||||||
|
val superClass = testServices.expressionMarkerProvider.getElementOfTypAtCaret<KtClassOrObject>(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)
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
fun foo() {
|
||||||
|
open class <caret_super>A
|
||||||
|
|
||||||
|
open class <caret_sub>T : A()
|
||||||
|
}
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
IS_SUBCLASS: true
|
||||||
|
IS_DIRECT_SUBCLASS: true
|
||||||
+5
@@ -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.AbstractExpectedExpressionTypeTest
|
||||||
import org.jetbrains.kotlin.analysis.api.impl.base.test.components.expressionTypeProvider.AbstractHLExpressionTypeTest
|
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.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.symbolDeclarationOverridesProvider.AbstractOverriddenDeclarationProviderTest
|
||||||
import org.jetbrains.kotlin.analysis.api.impl.base.test.components.symbolDeclarationRenderer.AbstractRendererTest
|
import org.jetbrains.kotlin.analysis.api.impl.base.test.components.symbolDeclarationRenderer.AbstractRendererTest
|
||||||
import org.jetbrains.kotlin.analysis.api.impl.base.test.components.typeCreator.AbstractTypeParameterTypeTest
|
import org.jetbrains.kotlin.analysis.api.impl.base.test.components.typeCreator.AbstractTypeParameterTypeTest
|
||||||
@@ -195,6 +196,10 @@ private fun TestGroupSuite.generateAnalysisApiComponentsTests() {
|
|||||||
test(AbstractOverriddenDeclarationProviderTest::class) {
|
test(AbstractOverriddenDeclarationProviderTest::class) {
|
||||||
model("overriddenSymbols")
|
model("overriddenSymbols")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test(AbstractIsSubclassOfTest::class) {
|
||||||
|
model("isSubclassOf")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
component("symbolDeclarationRenderer") {
|
component("symbolDeclarationRenderer") {
|
||||||
|
|||||||
Reference in New Issue
Block a user