Handle erroneous code (initial drop, TBD).
This commit is contained in:
committed by
Dmitry Petrov
parent
bf03be97a1
commit
fe397eddbe
+1
-1
@@ -38,7 +38,7 @@ class DeclarationGenerator(override val context: GeneratorContext) : Generator {
|
||||
is KtTypeAlias ->
|
||||
generateTypeAliasDeclaration(ktDeclaration)
|
||||
else ->
|
||||
IrDummyDeclaration(
|
||||
IrErrorDeclarationImpl(
|
||||
ktDeclaration.startOffset, ktDeclaration.endOffset,
|
||||
getOrFail(BindingContext.DECLARATION_TO_DESCRIPTOR, ktDeclaration)
|
||||
)
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.psi2ir.generators
|
||||
|
||||
import org.jetbrains.kotlin.ir.expressions.IrErrorCallExpressionImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrErrorExpressionImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
|
||||
class ErrorExpressionGenerator(statementGenerator: StatementGenerator) : StatementGeneratorExtension(statementGenerator) {
|
||||
fun generateErrorExpression(ktElement: KtElement, message: String?): IrExpression =
|
||||
IrErrorExpressionImpl(ktElement.startOffset, ktElement.endOffset,
|
||||
if (ktElement is KtExpression) getErrorExpressionType(ktElement) else ErrorUtils.createErrorType(""),
|
||||
message ?: "")
|
||||
|
||||
|
||||
fun generateErrorCall(ktCall: KtCallExpression): IrExpression {
|
||||
val type = getErrorExpressionType(ktCall)
|
||||
|
||||
val irErrorCall = IrErrorCallExpressionImpl(ktCall.startOffset, ktCall.endOffset, type, "") // TODO problem description?
|
||||
irErrorCall.explicitReceiver = (ktCall.parent as? KtDotQualifiedExpression)?.let {
|
||||
statementGenerator.generateExpression(it.receiverExpression)
|
||||
}
|
||||
|
||||
ktCall.valueArguments.forEach {
|
||||
val ktArgument = it.getArgumentExpression()
|
||||
if (ktArgument != null) {
|
||||
irErrorCall.addArgument(statementGenerator.generateExpression(ktArgument))
|
||||
}
|
||||
}
|
||||
|
||||
ktCall.lambdaArguments.forEach {
|
||||
irErrorCall.addArgument(statementGenerator.generateExpression(it.getArgumentExpression()))
|
||||
}
|
||||
|
||||
return irErrorCall
|
||||
}
|
||||
|
||||
private fun getErrorExpressionType(ktExpression: KtExpression) =
|
||||
getInferredTypeWithImplicitCasts(ktExpression) ?: ErrorUtils.createErrorType("")
|
||||
|
||||
fun generateErrorExpression(ktName: KtSimpleNameExpression): IrExpression {
|
||||
val type = getErrorExpressionType(ktName)
|
||||
|
||||
val irErrorCall = IrErrorCallExpressionImpl(ktName.startOffset, ktName.endOffset, type, "") // TODO problem description?
|
||||
irErrorCall.explicitReceiver = (ktName.parent as? KtDotQualifiedExpression)?.let {
|
||||
statementGenerator.generateExpression(it.receiverExpression)
|
||||
}
|
||||
|
||||
return irErrorCall
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
package org.jetbrains.kotlin.psi2ir.generators
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.ir.expressions.IrDummyExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrErrorExpressionImpl
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
@@ -57,5 +57,5 @@ fun Generator.getInferredTypeWithImplicitCastsOrFail(key: KtExpression): KotlinT
|
||||
fun Generator.getResolvedCall(key: KtElement): ResolvedCall<out CallableDescriptor>? =
|
||||
key.getResolvedCall(context.bindingContext)
|
||||
|
||||
fun Generator.createDummyExpression(ktExpression: KtExpression, description: String): IrDummyExpression =
|
||||
IrDummyExpression(ktExpression.startOffset, ktExpression.endOffset, getInferredTypeWithImplicitCastsOrFail(ktExpression), description)
|
||||
fun Generator.createDummyExpression(ktExpression: KtExpression, description: String): IrErrorExpressionImpl =
|
||||
IrErrorExpressionImpl(ktExpression.startOffset, ktExpression.endOffset, getInferredTypeWithImplicitCastsOrFail(ktExpression), description)
|
||||
+10
-6
@@ -56,7 +56,12 @@ class StatementGenerator(
|
||||
ktExpression.genExpr()
|
||||
|
||||
private fun KtElement.genStmt(): IrStatement =
|
||||
deparenthesize().accept(this@StatementGenerator, null)
|
||||
try {
|
||||
deparenthesize().accept(this@StatementGenerator, null)
|
||||
}
|
||||
catch (e: Exception) {
|
||||
ErrorExpressionGenerator(this@StatementGenerator).generateErrorExpression(this, e.message)
|
||||
}
|
||||
|
||||
private fun KtElement.genExpr(): IrExpression =
|
||||
genStmt().assertCast()
|
||||
@@ -220,9 +225,7 @@ class StatementGenerator(
|
||||
|
||||
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression, data: Nothing?): IrExpression {
|
||||
val resolvedCall = getResolvedCall(expression) ?:
|
||||
return IrDummyExpression(expression.startOffset, expression.endOffset,
|
||||
context.builtIns.nothingType,
|
||||
"No resolved call for ${expression.text}")
|
||||
return ErrorExpressionGenerator(this).generateErrorExpression(expression)
|
||||
|
||||
if (resolvedCall is VariableAsFunctionResolvedCall) {
|
||||
val variableCall = pregenerateCall(resolvedCall.variableCall)
|
||||
@@ -257,14 +260,15 @@ class StatementGenerator(
|
||||
is VariableDescriptor ->
|
||||
CallGenerator(this).generateGetVariable(expression.startOffset, expression.endOffset, descriptor)
|
||||
else ->
|
||||
IrDummyExpression(
|
||||
IrErrorExpressionImpl(
|
||||
expression.startOffset, expression.endOffset, getInferredTypeWithImplicitCastsOrFail(expression),
|
||||
expression.text + ": ${descriptor.name} ${descriptor.javaClass.simpleName}"
|
||||
)
|
||||
}
|
||||
|
||||
override fun visitCallExpression(expression: KtCallExpression, data: Nothing?): IrStatement {
|
||||
val resolvedCall = getResolvedCall(expression) ?: TODO("No resolved call for call expression")
|
||||
val resolvedCall = getResolvedCall(expression) ?:
|
||||
return ErrorExpressionGenerator(this).generateErrorCall(expression)
|
||||
|
||||
if (resolvedCall is VariableAsFunctionResolvedCall) {
|
||||
val functionCall = pregenerateCall(resolvedCall.functionCall)
|
||||
|
||||
@@ -33,12 +33,14 @@ abstract class AbstractIrGeneratorTestCase : CodegenTestCase() {
|
||||
|
||||
protected abstract fun doTest(wholeFile: File, testFiles: List<TestFile>)
|
||||
|
||||
protected fun generateIrFilesAsSingleModule(testFiles: List<TestFile>): Map<TestFile, IrFile> {
|
||||
protected fun generateIrFilesAsSingleModule(testFiles: List<TestFile>, ignoreErrors: Boolean = false): Map<TestFile, IrFile> {
|
||||
assert(myFiles != null) { "myFiles not initialized" }
|
||||
assert(myEnvironment != null) { "myEnvironment not initialized" }
|
||||
val analysisResult = JvmResolveUtil.analyzeAndCheckForErrors(myFiles.psiFiles, myEnvironment)
|
||||
analysisResult.throwIfError()
|
||||
AnalyzingUtils.throwExceptionOnErrors(analysisResult.bindingContext)
|
||||
val analysisResult = JvmResolveUtil.analyze(myFiles.psiFiles, myEnvironment)
|
||||
if (!ignoreErrors) {
|
||||
analysisResult.throwIfError()
|
||||
AnalyzingUtils.throwExceptionOnErrors(analysisResult.bindingContext)
|
||||
}
|
||||
val psi2ir = Psi2IrTranslator()
|
||||
val irModule = psi2ir.generateModule(analysisResult.moduleDescriptor, myFiles.psiFiles, analysisResult.bindingContext)
|
||||
val ktFiles = testFiles.filter { it.name.endsWith(".kt") }
|
||||
|
||||
@@ -32,7 +32,8 @@ import java.util.regex.Pattern
|
||||
abstract class AbstractIrTextTestCase : AbstractIrGeneratorTestCase() {
|
||||
override fun doTest(wholeFile: File, testFiles: List<TestFile>) {
|
||||
val dir = wholeFile.parentFile
|
||||
for ((testFile, irFile) in generateIrFilesAsSingleModule(testFiles)) {
|
||||
val ignoreErrors = shouldIgnoreErrors(wholeFile)
|
||||
for ((testFile, irFile) in generateIrFilesAsSingleModule(testFiles, ignoreErrors)) {
|
||||
doTestIrFileAgainstExpectations(dir, testFile, irFile)
|
||||
}
|
||||
}
|
||||
@@ -74,6 +75,10 @@ abstract class AbstractIrTextTestCase : AbstractIrGeneratorTestCase() {
|
||||
companion object {
|
||||
private val EXPECTED_OCCURRENCES_PATTERN = Regex("""^\s*//\s*(\d+)\s*(.*)$""")
|
||||
private val IR_TREES_TXT_PATTERN = Regex("""// \s*<<<\s+(.*)$""")
|
||||
private val IGNORE_ERRORS_PATTERN = Regex("""// !IGNORE_ERRORS""")
|
||||
|
||||
internal fun shouldIgnoreErrors(wholeFile: File): Boolean =
|
||||
IGNORE_ERRORS_PATTERN.containsMatchIn(wholeFile.readText())
|
||||
|
||||
internal fun parseExpectations(dir: File, testFile: TestFile): Expectations {
|
||||
val regexps = ArrayList<RegexpInText>()
|
||||
|
||||
+5
-3
@@ -21,15 +21,17 @@ import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.throwNoSuchSlot
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
|
||||
class IrDummyDeclaration(
|
||||
interface IrErrorDeclaration : IrDeclaration
|
||||
|
||||
class IrErrorDeclarationImpl(
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
override val descriptor: DeclarationDescriptor
|
||||
) : IrDeclarationBase(startOffset, endOffset, IrDeclarationOrigin.DEFINED) {
|
||||
) : IrDeclarationBase(startOffset, endOffset, IrDeclarationOrigin.DEFINED), IrErrorDeclaration {
|
||||
override val declarationKind: IrDeclarationKind get() = IrDeclarationKind.DUMMY
|
||||
|
||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
|
||||
return visitor.visitDummyDeclaration(this, data)
|
||||
return visitor.visitErrorDeclaration(this, data)
|
||||
}
|
||||
|
||||
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* 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.ir.expressions
|
||||
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class IrDummyExpression(
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
type: KotlinType,
|
||||
val description: String
|
||||
) : IrTerminalExpressionBase(startOffset, endOffset, type), IrExpressionWithCopy {
|
||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||
visitor.visitDummyExpression(this, data)
|
||||
|
||||
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
||||
// No children
|
||||
}
|
||||
|
||||
override fun copy(): IrDummyExpression =
|
||||
IrDummyExpression(startOffset, endOffset, type, description)
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.ir.expressions
|
||||
|
||||
import org.jetbrains.kotlin.ir.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
|
||||
interface IrErrorExpression : IrExpression {
|
||||
val description: String
|
||||
}
|
||||
|
||||
interface IrErrorCallExpression : IrErrorExpression {
|
||||
var explicitReceiver: IrExpression?
|
||||
val arguments: List<IrExpression>
|
||||
}
|
||||
|
||||
class IrErrorExpressionImpl(
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
type: KotlinType,
|
||||
override val description: String
|
||||
) : IrTerminalExpressionBase(startOffset, endOffset, type), IrExpressionWithCopy, IrErrorExpression {
|
||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||
visitor.visitErrorExpression(this, data)
|
||||
|
||||
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
||||
// No children
|
||||
}
|
||||
|
||||
override fun copy(): IrErrorExpressionImpl =
|
||||
IrErrorExpressionImpl(startOffset, endOffset, type, description)
|
||||
}
|
||||
|
||||
class IrErrorCallExpressionImpl(
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
type: KotlinType,
|
||||
override val description: String
|
||||
) : IrExpressionBase(startOffset, endOffset, type), IrErrorCallExpression {
|
||||
override var explicitReceiver: IrExpression? = null
|
||||
set(value) {
|
||||
value?.assertDetached()
|
||||
field?.detach()
|
||||
field = value
|
||||
value?.setTreeLocation(this, DISPATCH_RECEIVER_SLOT)
|
||||
}
|
||||
|
||||
override val arguments: MutableList<IrExpression> = SmartList()
|
||||
|
||||
fun addArgument(argument: IrExpression) {
|
||||
argument.assertDetached()
|
||||
argument.setTreeLocation(this, arguments.size)
|
||||
arguments.add(argument)
|
||||
}
|
||||
|
||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
|
||||
return visitor.visitErrorCallExpression(this, data)
|
||||
}
|
||||
|
||||
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
||||
explicitReceiver?.accept(visitor, data)
|
||||
arguments.forEach { it.accept(visitor, data) }
|
||||
}
|
||||
|
||||
override fun getChild(slot: Int): IrElement? =
|
||||
arguments.getOrNull(slot)
|
||||
|
||||
override fun replaceChild(slot: Int, newChild: IrElement) {
|
||||
newChild.assertDetached()
|
||||
arguments[slot].detach()
|
||||
arguments[slot] = newChild.assertCast()
|
||||
newChild.setTreeLocation(this, slot)
|
||||
}
|
||||
}
|
||||
@@ -59,6 +59,13 @@ class DumpIrTreeVisitor(out: Appendable): IrElementVisitor<Unit, String> {
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitErrorCallExpression(expression: IrErrorCallExpression, data: String) {
|
||||
expression.dumpLabeledElementWith(data) {
|
||||
expression.explicitReceiver?.accept(this, "receiver")
|
||||
expression.arguments.forEach { it.accept(this, "") }
|
||||
}
|
||||
}
|
||||
|
||||
private fun visitFunctionWithParameters(declaration: IrFunction, data: String) {
|
||||
declaration.dumpLabeledElementWith(data) {
|
||||
declaration.descriptor.valueParameters.forEach { valueParameter ->
|
||||
|
||||
@@ -182,11 +182,14 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
|
||||
override fun visitTryCatch(tryCatch: IrTryCatch, data: Nothing?): String =
|
||||
"TRY_CATCH type=${tryCatch.type.render()}"
|
||||
|
||||
override fun visitDummyDeclaration(declaration: IrDummyDeclaration, data: Nothing?): String =
|
||||
"DUMMY ${declaration.descriptor.javaClass.simpleName} ${declaration.descriptor.name}"
|
||||
override fun visitErrorDeclaration(declaration: IrErrorDeclaration, data: Nothing?): String =
|
||||
"ERROR_DECL ${declaration.descriptor.javaClass.simpleName} ${declaration.descriptor.name}"
|
||||
|
||||
override fun visitDummyExpression(expression: IrDummyExpression, data: Nothing?): String =
|
||||
"DUMMY ${expression.description} type=${expression.type.render()}"
|
||||
override fun visitErrorExpression(expression: IrErrorExpression, data: Nothing?): String =
|
||||
"ERROR_EXPR '${expression.description}' type=${expression.type.render()}"
|
||||
|
||||
override fun visitErrorCallExpression(expression: IrErrorCallExpression, data: Nothing?): String =
|
||||
"ERROR_CALL '${expression.description}' type=${expression.type.render()}"
|
||||
|
||||
companion object {
|
||||
private val DESCRIPTOR_RENDERER = DescriptorRenderer.withOptions {
|
||||
|
||||
@@ -91,7 +91,7 @@ interface IrElementVisitor<out R, in D> {
|
||||
fun visitReturn(expression: IrReturn, data: D) = visitExpression(expression, data)
|
||||
fun visitThrow(expression: IrThrow, data: D) = visitExpression(expression, data)
|
||||
|
||||
// NB Use it only for testing purposes; will be removed as soon as all Kotlin expression types are covered
|
||||
fun visitDummyDeclaration(declaration: IrDummyDeclaration, data: D) = visitDeclaration(declaration, data)
|
||||
fun visitDummyExpression(expression: IrDummyExpression, data: D) = visitExpression(expression, data)
|
||||
fun visitErrorDeclaration(declaration: IrErrorDeclaration, data: D) = visitDeclaration(declaration, data)
|
||||
fun visitErrorExpression(expression: IrErrorExpression, data: D) = visitExpression(expression, data)
|
||||
fun visitErrorCallExpression(expression: IrErrorCallExpression, data: D) = visitErrorExpression(expression, data)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// !IGNORE_ERRORS
|
||||
|
||||
val test1 = unresolved
|
||||
|
||||
val test2: Unresolved =
|
||||
unresolved()
|
||||
|
||||
val test3 = 42.unresolved(56)
|
||||
|
||||
val test4 = 42 *
|
||||
@@ -209,6 +209,21 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/ir/irText/errors")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Errors extends AbstractIrTextTestCase {
|
||||
public void testAllFilesPresentInErrors() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/ir/irText/errors"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("unresolvedReference.kt")
|
||||
public void testUnresolvedReference() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/errors/unresolvedReference.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/ir/irText/expressions")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user