Cleanup and additional tests
This commit is contained in:
+51
-136
@@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package com.bnorm.power
|
package com.bnorm.power
|
||||||
|
|
||||||
|
import com.bnorm.power.delegate.FunctionDelegate
|
||||||
|
import com.bnorm.power.delegate.LambdaFunctionDelegate
|
||||||
|
import com.bnorm.power.delegate.SimpleFunctionDelegate
|
||||||
import com.bnorm.power.diagram.IrTemporaryVariable
|
import com.bnorm.power.diagram.IrTemporaryVariable
|
||||||
import com.bnorm.power.diagram.Node
|
import com.bnorm.power.diagram.Node
|
||||||
import com.bnorm.power.diagram.buildDiagramNesting
|
import com.bnorm.power.diagram.buildDiagramNesting
|
||||||
@@ -32,28 +35,18 @@ import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
|
|||||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
|
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
|
||||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.asString
|
import org.jetbrains.kotlin.ir.backend.js.utils.asString
|
||||||
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
|
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
|
||||||
import org.jetbrains.kotlin.ir.builders.irBlockBody
|
|
||||||
import org.jetbrains.kotlin.ir.builders.irCall
|
|
||||||
import org.jetbrains.kotlin.ir.builders.irCallOp
|
import org.jetbrains.kotlin.ir.builders.irCallOp
|
||||||
import org.jetbrains.kotlin.ir.builders.irReturn
|
|
||||||
import org.jetbrains.kotlin.ir.builders.irString
|
import org.jetbrains.kotlin.ir.builders.irString
|
||||||
import org.jetbrains.kotlin.ir.builders.parent
|
import org.jetbrains.kotlin.ir.builders.parent
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
import org.jetbrains.kotlin.ir.declarations.path
|
import org.jetbrains.kotlin.ir.declarations.path
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation
|
import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionExpressionImpl
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
@@ -68,7 +61,6 @@ import org.jetbrains.kotlin.ir.util.functions
|
|||||||
import org.jetbrains.kotlin.ir.util.isFunctionOrKFunction
|
import org.jetbrains.kotlin.ir.util.isFunctionOrKFunction
|
||||||
import org.jetbrains.kotlin.ir.util.kotlinFqName
|
import org.jetbrains.kotlin.ir.util.kotlinFqName
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
|
||||||
class PowerAssertCallTransformer(
|
class PowerAssertCallTransformer(
|
||||||
@@ -81,17 +73,27 @@ class PowerAssertCallTransformer(
|
|||||||
override fun visitCall(expression: IrCall): IrExpression {
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
val function = expression.symbol.owner
|
val function = expression.symbol.owner
|
||||||
val fqName = function.kotlinFqName
|
val fqName = function.kotlinFqName
|
||||||
if (function.valueParameters.isEmpty() || functions.none { fqName == it })
|
if (function.valueParameters.isEmpty() || functions.none { fqName == it }) {
|
||||||
return super.visitCall(expression)
|
return super.visitCall(expression)
|
||||||
|
}
|
||||||
|
|
||||||
// Find a valid delegate function or do not translate
|
// Find a valid delegate function or do not translate
|
||||||
// TODO better way to determine which delegate to actually use
|
// TODO better way to determine which delegate to actually use
|
||||||
val delegates = findDelegates(function)
|
val delegates = findDelegates(function)
|
||||||
val delegate = delegates.maxByOrNull { it.function.valueParameters.size } ?: run {
|
val delegate = delegates.maxByOrNull { it.function.valueParameters.size }
|
||||||
val valueType = function.valueParameters[0].type.asString()
|
if (delegate == null) {
|
||||||
|
val valueTypesTruncated = function.valueParameters.subList(0, function.valueParameters.size - 1)
|
||||||
|
.joinToString(", ") { it.type.asString() }
|
||||||
|
val valueTypesAll = function.valueParameters.joinToString(", ") { it.type.asString() }
|
||||||
messageCollector.warn(
|
messageCollector.warn(
|
||||||
expression,
|
expression = expression,
|
||||||
"Unable to find overload for function $fqName callable as $fqName($valueType, String) or $fqName($valueType, () -> String) for power-assert transformation"
|
message = """
|
||||||
|
|Unable to find overload of function $fqName for power-assert transformation:
|
||||||
|
| - $fqName($valueTypesTruncated, String)
|
||||||
|
| - $fqName($valueTypesTruncated, () -> String)
|
||||||
|
| - $fqName($valueTypesAll, String)
|
||||||
|
| - $fqName($valueTypesAll, () -> String)
|
||||||
|
""".trimMargin()
|
||||||
)
|
)
|
||||||
return super.visitCall(expression)
|
return super.visitCall(expression)
|
||||||
}
|
}
|
||||||
@@ -110,7 +112,7 @@ class PowerAssertCallTransformer(
|
|||||||
.map { arg -> arg?.let { buildTree(it) } }
|
.map { arg -> arg?.let { buildTree(it) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
// If all roots are null, all parameters are constants and expression need not be transformed
|
// If all roots are null, there are no transformable parameters
|
||||||
if (roots.all { it == null }) {
|
if (roots.all { it == null }) {
|
||||||
messageCollector.info(expression, "Expression is constant and will not be power-assert transformed")
|
messageCollector.info(expression, "Expression is constant and will not be power-assert transformed")
|
||||||
return super.visitCall(expression)
|
return super.visitCall(expression)
|
||||||
@@ -118,7 +120,7 @@ class PowerAssertCallTransformer(
|
|||||||
|
|
||||||
val symbol = currentScope!!.scope.scopeOwnerSymbol
|
val symbol = currentScope!!.scope.scopeOwnerSymbol
|
||||||
val builder = DeclarationIrBuilder(context, symbol, expression.startOffset, expression.endOffset)
|
val builder = DeclarationIrBuilder(context, symbol, expression.startOffset, expression.endOffset)
|
||||||
return builder.diagram(expression, delegate, symbol, messageArgument, roots)
|
return builder.diagram(expression, delegate, messageArgument, roots)
|
||||||
// .also { println(expression.dump()) }
|
// .also { println(expression.dump()) }
|
||||||
// .also { println(it.dump()) }
|
// .also { println(it.dump()) }
|
||||||
// .also { println(expression.dumpKotlinLike()) }
|
// .also { println(expression.dumpKotlinLike()) }
|
||||||
@@ -128,7 +130,6 @@ class PowerAssertCallTransformer(
|
|||||||
private fun DeclarationIrBuilder.diagram(
|
private fun DeclarationIrBuilder.diagram(
|
||||||
original: IrCall,
|
original: IrCall,
|
||||||
delegate: FunctionDelegate,
|
delegate: FunctionDelegate,
|
||||||
scopeSymbol: IrSymbol,
|
|
||||||
messageArgument: IrExpression?,
|
messageArgument: IrExpression?,
|
||||||
roots: List<Node?>,
|
roots: List<Node?>,
|
||||||
index: Int = 0,
|
index: Int = 0,
|
||||||
@@ -136,63 +137,43 @@ class PowerAssertCallTransformer(
|
|||||||
variables: List<IrTemporaryVariable> = listOf()
|
variables: List<IrTemporaryVariable> = listOf()
|
||||||
): IrExpression {
|
): IrExpression {
|
||||||
if (index >= roots.size) {
|
if (index >= roots.size) {
|
||||||
val lambda = messageArgument?.asSimpleLambda()
|
val prefix = buildMessagePrefix(messageArgument, roots, original)?.deepCopyWithSymbols(parent)
|
||||||
val title = when {
|
|
||||||
messageArgument is IrConst<*> -> messageArgument
|
|
||||||
messageArgument is IrStringConcatenation -> messageArgument
|
|
||||||
lambda != null -> lambda.deepCopyWithSymbols(parent).inline(parent)
|
|
||||||
.transform(ReturnableBlockTransformer(context, scopeSymbol), null)
|
|
||||||
messageArgument != null -> {
|
|
||||||
val invoke = messageArgument.type.classOrNull!!.owner.functions
|
|
||||||
.single { it.name == OperatorNameConventions.INVOKE }
|
|
||||||
irCallOp(invoke.symbol, invoke.returnType, messageArgument)
|
|
||||||
}
|
|
||||||
// TODO what should the default message be?
|
|
||||||
roots.size == 1 && original.getValueArgument(0)!!.type.isBoolean() -> irString("Assertion failed")
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
val prefix = title?.deepCopyWithSymbols(parent)
|
|
||||||
val diagram = irDiagramString(file, fileSource, prefix, original, variables)
|
val diagram = irDiagramString(file, fileSource, prefix, original, variables)
|
||||||
return delegate.buildCall(this, original, arguments, diagram)
|
return delegate.buildCall(this, original, arguments, diagram)
|
||||||
} else {
|
} else {
|
||||||
val root = roots[index]
|
val root = roots[index]
|
||||||
if (root == null) {
|
if (root == null) {
|
||||||
return diagram(
|
val newArguments = arguments + original.getValueArgument(index)
|
||||||
original,
|
return diagram(original, delegate, messageArgument, roots, index + 1, newArguments, variables)
|
||||||
delegate,
|
|
||||||
scopeSymbol,
|
|
||||||
messageArgument,
|
|
||||||
roots,
|
|
||||||
index + 1,
|
|
||||||
arguments + original.getValueArgument(index),
|
|
||||||
variables
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
return buildDiagramNesting(root) { argument, newVariables ->
|
return buildDiagramNesting(root) { argument, newVariables ->
|
||||||
diagram(
|
val newArguments = arguments + argument
|
||||||
original,
|
diagram(original, delegate, messageArgument, roots, index + 1, newArguments, variables + newVariables)
|
||||||
delegate,
|
|
||||||
scopeSymbol,
|
|
||||||
messageArgument,
|
|
||||||
roots,
|
|
||||||
index + 1,
|
|
||||||
arguments + argument,
|
|
||||||
variables + newVariables
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private interface FunctionDelegate {
|
private fun DeclarationIrBuilder.buildMessagePrefix(
|
||||||
val function: IrFunction
|
messageArgument: IrExpression?,
|
||||||
fun buildCall(
|
roots: List<Node?>,
|
||||||
builder: IrBuilderWithScope,
|
original: IrCall
|
||||||
original: IrCall,
|
): IrExpression? {
|
||||||
arguments: List<IrExpression?>,
|
val lambda = messageArgument?.asSimpleLambda()
|
||||||
message: IrExpression
|
return when {
|
||||||
): IrExpression
|
messageArgument is IrConst<*> -> messageArgument
|
||||||
|
messageArgument is IrStringConcatenation -> messageArgument
|
||||||
|
lambda != null -> lambda.deepCopyWithSymbols(parent).inline(parent)
|
||||||
|
.transform(ReturnableBlockTransformer(context, scope.scopeOwnerSymbol), null)
|
||||||
|
messageArgument != null -> {
|
||||||
|
val invoke = messageArgument.type.classOrNull!!.owner.functions
|
||||||
|
.single { it.name == OperatorNameConventions.INVOKE }
|
||||||
|
irCallOp(invoke.symbol, invoke.returnType, messageArgument)
|
||||||
|
}
|
||||||
|
// TODO what should the default message be?
|
||||||
|
roots.size == 1 && original.getValueArgument(0)!!.type.isBoolean() -> irString("Assertion failed")
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findDelegates(function: IrFunction): List<FunctionDelegate> {
|
private fun findDelegates(function: IrFunction): List<FunctionDelegate> {
|
||||||
@@ -203,81 +184,15 @@ class PowerAssertCallTransformer(
|
|||||||
.mapNotNull { overload ->
|
.mapNotNull { overload ->
|
||||||
val parameters = overload.owner.valueParameters
|
val parameters = overload.owner.valueParameters
|
||||||
if (parameters.size !in values.size..values.size + 1) return@mapNotNull null
|
if (parameters.size !in values.size..values.size + 1) return@mapNotNull null
|
||||||
if (!parameters.zip(values)
|
if (!parameters.zip(values).all { (param, value) -> value.type.isAssignableTo(param.type) }) {
|
||||||
.all { (param, value) -> value.type.isAssignableTo(param.type) }
|
return@mapNotNull null
|
||||||
) return@mapNotNull null
|
}
|
||||||
|
|
||||||
val messageParameter = parameters.last()
|
val messageParameter = parameters.last()
|
||||||
return@mapNotNull when {
|
return@mapNotNull when {
|
||||||
isStringSupertype(messageParameter.type) -> {
|
isStringSupertype(messageParameter.type) -> SimpleFunctionDelegate(overload)
|
||||||
object : FunctionDelegate {
|
isStringFunction(messageParameter.type) -> LambdaFunctionDelegate(overload, messageParameter)
|
||||||
override val function = overload.owner
|
else -> null
|
||||||
override fun buildCall(
|
|
||||||
builder: IrBuilderWithScope,
|
|
||||||
original: IrCall,
|
|
||||||
arguments: List<IrExpression?>,
|
|
||||||
message: IrExpression
|
|
||||||
): IrExpression = with(builder) {
|
|
||||||
irCall(overload, type = original.type).apply {
|
|
||||||
dispatchReceiver = original.dispatchReceiver?.deepCopyWithSymbols(parent)
|
|
||||||
extensionReceiver = original.extensionReceiver?.deepCopyWithSymbols(parent)
|
|
||||||
for (i in 0 until original.typeArgumentsCount) {
|
|
||||||
putTypeArgument(i, original.getTypeArgument(i))
|
|
||||||
}
|
|
||||||
for ((i, argument) in arguments.withIndex()) {
|
|
||||||
putValueArgument(i, argument?.deepCopyWithSymbols(builder.scope.getLocalDeclarationParent()))
|
|
||||||
}
|
|
||||||
putValueArgument(parameters.size - 1, message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
isStringFunction(messageParameter.type) -> {
|
|
||||||
object : FunctionDelegate {
|
|
||||||
override val function = overload.owner
|
|
||||||
override fun buildCall(
|
|
||||||
builder: IrBuilderWithScope,
|
|
||||||
original: IrCall,
|
|
||||||
arguments: List<IrExpression?>,
|
|
||||||
message: IrExpression
|
|
||||||
): IrExpression = with(builder) {
|
|
||||||
val scope = this
|
|
||||||
val lambda = builder.context.irFactory.buildFun {
|
|
||||||
name = Name.special("<anonymous>")
|
|
||||||
returnType = context.irBuiltIns.stringType
|
|
||||||
visibility = DescriptorVisibilities.LOCAL
|
|
||||||
origin = IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA
|
|
||||||
}.apply {
|
|
||||||
val bodyBuilder = DeclarationIrBuilder(this@PowerAssertCallTransformer.context, symbol)
|
|
||||||
body = bodyBuilder.irBlockBody {
|
|
||||||
+irReturn(message)
|
|
||||||
}
|
|
||||||
parent = scope.parent
|
|
||||||
}
|
|
||||||
val expression = IrFunctionExpressionImpl(
|
|
||||||
original.startOffset,
|
|
||||||
original.endOffset,
|
|
||||||
messageParameter.type,
|
|
||||||
lambda,
|
|
||||||
IrStatementOrigin.LAMBDA
|
|
||||||
)
|
|
||||||
irCall(overload, type = original.type).apply {
|
|
||||||
dispatchReceiver = original.dispatchReceiver?.deepCopyWithSymbols(parent)
|
|
||||||
extensionReceiver = original.extensionReceiver?.deepCopyWithSymbols(parent)
|
|
||||||
for (i in 0 until original.typeArgumentsCount) {
|
|
||||||
putTypeArgument(i, original.getTypeArgument(i))
|
|
||||||
}
|
|
||||||
for ((i, argument) in arguments.withIndex()) {
|
|
||||||
putValueArgument(i, argument?.deepCopyWithSymbols(builder.scope.getLocalDeclarationParent()))
|
|
||||||
}
|
|
||||||
putValueArgument(parameters.size - 1, expression)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Brian Norman
|
||||||
|
*
|
||||||
|
* 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 com.bnorm.power.delegate
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
|
||||||
|
import org.jetbrains.kotlin.ir.builders.irCall
|
||||||
|
import org.jetbrains.kotlin.ir.builders.parent
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
|
||||||
|
|
||||||
|
interface FunctionDelegate {
|
||||||
|
val function: IrFunction
|
||||||
|
|
||||||
|
fun buildCall(
|
||||||
|
builder: IrBuilderWithScope,
|
||||||
|
original: IrCall,
|
||||||
|
arguments: List<IrExpression?>,
|
||||||
|
message: IrExpression
|
||||||
|
): IrExpression
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irCallCopy(
|
||||||
|
overload: IrSimpleFunctionSymbol,
|
||||||
|
original: IrCall,
|
||||||
|
arguments: List<IrExpression?>,
|
||||||
|
expression: IrExpression
|
||||||
|
): IrExpression {
|
||||||
|
return irCall(overload, type = original.type).apply {
|
||||||
|
dispatchReceiver = original.dispatchReceiver?.deepCopyWithSymbols(parent)
|
||||||
|
extensionReceiver = original.extensionReceiver?.deepCopyWithSymbols(parent)
|
||||||
|
for (i in 0 until original.typeArgumentsCount) {
|
||||||
|
putTypeArgument(i, original.getTypeArgument(i))
|
||||||
|
}
|
||||||
|
for ((i, argument) in arguments.withIndex()) {
|
||||||
|
putValueArgument(i, argument?.deepCopyWithSymbols(parent))
|
||||||
|
}
|
||||||
|
putValueArgument(arguments.size, expression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Brian Norman
|
||||||
|
*
|
||||||
|
* 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 com.bnorm.power.delegate
|
||||||
|
|
||||||
|
import com.bnorm.power.irLambda
|
||||||
|
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
|
||||||
|
import org.jetbrains.kotlin.ir.builders.irReturn
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
|
|
||||||
|
class LambdaFunctionDelegate(
|
||||||
|
private val overload: IrSimpleFunctionSymbol,
|
||||||
|
private val messageParameter: IrValueParameter
|
||||||
|
) : FunctionDelegate {
|
||||||
|
override val function = overload.owner
|
||||||
|
|
||||||
|
override fun buildCall(
|
||||||
|
builder: IrBuilderWithScope,
|
||||||
|
original: IrCall,
|
||||||
|
arguments: List<IrExpression?>,
|
||||||
|
message: IrExpression
|
||||||
|
): IrExpression = with(builder) {
|
||||||
|
val expression = irLambda(context.irBuiltIns.stringType, messageParameter.type) {
|
||||||
|
+irReturn(message)
|
||||||
|
}
|
||||||
|
irCallCopy(overload, original, arguments, expression)
|
||||||
|
}
|
||||||
|
}
|
||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Brian Norman
|
||||||
|
*
|
||||||
|
* 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 com.bnorm.power.delegate
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
|
||||||
|
import org.jetbrains.kotlin.ir.builders.irCall
|
||||||
|
import org.jetbrains.kotlin.ir.builders.parent
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
|
||||||
|
|
||||||
|
class SimpleFunctionDelegate(
|
||||||
|
private val overload: IrSimpleFunctionSymbol
|
||||||
|
) : FunctionDelegate {
|
||||||
|
override val function = overload.owner
|
||||||
|
|
||||||
|
override fun buildCall(
|
||||||
|
builder: IrBuilderWithScope,
|
||||||
|
original: IrCall,
|
||||||
|
arguments: List<IrExpression?>,
|
||||||
|
message: IrExpression
|
||||||
|
): IrExpression = builder.irCallCopy(overload, original, arguments, message)
|
||||||
|
}
|
||||||
+16
@@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Brian Norman
|
||||||
|
*
|
||||||
|
* 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 com.bnorm.power.diagram
|
package com.bnorm.power.diagram
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.builders.IrStatementsBuilder
|
import org.jetbrains.kotlin.ir.builders.IrStatementsBuilder
|
||||||
|
|||||||
@@ -1,7 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Brian Norman
|
||||||
|
*
|
||||||
|
* 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 com.bnorm.power
|
package com.bnorm.power
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
|
||||||
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||||
|
import org.jetbrains.kotlin.ir.builders.IrBlockBodyBuilder
|
||||||
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
|
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||||
|
import org.jetbrains.kotlin.ir.builders.irBlockBody
|
||||||
import org.jetbrains.kotlin.ir.builders.irString
|
import org.jetbrains.kotlin.ir.builders.irString
|
||||||
|
import org.jetbrains.kotlin.ir.builders.parent
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrFunctionExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionExpressionImpl
|
||||||
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
fun IrBuilderWithScope.irString(builderAction: StringBuilder.() -> Unit) =
|
fun IrBuilderWithScope.irString(builderAction: StringBuilder.() -> Unit) =
|
||||||
irString(buildString { builderAction() })
|
irString(buildString { builderAction() })
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irLambda(
|
||||||
|
returnType: IrType,
|
||||||
|
lambdaType: IrType,
|
||||||
|
startOffset: Int = this.startOffset,
|
||||||
|
endOffset: Int = this.endOffset,
|
||||||
|
block: IrBlockBodyBuilder.() -> Unit
|
||||||
|
): IrFunctionExpression {
|
||||||
|
val scope = this
|
||||||
|
val lambda = context.irFactory.buildFun {
|
||||||
|
name = Name.special("<anonymous>")
|
||||||
|
this.returnType = returnType
|
||||||
|
visibility = DescriptorVisibilities.LOCAL
|
||||||
|
origin = IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA
|
||||||
|
}.apply {
|
||||||
|
val bodyBuilder = DeclarationIrBuilder(context, symbol)
|
||||||
|
body = bodyBuilder.irBlockBody {
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
parent = scope.parent
|
||||||
|
}
|
||||||
|
return IrFunctionExpressionImpl(startOffset, endOffset, lambdaType, lambda, IrStatementOrigin.LAMBDA)
|
||||||
|
}
|
||||||
|
|||||||
+16
@@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Brian Norman
|
||||||
|
*
|
||||||
|
* 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 com.bnorm.power
|
package com.bnorm.power
|
||||||
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
package com.bnorm.power
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.name.FqName
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
class AssertBooleanTest {
|
|
||||||
@Test
|
|
||||||
fun `test assertTrue transformation`() {
|
|
||||||
assertMessage(
|
|
||||||
"""
|
|
||||||
import kotlin.test.assertTrue
|
|
||||||
|
|
||||||
fun main() {
|
|
||||||
assertTrue(1 != 1)
|
|
||||||
}""",
|
|
||||||
"""
|
|
||||||
Assertion failed
|
|
||||||
assertTrue(1 != 1)
|
|
||||||
|
|
|
||||||
false
|
|
||||||
""".trimIndent(),
|
|
||||||
PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertTrue")))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `test assertFalse transformation`() {
|
|
||||||
assertMessage(
|
|
||||||
"""
|
|
||||||
import kotlin.test.assertFalse
|
|
||||||
|
|
||||||
fun main() {
|
|
||||||
assertFalse(1 == 1)
|
|
||||||
}""",
|
|
||||||
"""
|
|
||||||
Assertion failed
|
|
||||||
assertFalse(1 == 1)
|
|
||||||
|
|
|
||||||
true
|
|
||||||
""".trimIndent(),
|
|
||||||
PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertFalse")))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Brian Norman
|
||||||
|
*
|
||||||
|
* 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 com.bnorm.power
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class AssertLibraryTest {
|
||||||
|
@Test
|
||||||
|
fun `test assertTrue transformation`() {
|
||||||
|
assertMessage(
|
||||||
|
"""
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
assertTrue(1 != 1)
|
||||||
|
}""",
|
||||||
|
"""
|
||||||
|
Assertion failed
|
||||||
|
assertTrue(1 != 1)
|
||||||
|
|
|
||||||
|
false
|
||||||
|
""".trimIndent(),
|
||||||
|
PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertTrue")))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test assertTrue transformation with message`() {
|
||||||
|
assertMessage(
|
||||||
|
"""
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
assertTrue(1 != 1, "Message:")
|
||||||
|
}""",
|
||||||
|
"""
|
||||||
|
Message:
|
||||||
|
assertTrue(1 != 1, "Message:")
|
||||||
|
|
|
||||||
|
false
|
||||||
|
""".trimIndent(),
|
||||||
|
PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertTrue")))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test assertFalse transformation`() {
|
||||||
|
assertMessage(
|
||||||
|
"""
|
||||||
|
import kotlin.test.assertFalse
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
assertFalse(1 == 1)
|
||||||
|
}""",
|
||||||
|
"""
|
||||||
|
Assertion failed
|
||||||
|
assertFalse(1 == 1)
|
||||||
|
|
|
||||||
|
true
|
||||||
|
""".trimIndent(),
|
||||||
|
PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertFalse")))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test assertFalse transformation with message`() {
|
||||||
|
assertMessage(
|
||||||
|
"""
|
||||||
|
import kotlin.test.assertFalse
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
assertFalse(1 == 1, "Message:")
|
||||||
|
}""",
|
||||||
|
"""
|
||||||
|
Message:
|
||||||
|
assertFalse(1 == 1, "Message:")
|
||||||
|
|
|
||||||
|
true
|
||||||
|
""".trimIndent(),
|
||||||
|
PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertFalse")))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test assertEquals transformation`() {
|
||||||
|
assertMessage(
|
||||||
|
"""
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val greeting = "Hello"
|
||||||
|
val name = "World"
|
||||||
|
assertEquals(greeting, name)
|
||||||
|
}""",
|
||||||
|
"""
|
||||||
|
assertEquals(greeting, name)
|
||||||
|
| |
|
||||||
|
| World
|
||||||
|
Hello expected:<[Hello]> but was:<[World]>
|
||||||
|
""".trimIndent(),
|
||||||
|
PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertEquals")))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test assertEquals transformation with message`() {
|
||||||
|
assertMessage(
|
||||||
|
"""
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val greeting = "Hello"
|
||||||
|
val name = "World"
|
||||||
|
assertEquals(greeting, name, "Message:")
|
||||||
|
}""",
|
||||||
|
"""
|
||||||
|
Message:
|
||||||
|
assertEquals(greeting, name, "Message:")
|
||||||
|
| |
|
||||||
|
| World
|
||||||
|
Hello expected:<[Hello]> but was:<[World]>
|
||||||
|
""".trimIndent(),
|
||||||
|
PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertEquals")))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test assertNotNull transformation`() {
|
||||||
|
assertMessage(
|
||||||
|
"""
|
||||||
|
import kotlin.test.assertNotNull
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val name: String? = null
|
||||||
|
assertNotNull(name)
|
||||||
|
}""",
|
||||||
|
"""
|
||||||
|
assertNotNull(name)
|
||||||
|
|
|
||||||
|
null
|
||||||
|
""".trimIndent(),
|
||||||
|
PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertNotNull")))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test assertNotNull transformation with message`() {
|
||||||
|
assertMessage(
|
||||||
|
"""
|
||||||
|
import kotlin.test.assertNotNull
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val name: String? = null
|
||||||
|
assertNotNull(name, "Message:")
|
||||||
|
}""",
|
||||||
|
"""
|
||||||
|
Message:
|
||||||
|
assertNotNull(name, "Message:")
|
||||||
|
|
|
||||||
|
null
|
||||||
|
""".trimIndent(),
|
||||||
|
PowerAssertComponentRegistrar(setOf(FqName("kotlin.test.assertNotNull")))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Brian Norman
|
||||||
|
*
|
||||||
|
* 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 com.bnorm.power
|
package com.bnorm.power
|
||||||
|
|
||||||
import com.tschuchort.compiletesting.KotlinCompilation
|
import com.tschuchort.compiletesting.KotlinCompilation
|
||||||
|
|||||||
+16
@@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Brian Norman
|
||||||
|
*
|
||||||
|
* 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 com.bnorm.power
|
package com.bnorm.power
|
||||||
|
|
||||||
import com.tschuchort.compiletesting.KotlinCompilation
|
import com.tschuchort.compiletesting.KotlinCompilation
|
||||||
|
|||||||
@@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Brian Norman
|
||||||
|
*
|
||||||
|
* 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 com.bnorm.power
|
package com.bnorm.power
|
||||||
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|||||||
@@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Brian Norman
|
||||||
|
*
|
||||||
|
* 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 com.bnorm.power
|
package com.bnorm.power
|
||||||
|
|
||||||
import com.tschuchort.compiletesting.KotlinCompilation
|
import com.tschuchort.compiletesting.KotlinCompilation
|
||||||
|
|||||||
Reference in New Issue
Block a user