Add tests for enhanced java signatures based on AbstractResolvedCallsTest.
Refactor AbstractResolvedCallsTest to support multiple carets (multiple methods being tested for resolve) in testdata file.
This commit is contained in:
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||
import org.jetbrains.kotlin.test.TestJdkKind
|
||||
|
||||
abstract class AbstractEnhancedSignaturesResolvedCallsTest : AbstractResolvedCallsTest() {
|
||||
// requires full JDK with various Java API: java.util.Optional, java.util.Map
|
||||
override fun createEnvironment(): KotlinCoreEnvironment = createEnvironmentWithJdk(ConfigurationKind.ALL, TestJdkKind.FULL_JDK)
|
||||
|
||||
override fun renderOutput(originalText: String, text: String, resolvedCallsAt: List<Pair<Int, ResolvedCall<*>?>>): String {
|
||||
val lines = text.lines()
|
||||
val lineOffsets = run {
|
||||
var offset = 0
|
||||
lines.map { offset.apply { offset += it.length + 1 /* new-line delimiter */ } }
|
||||
}
|
||||
fun lineIndexAt(caret: Int): Int =
|
||||
lineOffsets.binarySearch(caret).let { result ->
|
||||
if (result < 0) result.inv() - 1 else result }
|
||||
|
||||
|
||||
val callsByLine = resolvedCallsAt.groupBy ({ (caret) -> lineIndexAt(caret) }, { (_, resolvedCall) -> resolvedCall })
|
||||
|
||||
return buildString {
|
||||
lines.forEachIndexed { lineIndex, line ->
|
||||
appendln(line)
|
||||
callsByLine[lineIndex]?.let { calls ->
|
||||
val indent = line.takeWhile(Char::isWhitespace) + " "
|
||||
calls.forEach { resolvedCall ->
|
||||
appendln("$indent// ${resolvedCall?.status}")
|
||||
appendln("$indent// ORIGINAL: ${resolvedCall?.run { resultingDescriptor!!.original.getText() }}")
|
||||
appendln("$indent// SUBSTITUTED: ${resolvedCall?.run { resultingDescriptor!!.getText() }}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+44
-16
@@ -48,34 +48,62 @@ abstract class AbstractResolvedCallsTest : KotlinTestWithEnvironment() {
|
||||
override fun createEnvironment(): KotlinCoreEnvironment = createEnvironmentWithMockJdk(ConfigurationKind.ALL)
|
||||
|
||||
fun doTest(filePath: String) {
|
||||
val text = KotlinTestUtils.doLoadFile(File(filePath))!!
|
||||
val originalText = KotlinTestUtils.doLoadFile(File(filePath))!!
|
||||
val (text, carets) = extractCarets(originalText)
|
||||
|
||||
val ktFile = KtPsiFactory(project).createFile(text.replace("<caret>", ""))
|
||||
val ktFile = KtPsiFactory(project).createFile(text)
|
||||
val bindingContext = JvmResolveUtil.analyze(ktFile, environment).bindingContext
|
||||
|
||||
val (element, cachedCall) = buildCachedCall(bindingContext, ktFile, text)
|
||||
val resolvedCallsAt = carets.map { caret -> caret to run {
|
||||
val (element, cachedCall) = buildCachedCallAtIndex(bindingContext, ktFile, caret)
|
||||
|
||||
val resolvedCall = if (cachedCall !is VariableAsFunctionResolvedCall) cachedCall
|
||||
else if ("(" == element?.text) cachedCall.functionCall
|
||||
else cachedCall.variableCall
|
||||
val resolvedCall = when {
|
||||
cachedCall !is VariableAsFunctionResolvedCall -> cachedCall
|
||||
"(" == element?.text -> cachedCall.functionCall
|
||||
else -> cachedCall.variableCall
|
||||
}
|
||||
|
||||
resolvedCall
|
||||
}}
|
||||
|
||||
val output = renderOutput(originalText, text, resolvedCallsAt)
|
||||
|
||||
val resolvedCallInfoFileName = FileUtil.getNameWithoutExtension(filePath) + ".txt"
|
||||
KotlinTestUtils.assertEqualsToFile(File(resolvedCallInfoFileName), "$text\n\n\n${resolvedCall?.renderToText()}")
|
||||
KotlinTestUtils.assertEqualsToFile(File(resolvedCallInfoFileName), output)
|
||||
}
|
||||
|
||||
open protected fun buildCachedCall(
|
||||
bindingContext: BindingContext, jetFile: KtFile, text: String
|
||||
protected open fun renderOutput(originalText: String, text: String, resolvedCallsAt: List<Pair<Int, ResolvedCall<*>?>>): String =
|
||||
resolvedCallsAt.joinToString("\n\n", prefix = "$originalText\n\n\n") { (_, resolvedCall) ->
|
||||
resolvedCall?.renderToText().toString()
|
||||
}
|
||||
|
||||
protected fun extractCarets(text: String): Pair<String, List<Int>> {
|
||||
val parts = text.split("<caret>")
|
||||
if (parts.size < 2) return text to emptyList()
|
||||
// possible to rewrite using 'scan' function to get partial sums of parts lengths
|
||||
val indices = mutableListOf<Int>()
|
||||
val resultText = buildString {
|
||||
parts.dropLast(1).forEach { part ->
|
||||
append(part)
|
||||
indices.add(this.length)
|
||||
}
|
||||
append(parts.last())
|
||||
}
|
||||
return resultText to indices
|
||||
}
|
||||
|
||||
protected open fun buildCachedCallAtIndex(
|
||||
bindingContext: BindingContext, jetFile: KtFile, index: Int
|
||||
): Pair<PsiElement?, ResolvedCall<out CallableDescriptor>?> {
|
||||
val element = jetFile.findElementAt(text.indexOf("<caret>"))!!
|
||||
val element = jetFile.findElementAt(index)!!
|
||||
val expression = element.getStrictParentOfType<KtExpression>()
|
||||
|
||||
val cachedCall = expression?.getParentResolvedCall(bindingContext, strict = false)
|
||||
return Pair(element, cachedCall)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun Receiver?.getText() = when (this) {
|
||||
internal fun Receiver?.getText() = when (this) {
|
||||
is ExpressionReceiver -> "${expression.text} {${type}}"
|
||||
is ImplicitClassReceiver -> "Class{${type}}"
|
||||
is ExtensionReceiver -> "${type}Ext{${declarationDescriptor.getText()}}"
|
||||
@@ -83,9 +111,9 @@ private fun Receiver?.getText() = when (this) {
|
||||
else -> toString()
|
||||
}
|
||||
|
||||
private fun ValueArgument.getText() = this.getArgumentExpression()?.text?.replace("\n", " ") ?: ""
|
||||
internal fun ValueArgument.getText() = this.getArgumentExpression()?.text?.replace("\n", " ") ?: ""
|
||||
|
||||
private fun ArgumentMapping.getText() = when (this) {
|
||||
internal fun ArgumentMapping.getText() = when (this) {
|
||||
is ArgumentMatch -> {
|
||||
val parameterType = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(valueParameter.type)
|
||||
"${status.name} ${valueParameter.name} : ${parameterType} ="
|
||||
@@ -93,12 +121,12 @@ private fun ArgumentMapping.getText() = when (this) {
|
||||
else -> "ARGUMENT UNMAPPED: "
|
||||
}
|
||||
|
||||
private fun DeclarationDescriptor.getText(): String = when (this) {
|
||||
internal fun DeclarationDescriptor.getText(): String = when (this) {
|
||||
is ReceiverParameterDescriptor -> "${value.getText()}::this"
|
||||
else -> DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.render(this)
|
||||
}
|
||||
|
||||
private fun ResolvedCall<*>.renderToText(): String {
|
||||
internal fun ResolvedCall<*>.renderToText(): String {
|
||||
return buildString {
|
||||
appendln("Resolved call:")
|
||||
appendln()
|
||||
|
||||
+3
-3
@@ -27,10 +27,10 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
|
||||
|
||||
abstract class AbstractResolvedConstructorDelegationCallsTests : AbstractResolvedCallsTest() {
|
||||
override fun buildCachedCall(
|
||||
bindingContext: BindingContext, jetFile: KtFile, text: String
|
||||
override fun buildCachedCallAtIndex(
|
||||
bindingContext: BindingContext, jetFile: KtFile, index: Int
|
||||
): Pair<PsiElement?, ResolvedCall<out CallableDescriptor>?> {
|
||||
val element = jetFile.findElementAt(text.indexOf("<caret>"))
|
||||
val element = jetFile.findElementAt(index)
|
||||
val constructor = element?.getNonStrictParentOfType<KtSecondaryConstructor>()!!
|
||||
val delegationCall = constructor.getDelegationCall()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user