FIR UAST: fix/test allCommentsInFile in UFile

This commit is contained in:
Jinseong Jeon
2021-05-07 16:20:32 -07:00
committed by Ilya Kirillov
parent 03b5c14944
commit 5dc0b52e38
14 changed files with 286 additions and 52 deletions
@@ -5,12 +5,15 @@
package org.jetbrains.uast.kotlin
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiRecursiveElementWalkingVisitor
import org.jetbrains.kotlin.asJava.findFacadeClass
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.uast.*
import java.util.ArrayList
class FirKotlinUFile(
override val psi: KtFile,
@@ -30,7 +33,15 @@ class FirKotlinUFile(
sourcePsi.packageFqName.asString()
}
override val allCommentsInFile: List<UComment> = comments
override val allCommentsInFile by lz {
val comments = ArrayList<UComment>(0)
psi.accept(object : PsiRecursiveElementWalkingVisitor() {
override fun visitComment(comment: PsiComment) {
comments += UComment(comment, this@FirKotlinUFile)
}
})
comments
}
override val imports: List<UImportStatement> by lz {
sourcePsi.importDirectives.map { FirKotlinUImportStatement(it, this) }
@@ -0,0 +1,6 @@
UFile(allCommentsInFile:
UComment(// Single-line comment bound to fun foo)
UComment(/*
* Multi-line comment bound to extension fun buzz
*/)
)
@@ -3,8 +3,12 @@
package declaration
// Single-line comment bound to fun foo
fun foo(): Int = 42
/*
* Multi-line comment bound to extension fun buzz
*/
fun String.buzz(): String {
return "$this... zzz..."
}
@@ -0,0 +1,5 @@
UFile(allCommentsInFile:
UComment(// file comment)
UComment(// Single-line comment bound to top-level property)
UComment(// Single-line comment bound to object)
)
@@ -1,12 +1,16 @@
import java.lang.Runnable
import java.lang.Thread
// file comment
// Single-line comment bound to top-level property
val topRunnable = object : Runnable {
override fun run() {
println("I'm running")
}
}
// Single-line comment bound to object
object RunnableManager {
val tasks : MutableList<Runnable> = mutableListOf<Runnable>()
@@ -0,0 +1,66 @@
/*
* 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.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.kotlin.internal.KotlinUElementWithComments
import java.io.File
interface FirUastCommentLogTestBase : FirUastPluginSelection, FirUastFileComparisonTestBase {
private fun getCommentsFile(filePath: String, suffix: String): File = getTestMetadataFileFromPath(filePath, "comments$suffix")
private fun getIdenticalCommentsFile(filePath: String): File = getCommentsFile(filePath, TXT)
private fun getPluginCommentsFile(filePath: String): File {
val identicalFile = getIdenticalCommentsFile(filePath)
if (identicalFile.exists()) return identicalFile
return getCommentsFile(filePath, "$pluginSuffix$TXT")
}
private fun UComment.testLog(): String {
return "UComment(${text})"
}
fun check(filePath: String, file: UFile) {
val commentsFile = getPluginCommentsFile(filePath)
val comments = file.asRecursiveLogString { uElement ->
val stringBuilder = StringBuilder()
when (uElement) {
is UFile -> {
if (uElement.allCommentsInFile.isNotEmpty()) {
stringBuilder.append("UFile(allCommentsInFile:\n")
stringBuilder.append(uElement.allCommentsInFile.joinToString(separator = "\n") { it.testLog() })
stringBuilder.append("\n)")
}
}
is KotlinUElementWithComments -> {
if (uElement.comments.isNotEmpty()) {
stringBuilder.append("${uElement::class.java.simpleName}(\n")
uElement.comments.joinToString(separator = "\n") { it.testLog() }
stringBuilder.append("\n)")
}
}
}
stringBuilder.toString()
}
// No comments in the file
if (comments.isEmpty()) return
KotlinTestUtils.assertEqualsToFile(commentsFile, comments)
cleanUpIdenticalFile(
commentsFile,
getCommentsFile(filePath, "$counterpartSuffix$TXT"),
getIdenticalCommentsFile(filePath),
kind = "comments"
)
}
}
@@ -0,0 +1,52 @@
/*
* 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.common.kotlin
import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.test.KtAssert
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
import java.io.File
interface FirUastFileComparisonTestBase {
fun getTestMetadataFileFromPath(filePath: String, ext: String): File {
return File(filePath.removeSuffix(".kt") + '.' + ext)
}
private val isTeamCityBuild: Boolean
get() = System.getenv("TEAMCITY_VERSION") != null
|| KtUsefulTestCase.IS_UNDER_TEAMCITY
fun cleanUpIdenticalFile(
currentFile: File,
counterpartFile: File,
identicalFile: File,
kind: String
) {
// Already cleaned up
if (identicalFile.exists()) return
// Nothing to compare
if (!currentFile.exists() || !counterpartFile.exists()) return
val content = currentFile.readText().trim()
if (content == counterpartFile.readText().trim()) {
val message = if (isTeamCityBuild) {
"Please remove .$kind.fir.txt dump and .$kind.fe10.txt dump"
} else {
currentFile.delete()
counterpartFile.delete()
FileUtil.writeToFile(identicalFile, content)
"Deleted .$kind.fir.txt dump and .$kind.fe10.txt dump, added .$kind.txt instead"
}
KtAssert.fail(
"""
Dump via FIR UAST & via FE10 UAST are the same.
$message
Please re-run the test now
""".trimIndent()
)
}
}
}
@@ -5,8 +5,8 @@
package org.jetbrains.uast.common.kotlin
private const val FE10_SUFFIX = ".fe10"
private const val FIR_SUFFIX = ".fir"
import org.jetbrains.uast.common.kotlin.FirUastTestSuffix.FE10_SUFFIX
import org.jetbrains.uast.common.kotlin.FirUastTestSuffix.FIR_SUFFIX
interface FirUastPluginSelection {
// Whether this is FIR UAST plugin or FE 1.0 UAST plugin
@@ -5,35 +5,29 @@
package org.jetbrains.uast.common.kotlin
import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.KtAssert
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
import org.jetbrains.uast.UFile
import org.jetbrains.uast.asRecursiveLogString
import org.jetbrains.uast.common.kotlin.FirUastTestSuffix.TXT
import java.io.File
interface FirUastRenderLogTestBase : FirUastPluginSelection {
fun getTestMetadataFileFromPath(filePath: String, ext: String): File {
return File(filePath.removeSuffix(".kt") + '.' + ext)
}
interface FirUastRenderLogTestBase : FirUastPluginSelection, FirUastFileComparisonTestBase {
private fun getRenderFile(filePath: String, suffix: String): File = getTestMetadataFileFromPath(filePath, "render$suffix")
private fun getLogFile(filePath: String, suffix: String): File = getTestMetadataFileFromPath(filePath, "log$suffix")
private fun getIdenticalRenderFile(filePath: String): File = getRenderFile(filePath, ".txt")
private fun getIdenticalLogFile(filePath: String): File = getLogFile(filePath, ".txt")
private fun getIdenticalRenderFile(filePath: String): File = getRenderFile(filePath, TXT)
private fun getIdenticalLogFile(filePath: String): File = getLogFile(filePath, TXT)
private fun getPluginRenderFile(filePath: String): File {
val identicalFile = getIdenticalRenderFile(filePath)
if (identicalFile.exists()) return identicalFile
return getRenderFile(filePath, "$pluginSuffix.txt")
return getRenderFile(filePath, "$pluginSuffix$TXT")
}
private fun getPluginLogFile(filePath: String): File {
val identicalFile = getIdenticalLogFile(filePath)
if (identicalFile.exists()) return identicalFile
return getLogFile(filePath, "$pluginSuffix.txt")
return getLogFile(filePath, "$pluginSuffix$TXT")
}
fun check(filePath: String, file: UFile) {
@@ -45,50 +39,15 @@ interface FirUastRenderLogTestBase : FirUastPluginSelection {
cleanUpIdenticalFile(
renderFile,
getRenderFile(filePath, "$counterpartSuffix.txt"),
getRenderFile(filePath, "$counterpartSuffix$TXT"),
getIdenticalRenderFile(filePath),
kind = "render"
)
cleanUpIdenticalFile(
logFile,
getLogFile(filePath, "$counterpartSuffix.txt"),
getLogFile(filePath, "$counterpartSuffix$TXT"),
getIdenticalLogFile(filePath),
kind = "log"
)
}
private val isTeamCityBuild: Boolean
get() = System.getenv("TEAMCITY_VERSION") != null
|| KtUsefulTestCase.IS_UNDER_TEAMCITY
private fun cleanUpIdenticalFile(
currentFile: File,
counterpartFile: File,
identicalFile: File,
kind: String
) {
// Already cleaned up
if (identicalFile.exists()) return
// Nothing to compare
if (!currentFile.exists() || !counterpartFile.exists()) return
val content = currentFile.readText().trim()
if (content == counterpartFile.readText().trim()) {
val message = if (isTeamCityBuild) {
"Please remove .$kind.fir.txt dump and .$kind.fe10.txt dump"
} else {
currentFile.delete()
counterpartFile.delete()
FileUtil.writeToFile(identicalFile, content)
"Deleted .$kind.fir.txt dump and .$kind.fe10.txt dump, added .$kind.txt instead"
}
KtAssert.fail(
"""
Dump via FIR UAST & via FE10 UAST are the same.
$message
Please re-run the test now
""".trimIndent()
)
}
}
}
@@ -0,0 +1,13 @@
/*
* 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.common.kotlin
object FirUastTestSuffix {
internal const val FE10_SUFFIX = ".fe10"
internal const val FIR_SUFFIX = ".fir"
internal const val TXT = ".txt"
}
@@ -0,0 +1,30 @@
/*
* 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 org.jetbrains.uast.UFile
import org.jetbrains.uast.common.kotlin.FirUastCommentLogTestBase
import java.io.File
abstract class AbstractFE1UastCommentsTest : AbstractKotlinUastTest(), FirUastCommentLogTestBase {
override val isFirUastPlugin: Boolean = false
override fun check(filePath: String, file: UFile) {
super<FirUastCommentLogTestBase>.check(filePath, file)
}
override var testDataDir = File("plugins/uast-kotlin-fir/testData")
fun doTest(filePath: String) {
testDataDir = File(filePath).parentFile
val testName = filePath.substring(filePath.lastIndexOf('/') + 1).removeSuffix(".kt")
val virtualFile = getVirtualFile(testName)
val psiFile = psiManager.findFile(virtualFile) ?: error("Can't get psi file for $testName")
val uFile = uastContext.convertElementWithParent(psiFile, null) ?: error("Can't get UFile for $testName")
check(filePath, uFile as UFile)
}
}
@@ -0,0 +1,22 @@
/*
* 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 org.jetbrains.uast.UFile
import org.jetbrains.uast.common.kotlin.FirUastCommentLogTestBase
import org.jetbrains.uast.test.env.kotlin.AbstractFirUastTest
abstract class AbstractFirUastCommentsTest : AbstractFirUastTest(), FirUastCommentLogTestBase {
override val isFirUastPlugin: Boolean = true
override fun check(filePath: String, file: UFile) {
super.check(filePath, file)
}
fun doTest(filePath: String) {
doCheck(filePath)
}
}
@@ -0,0 +1,31 @@
/*
* 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.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
@TestMetadata("plugins/uast-kotlin-fir/testData/declaration")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class FE1UastCommentsTest extends AbstractFE1UastCommentsTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("facade.kt")
public void testFacade() throws Exception {
runTest("plugins/uast-kotlin-fir/testData/declaration/facade.kt");
}
@TestMetadata("objects.kt")
public void testObjects() throws Exception {
runTest("plugins/uast-kotlin-fir/testData/declaration/objects.kt");
}
}
@@ -0,0 +1,31 @@
/*
* 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.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
@TestMetadata("plugins/uast-kotlin-fir/testData/declaration")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class FirUastCommentsTest extends AbstractFirUastCommentsTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("facade.kt")
public void testFacade() throws Exception {
runTest("plugins/uast-kotlin-fir/testData/declaration/facade.kt");
}
@TestMetadata("objects.kt")
public void testObjects() throws Exception {
runTest("plugins/uast-kotlin-fir/testData/declaration/objects.kt");
}
}