UAST: utilize identifier test base

This commit is contained in:
Jinseong Jeon
2021-05-17 00:15:31 -07:00
committed by Ilya Kirillov
parent da15f0ffe8
commit c37123603c
22 changed files with 122 additions and 103 deletions
+1
View File
@@ -364,6 +364,7 @@ extra["tasksWithWarnings"] = listOf(
":kotlin-stdlib-jdk7:compileTestKotlin",
":kotlin-stdlib-jdk8:compileTestKotlin",
":plugins:uast-kotlin-base:compileKotlin",
":plugins:uast-kotlin-base:compileTestKotlin",
":plugins:uast-kotlin:compileKotlin",
":plugins:uast-kotlin:compileTestKotlin",
":plugins:uast-kotlin-fir:compileKotlin",
@@ -11,8 +11,16 @@ dependencies {
// BEWARE: UAST should not depend on IJ platform so that it can work in Android Lint CLI mode (where IDE is not available)
compileOnly(intellijCoreDep()) { includeJars("intellij-core", "asm-all", rootProject = rootProject) }
compileOnly(intellijPluginDep("java")) { includeJars("java-api", "java-impl") }
testImplementation(commonDep("junit:junit"))
testCompileOnly(intellijPluginDep("java")) { includeJars("java-api", "java-impl") }
testImplementation(projectTests(":compiler:tests-common"))
testCompileOnly(intellijDep("ideaIC"))
}
sourceSets {
"main" { projectDefault() }
"test" { projectDefault() }
}
testsJar ()
@@ -1,12 +1,11 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.uast.test.common.kotlin
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiFile
import org.jetbrains.uast.UFile
import kotlin.reflect.KClass
@@ -36,9 +35,9 @@ abstract class IndentedPrintingVisitor(val shouldIndent: (PsiElement) -> Boolean
val result: String
get() = builder.toString()
}
fun IndentedPrintingVisitor.visitUFileAndGetResult(uFile: UFile): String {
(uFile.sourcePsi as PsiFile).accept(this)
return result
}
fun visitUFileAndGetResult(uFile: UFile): String {
uFile.sourcePsi.accept(this)
return result
}
}
@@ -0,0 +1,78 @@
/*
* 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.uast.test.common.kotlin
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.psi.KtBlockExpression
import org.jetbrains.uast.*
import org.jetbrains.uast.visitor.AbstractUastVisitor
import org.jetbrains.uast.test.common.UElementToParentMap
import org.jetbrains.uast.test.common.visitUFileAndGetResult
import org.junit.ComparisonFailure
import kotlin.test.assertNotNull
import kotlin.test.fail
fun UFile.asIdentifiersWithParents() = object : IndentedPrintingVisitor(KtBlockExpression::class) {
override fun render(element: PsiElement): CharSequence? = element.toUElementOfType<UIdentifier>()?.let { uIdentifier ->
StringBuilder().apply {
append(uIdentifier.sourcePsiElement!!.text)
append(" -> ")
append(uIdentifier.uastParent?.asLogString())
}
}
}.visitUFileAndGetResult(this)
fun UFile.testIdentifiersParents() {
accept(object : AbstractUastVisitor() {
override fun visitElement(node: UElement): Boolean {
val uIdentifier = when (node) {
is UAnchorOwner -> node.uastAnchor ?: return false
is UBinaryExpression -> node.operatorIdentifier ?: return false
else -> return false
}
assertParents(node, uIdentifier)
val identifierSourcePsi = uIdentifier.sourcePsi ?: return false
val operatorIdentifierFromSource = identifierSourcePsi.toUElementOfType<UIdentifier>()
?: fail("$identifierSourcePsi of ${identifierSourcePsi.javaClass} should be convertible to UIdentifier")
assertParents(node, operatorIdentifierFromSource)
return false
}
})
}
private fun Sequence<UElement>.log() = this.joinToString { it.asLogString() }
private fun assertParents(node: UElement, uastAnchor: UIdentifier?) {
// skipping such elements because they are ambiguous (properties and getters for instance)
if (node.sourcePsi.toUElement() != node) return
if (uastAnchor == null)
throw AssertionError("no uast anchor for node = $node")
val nodeParents = node.withContainingElements.log()
val anchorParentParents = uastAnchor.uastParent?.withContainingElements?.log() ?: ""
// dropping node itself because we allow children to share identifiers with parents (primary constructor for instance)
val parentsSuffix = node.withContainingElements.drop(1).log()
if (!anchorParentParents.endsWith(parentsSuffix))
throw ComparisonFailure(
"wrong parents for '${uastAnchor.sourcePsi?.text}' owner: $node[${node.sourcePsi}[${node.sourcePsi?.text}]]",
nodeParents,
anchorParentParents
)
}
private fun refNameRetriever(psiElement: PsiElement): UElement? =
when (val uElement = psiElement.toUElementOfExpectedTypes(UCallExpression::class.java, UReferenceExpression::class.java)) {
is UReferenceExpression -> uElement.referenceNameElement
is UCallExpression -> uElement.classReference?.referenceNameElement
else -> null
}?.also {
assertNotNull(it.sourcePsi, "referenceNameElement should have physical source, origin = $psiElement")
}
fun UFile.asRefNames() = object : UElementToParentMap(::refNameRetriever) {
override fun renderSource(element: PsiElement): String = element.javaClass.simpleName
}.visitUFileAndGetResult(this)
+3 -1
View File
@@ -25,15 +25,17 @@ dependencies {
implementation(project(":idea:idea-frontend-api"))
implementation(project(":idea:idea-frontend-fir"))
testImplementation(toolsJar())
testImplementation(commonDep("junit:junit"))
testCompileOnly(intellijPluginDep("java")) { includeJars("java-api", "java-impl") }
testImplementation(projectTests(":compiler:tests-common"))
testImplementation(projectTests(":idea:idea-test-framework"))
testImplementation(projectTests(":idea"))
testImplementation(projectTests(":idea:idea-fir"))
testImplementation(projectTests(":plugins:uast-kotlin-base"))
// To compare various aspects (e.g., render, log, type, value, etc.) against legacy UAST Kotlin
testImplementation(projectTests(":plugins:uast-kotlin"))
testRuntimeOnly(toolsJar())
}
sourceSets {
@@ -3,7 +3,7 @@
* 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.uast.common.kotlin
package org.jetbrains.uast.test.common.kotlin
import java.io.File
@@ -3,13 +3,13 @@
* 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.uast.common.kotlin
package org.jetbrains.uast.test.common.kotlin
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.uast.UComment
import org.jetbrains.uast.UFile
import org.jetbrains.uast.asRecursiveLogString
import org.jetbrains.uast.common.kotlin.FirUastTestSuffix.TXT
import org.jetbrains.uast.test.common.kotlin.FirUastTestSuffix.TXT
import org.jetbrains.uast.kotlin.internal.KotlinUElementWithComments
import java.io.File
@@ -3,7 +3,7 @@
* 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.uast.common.kotlin
package org.jetbrains.uast.test.common.kotlin
import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.test.KtAssert
@@ -3,10 +3,10 @@
* 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.uast.common.kotlin
package org.jetbrains.uast.test.common.kotlin
import org.jetbrains.uast.common.kotlin.FirUastTestSuffix.FE10_SUFFIX
import org.jetbrains.uast.common.kotlin.FirUastTestSuffix.FIR_SUFFIX
import org.jetbrains.uast.test.common.kotlin.FirUastTestSuffix.FE10_SUFFIX
import org.jetbrains.uast.test.common.kotlin.FirUastTestSuffix.FIR_SUFFIX
interface FirUastPluginSelection {
// Whether this is FIR UAST plugin or FE 1.0 UAST plugin
@@ -3,12 +3,12 @@
* 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.uast.common.kotlin
package org.jetbrains.uast.test.common.kotlin
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.uast.UFile
import org.jetbrains.uast.asRecursiveLogString
import org.jetbrains.uast.common.kotlin.FirUastTestSuffix.TXT
import org.jetbrains.uast.test.common.kotlin.FirUastTestSuffix.TXT
import java.io.File
interface FirUastRenderLogTestBase : FirUastPluginSelection, FirUastFileComparisonTestBase {
@@ -3,7 +3,7 @@
* 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.uast.common.kotlin
package org.jetbrains.uast.test.common.kotlin
object FirUastTestSuffix {
internal const val FE10_SUFFIX = ".fe10"
@@ -18,11 +18,11 @@ import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.uast.UFile
import org.jetbrains.uast.UastFacade
import org.jetbrains.uast.UastLanguagePlugin
import org.jetbrains.uast.common.kotlin.FirUastPluginSelection
import org.jetbrains.uast.kotlin.BaseKotlinUastResolveProviderService
import org.jetbrains.uast.kotlin.FirKotlinUastResolveProviderService
import org.jetbrains.uast.kotlin.firKotlinUastPlugin
import org.jetbrains.uast.kotlin.internal.FirCliKotlinUastResolveProviderService
import org.jetbrains.uast.test.common.kotlin.FirUastPluginSelection
import java.io.File
abstract class AbstractFirUastTest : KotlinLightCodeInsightFixtureTestCase(), FirUastPluginSelection {
@@ -5,6 +5,6 @@
package org.jetbrains.uast.test.kotlin
import org.jetbrains.uast.common.kotlin.FirLegacyUastRenderLogTestBase
import org.jetbrains.uast.test.common.kotlin.FirLegacyUastRenderLogTestBase
abstract class AbstractFE1LegacyUastDeclarationTest : AbstractFE1UastDeclarationTest(), FirLegacyUastRenderLogTestBase
@@ -6,7 +6,7 @@
package org.jetbrains.uast.test.kotlin
import org.jetbrains.uast.UFile
import org.jetbrains.uast.common.kotlin.FirUastCommentLogTestBase
import org.jetbrains.uast.test.common.kotlin.FirUastCommentLogTestBase
import java.io.File
abstract class AbstractFE1UastCommentsTest : AbstractKotlinUastTest(), FirUastCommentLogTestBase {
@@ -6,7 +6,7 @@
package org.jetbrains.uast.test.kotlin
import org.jetbrains.uast.UFile
import org.jetbrains.uast.common.kotlin.FirUastRenderLogTestBase
import org.jetbrains.uast.test.common.kotlin.FirUastRenderLogTestBase
import java.io.File
abstract class AbstractFE1UastDeclarationTest : AbstractKotlinUastTest(), FirUastRenderLogTestBase {
@@ -5,6 +5,6 @@
package org.jetbrains.uast.test.kotlin
import org.jetbrains.uast.common.kotlin.FirLegacyUastRenderLogTestBase
import org.jetbrains.uast.test.common.kotlin.FirLegacyUastRenderLogTestBase
abstract class AbstractFirLegacyUastDeclarationTest : AbstractFirUastDeclarationTest(), FirLegacyUastRenderLogTestBase
@@ -6,7 +6,7 @@
package org.jetbrains.uast.test.kotlin
import org.jetbrains.uast.UFile
import org.jetbrains.uast.common.kotlin.FirUastCommentLogTestBase
import org.jetbrains.uast.test.common.kotlin.FirUastCommentLogTestBase
import org.jetbrains.uast.test.env.kotlin.AbstractFirUastTest
abstract class AbstractFirUastCommentsTest : AbstractFirUastTest(), FirUastCommentLogTestBase {
@@ -6,7 +6,7 @@
package org.jetbrains.uast.test.kotlin
import org.jetbrains.uast.UFile
import org.jetbrains.uast.common.kotlin.FirUastRenderLogTestBase
import org.jetbrains.uast.test.common.kotlin.FirUastRenderLogTestBase
import org.jetbrains.uast.test.env.kotlin.AbstractFirUastTest
abstract class AbstractFirUastDeclarationTest : AbstractFirUastTest(), FirUastRenderLogTestBase {
+1
View File
@@ -44,6 +44,7 @@ dependencies {
testCompile(project(":compiler:util"))
testCompile(project(":compiler:cli"))
testCompile(projectTests(":idea:idea-test-framework"))
testCompile(projectTests(":plugins:uast-kotlin-base"))
testCompile(project(":idea:idea-native")) { isTransitive = false }
testCompile(project(":idea:idea-gradle-native")) { isTransitive = false }
@@ -1,14 +1,14 @@
/*
* 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.uast.test.kotlin
import com.intellij.psi.PsiElement
import org.jetbrains.uast.*
import org.jetbrains.uast.test.common.UElementToParentMap
import org.jetbrains.uast.UFile
import org.jetbrains.uast.test.common.kotlin.IdentifiersTestBase
import org.jetbrains.uast.test.common.visitUFileAndGetResult
import org.jetbrains.uast.test.common.kotlin.asRefNames
import org.jetbrains.uast.test.env.kotlin.assertEqualsToFile
import java.io.File
import kotlin.test.assertNotNull
abstract class AbstractKotlinIdentifiersTest : AbstractKotlinUastTest(), IdentifiersTestBase {
@@ -22,16 +22,3 @@ abstract class AbstractKotlinIdentifiersTest : AbstractKotlinUastTest(), Identif
assertEqualsToFile("refNames", getTestFile(testName, "refNames.txt"), file.asRefNames())
}
}
private fun refNameRetriever(psiElement: PsiElement): UElement? =
when (val uElement = psiElement.toUElementOfExpectedTypes(UCallExpression::class.java, UReferenceExpression::class.java)) {
is UReferenceExpression -> uElement.referenceNameElement
is UCallExpression -> uElement.classReference?.referenceNameElement
else -> null
}?.also {
assertNotNull(it.sourcePsi, "referenceNameElement should have physical source, origin = $psiElement")
}
fun UFile.asRefNames() = object : UElementToParentMap(::refNameRetriever) {
override fun renderSource(element: PsiElement): String = element.javaClass.simpleName
}.visitUFileAndGetResult(this)
@@ -11,17 +11,14 @@ import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.uast.*
import org.jetbrains.uast.test.common.kotlin.IndentedPrintingVisitor
import org.jetbrains.uast.test.common.kotlin.visitUFileAndGetResult
import org.jetbrains.uast.test.env.kotlin.assertEqualsToFile
import java.io.File
abstract class AbstractKotlinResolveEverythingTest : AbstractKotlinUastTest() {
private fun getTestFile(testName: String, ext: String) =
File(File(TEST_KOTLIN_MODEL_DIR, testName).canonicalPath + '.' + ext)
private fun UFile.resolvableWithTargets() = object : IndentedPrintingVisitor(KtBlockExpression::class) {
override fun render(element: PsiElement) =
UastFacade.convertToAlternatives<UExpression>(element, arrayOf(UReferenceExpression::class.java, UCallExpression::class.java))
@@ -57,4 +54,4 @@ abstract class AbstractKotlinResolveEverythingTest : AbstractKotlinUastTest() {
override fun check(testName: String, file: UFile) {
assertEqualsToFile("resolved", getTestFile(testName, "resolved.txt"), file.resolvableWithTargets())
}
}
}
@@ -5,67 +5,13 @@
package org.jetbrains.uast.test.common.kotlin
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.psi.KtBlockExpression
import org.jetbrains.uast.*
import org.jetbrains.uast.UFile
import org.jetbrains.uast.test.env.kotlin.assertEqualsToFile
import org.jetbrains.uast.visitor.AbstractUastVisitor
import org.junit.ComparisonFailure
import java.io.File
import kotlin.test.fail
interface IdentifiersTestBase {
fun getIdentifiersFile(testName: String): File
private fun UFile.asIdentifiersWithParents() = object : IndentedPrintingVisitor(KtBlockExpression::class) {
override fun render(element: PsiElement): CharSequence? = element.toUElementOfType<UIdentifier>()?.let { uIdentifier ->
StringBuilder().apply {
append(uIdentifier.sourcePsiElement!!.text)
append(" -> ")
append(uIdentifier.uastParent?.asLogString())
}
}
}.visitUFileAndGetResult(this)
private fun UFile.testIdentifiersParents() {
accept(object : AbstractUastVisitor() {
override fun visitElement(node: UElement): Boolean {
val uIdentifier = when (node) {
is UAnchorOwner -> node.uastAnchor ?: return false
is UBinaryExpression -> node.operatorIdentifier ?: return false
else -> return false
}
assertParents(node, uIdentifier)
val identifierSourcePsi = uIdentifier.sourcePsi ?: return false
val operatorIdentifierFromSource = identifierSourcePsi.toUElementOfType<UIdentifier>()
?: fail("$identifierSourcePsi of ${identifierSourcePsi.javaClass} should be convertable to UIdentifier")
assertParents(node, operatorIdentifierFromSource)
return false
}
})
}
fun assertParents(node: UElement, uastAnchor: UIdentifier?) {
//skipping such elements because they are ambiguous (properties and getters for instance)
if (node.sourcePsi.toUElement() != node) return
if (uastAnchor == null)
throw AssertionError("no uast anchor for node = $node")
val nodeParents = node.withContainingElements.log()
val anchorParentParents = uastAnchor.uastParent?.withContainingElements?.log() ?: ""
// dropping node itself because we allow children to share identifiers with parents (primary constructor for instance)
val parentsSuffix = node.withContainingElements.drop(1).log()
if (!anchorParentParents.endsWith(parentsSuffix))
throw ComparisonFailure(
"wrong parents for '${uastAnchor.sourcePsi?.text}' owner: $node[${node.sourcePsi}[${node.sourcePsi?.text}]]",
nodeParents,
anchorParentParents
)
}
private fun Sequence<UElement>.log() = this.joinToString { it.asLogString() }
fun check(testName: String, file: UFile) {
val valuesFile = getIdentifiersFile(testName)