diff --git a/compiler/ir/ir.ir2cfg/src/org/jetbrains/kotlin/ir2cfg/generators/FunctionGenerator.kt b/compiler/ir/ir.ir2cfg/src/org/jetbrains/kotlin/ir2cfg/generators/FunctionGenerator.kt new file mode 100644 index 00000000000..ccc6f7f7871 --- /dev/null +++ b/compiler/ir/ir.ir2cfg/src/org/jetbrains/kotlin/ir2cfg/generators/FunctionGenerator.kt @@ -0,0 +1,109 @@ +/* + * 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.ir2cfg.generators + +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.IrVariable +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.visitors.IrElementVisitor +import org.jetbrains.kotlin.ir2cfg.graph.ControlFlowGraph +import org.jetbrains.kotlin.ir2cfg.nodes.MergeCfgElement + +class FunctionGenerator(val function: IrFunction) { + + val builder = FunctionBuilder(function) + + val exit = MergeCfgElement(function, "Function exit") + + fun generate(): ControlFlowGraph { + val visitor = FunctionVisitor() + function.accept(visitor, true) + return builder.build() + } + + inner class FunctionVisitor : IrElementVisitor { + + inline fun IE.process(includeSelf: Boolean = true) = this.accept(this@FunctionVisitor, includeSelf) + + override fun visitFunction(declaration: IrFunction, data: Boolean): IrElement? { + if (data) { + builder.add(declaration) + } + val result = declaration.body?.process() + if (result != null && !result.isNothing()) { + builder.jump(exit, from = result) + } + return result + } + + private fun IrStatementContainer.process(): IrElement? { + var result: IrElement? = null + for (statement in statements) { + result = statement.process() + } + return result + } + + private fun IrElement?.isNothing() = this is IrExpression && KotlinBuiltIns.isNothing(type) + + override fun visitBlockBody(body: IrBlockBody, data: Boolean): IrElement? { + return body.process() ?: body + } + + override fun visitBlock(expression: IrBlock, data: Boolean): IrElement? { + return expression.process() ?: expression + } + + override fun visitVariable(declaration: IrVariable, data: Boolean): IrElement? { + declaration.initializer?.process() + return if (data) { + builder.add(declaration) + declaration + } + else null + } + + override fun visitReturn(expression: IrReturn, data: Boolean): IrElement? { + expression.value.process() + if (data) { + builder.add(expression) + } + builder.jump(exit) + return expression + } + + override fun visitExpressionBody(body: IrExpressionBody, data: Boolean): IrElement? { + if (data) { + builder.add(body) + } + return body.expression.process() + } + + override fun visitExpression(expression: IrExpression, data: Boolean): IrElement? { + if (data) { + builder.add(expression) + } + return expression + } + + override fun visitElement(element: IrElement, data: Boolean): IrElement? { + TODO("not implemented") + } + } +} \ No newline at end of file diff --git a/compiler/ir/ir.ir2cfg/src/org/jetbrains/kotlin/ir2cfg/nodes/CfgIrElement.kt b/compiler/ir/ir.ir2cfg/src/org/jetbrains/kotlin/ir2cfg/nodes/CfgIrElement.kt new file mode 100644 index 00000000000..7262774aa84 --- /dev/null +++ b/compiler/ir/ir.ir2cfg/src/org/jetbrains/kotlin/ir2cfg/nodes/CfgIrElement.kt @@ -0,0 +1,21 @@ +/* + * 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.ir2cfg.nodes + +import org.jetbrains.kotlin.ir.IrElement + +interface CfgIrElement : IrElement \ No newline at end of file diff --git a/compiler/ir/ir.ir2cfg/src/org/jetbrains/kotlin/ir2cfg/nodes/MergeCfgElement.kt b/compiler/ir/ir.ir2cfg/src/org/jetbrains/kotlin/ir2cfg/nodes/MergeCfgElement.kt new file mode 100644 index 00000000000..3f2f4a32701 --- /dev/null +++ b/compiler/ir/ir.ir2cfg/src/org/jetbrains/kotlin/ir2cfg/nodes/MergeCfgElement.kt @@ -0,0 +1,35 @@ +/* + * 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.ir2cfg.nodes + +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.util.dump +import org.jetbrains.kotlin.ir.visitors.IrElementTransformer +import org.jetbrains.kotlin.ir.visitors.IrElementVisitor + +class MergeCfgElement(val from: IrElement, val name: String) : CfgIrElement { + override val startOffset = from.startOffset + override val endOffset = from.endOffset + + override fun accept(visitor: IrElementVisitor, data: D) = visitor.visitElement(this, data) + + override fun acceptChildren(visitor: IrElementVisitor, data: D) = Unit + + override fun transformChildren(transformer: IrElementTransformer, data: D) = Unit + + override fun toString() = "$name: ${from.dump()}" +} \ No newline at end of file