diff --git a/build.gradle.kts b/build.gradle.kts index 15947c5cf..cc93e1660 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -172,11 +172,9 @@ if (!repoUrl.isNullOrEmpty()) { project(":jacodb-api-storage"), project(":jacodb-core"), project(":jacodb-storage"), - project(":jacodb-analysis"), project(":jacodb-approximations"), project(":jacodb-taint-configuration"), project(":jacodb-ets"), - project(":jacodb-panda-static"), ) ) { tasks { diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index 732c6c7e5..1ac3c0864 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -22,7 +22,7 @@ object Versions { const val jooq = "3.14.16" const val juliet = "1.3.2" const val junit = "5.9.2" - const val kotlin = "2.0.20" + const val kotlin = "2.1.0" const val kotlin_logging = "1.8.3" const val kotlinx_benchmark = "0.4.6" const val kotlinx_cli = "0.3.5" diff --git a/jacodb-analysis/README.md b/jacodb-analysis/README.md deleted file mode 100644 index cb6a4b854..000000000 --- a/jacodb-analysis/README.md +++ /dev/null @@ -1,75 +0,0 @@ -# Module `jacodb-analysis` - -The `jacodb-analysis` module allows launching application dataflow analyses. -It contains an API to write custom analyses, and several ready-to-use analyses. - -## Units - -The [IFDS](https://dx.doi.org/10.1145/199448.199462) framework is the basis for this module. -To make the implementation scalable, the analyzed code is split into the so-called units, so that the framework -can analyze them concurrently. -Information is shared between the units via summaries, but the lifecycle of each unit is controlled -separately. - -## Get started - -The analysis entry point is the [runAnalysis] method. To call it, you have to provide: -* `graph` — an application graph that is used for analysis. To obtain this graph, one should call the [newApplicationGraphForAnalysis] method. -* `unitResolver` — an object that groups methods into units. Choose one from `UnitResolversLibrary`. -Note that, in general, larger units mean more precise but also more resource-consuming analysis. -* `ifdsUnitRunnerFactory` — an [IfdsUnitRunnerFactory] instance, that can create runners. Runners are used to analyze each unit. -So this factory is what define concrete analysis. - Ready-to-use runner factories are located in `RunnersLibrary`. -* `methods` — a list of methods to analyze. - -For example, to detect the unused variables in the given `analyzedClass` methods, you may run the following code -(assuming that `classpath` is an instance of [JcClasspath]): - -```kotlin -val applicationGraph = runBlocking { - classpath.newApplicationGraphForAnalysis() -} - -val methodsToAnalyze = analyzedClass.declaredMethods -val unitResolver = MethodUnitResolver -val runnerFactory = UnusedVariableRunnerFactory - -runAnalysis(applicationGraph, unitResolver, runnerFactory, methodsToAnalyze) -``` - -## Implemented runners - -By now, the following runners are implemented: -* `UnusedVariableRunner` that can detect issues like unused variable declaration, unused `return` value, etc. -* `NpeRunner` that can find instructions with possible `null` value dereference. -* Generic `TaintRunner` that can perform taint analysis. -* `SqlInjectionRunner`, which finds places vulnerable to SQL injections, thus performing a specific kind of taint - analysis. - -## Implementing your own analysis - -To implement a simple one-pass analysis, use [IfdsBaseUnitRunnerFactory]. -To instantiate it, you need an [AnalyzerFactory] instance, which is an object that can create [Analyzer] via -[JcApplicationGraph]. - -To instantiate an [Analyzer] interface, you have to specify the following: - -* `flowFunctions`, which describe the dataflow facts and their transmissions during the analysis; - -* semantics for these dataflow facts, i.e. how these facts produce vulnerabilities, summaries, etc. -This should be done by implementing `handleNewEdge`, `handleNewCrossUnitCall` and `handleIfdsResult` methods. - -To implement bidirectional analysis, you may use composite [BidiIfdsUnitRunnerFactory]. - - - - -[runAnalysis]: https://jacodb.org/docs/jacodb-analysis/org.jacodb.analysis/run-analysis.html -[newApplicationGraphForAnalysis]: https://jacodb.org/docs/jacodb-analysis/org.jacodb.analysis.graph/new-application-graph-for-analysis.html -[IfdsUnitRunnerFactory]: https://jacodb.org/docs/jacodb-analysis/org.jacodb.analysis.engine/-ifds-unit-runner-factory/index.html -[JcClasspath]: https://jacodb.org/docs/jacodb-api/org.jacodb.api/-jc-classpath/index.html -[IfdsBaseUnitRunnerFactory]: https://jacodb.org/docs/jacodb-analysis/org.jacodb.analysis.engine/-ifds-base-unit-runner-factory/index.html -[AnalyzerFactory]: https://jacodb.org/docs/jacodb-analysis/org.jacodb.analysis.engine/-analyzer-factory/index.html -[Analyzer]: https://jacodb.org/docs/jacodb-analysis/org.jacodb.analysis.engine/-analyzer/index.html -[JcApplicationGraph]: https://jacodb.org/docs/jacodb-api/org.jacodb.api.analysis/-jc-application-graph/index.html -[BidiIfdsUnitRunnerFactory]: https://jacodb.org/docs/jacodb-analysis/org.jacodb.analysis.engine/-bidi-ifds-unit-runner-factory/index.html \ No newline at end of file diff --git a/jacodb-analysis/build.gradle.kts b/jacodb-analysis/build.gradle.kts deleted file mode 100644 index dd121df72..000000000 --- a/jacodb-analysis/build.gradle.kts +++ /dev/null @@ -1,32 +0,0 @@ -plugins { - kotlin("plugin.serialization") - `java-test-fixtures` -} - -dependencies { - api(project(":jacodb-api-jvm")) - api(project(":jacodb-core")) - api(project(":jacodb-taint-configuration")) - api(project(":jacodb-ets")) - api(project(":jacodb-panda-static")) - - implementation(Libs.kotlin_logging) - implementation(Libs.slf4j_simple) - implementation(Libs.kotlinx_coroutines_core) - implementation(Libs.kotlinx_serialization_json) - api(Libs.sarif4k) - - testImplementation(project(":jacodb-api-jvm")) - testImplementation(testFixtures(project(":jacodb-core"))) - testImplementation(testFixtures(project(":jacodb-storage"))) - testImplementation(kotlin("test")) - testImplementation(Libs.mockk) - - // Additional deps for analysis: - testImplementation(files("src/test/resources/pointerbench.jar")) - testImplementation(Libs.joda_time) - testImplementation(Libs.juliet_support) - for (cweNum in listOf(89, 476, 563, 690)) { - testImplementation(Libs.juliet_cwe(cweNum)) - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/Condition.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/Condition.kt deleted file mode 100644 index af05a9dd1..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/Condition.kt +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.config - -import org.jacodb.analysis.ifds.Maybe -import org.jacodb.analysis.ifds.onSome -import org.jacodb.analysis.taint.Tainted -import org.jacodb.analysis.util.Traits -import org.jacodb.analysis.util.removeTrailingElementAccessors -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.common.cfg.CommonValue -import org.jacodb.api.jvm.cfg.JcValue -import org.jacodb.api.jvm.ext.isAssignable -import org.jacodb.taint.configuration.And -import org.jacodb.taint.configuration.AnnotationType -import org.jacodb.taint.configuration.ConditionVisitor -import org.jacodb.taint.configuration.ConstantEq -import org.jacodb.taint.configuration.ConstantGt -import org.jacodb.taint.configuration.ConstantLt -import org.jacodb.taint.configuration.ConstantMatches -import org.jacodb.taint.configuration.ConstantTrue -import org.jacodb.taint.configuration.ContainsMark -import org.jacodb.taint.configuration.IsConstant -import org.jacodb.taint.configuration.IsType -import org.jacodb.taint.configuration.Not -import org.jacodb.taint.configuration.Or -import org.jacodb.taint.configuration.PositionResolver -import org.jacodb.taint.configuration.SourceFunctionMatches -import org.jacodb.taint.configuration.TypeMatches - -// TODO: replace 'JcInt' with 'CommonInt', etc - -context(Traits) -open class BasicConditionEvaluator( - internal val positionResolver: PositionResolver>, -) : ConditionVisitor { - - override fun visit(condition: ConstantTrue): Boolean { - return true - } - - override fun visit(condition: Not): Boolean { - return !condition.arg.accept(this) - } - - override fun visit(condition: And): Boolean { - return condition.args.all { it.accept(this) } - } - - override fun visit(condition: Or): Boolean { - return condition.args.any { it.accept(this) } - } - - override fun visit(condition: IsType): Boolean { - // Note: TaintConfigurationFeature.ConditionSpecializer is responsible for - // expanding IsType condition upon parsing the taint configuration. - error("Unexpected condition: $condition") - } - - override fun visit(condition: AnnotationType): Boolean { - // Note: TaintConfigurationFeature.ConditionSpecializer is responsible for - // expanding AnnotationType condition upon parsing the taint configuration. - error("Unexpected condition: $condition") - } - - override fun visit(condition: IsConstant): Boolean { - positionResolver.resolve(condition.position).onSome { - return it.isConstant() - } - return false - } - - override fun visit(condition: ConstantEq): Boolean { - positionResolver.resolve(condition.position).onSome { value -> - return value.eqConstant(condition.value) - } - return false - } - - override fun visit(condition: ConstantLt): Boolean { - positionResolver.resolve(condition.position).onSome { value -> - return value.ltConstant(condition.value) - } - return false - } - - override fun visit(condition: ConstantGt): Boolean { - positionResolver.resolve(condition.position).onSome { value -> - return value.gtConstant(condition.value) - } - return false - } - - override fun visit(condition: ConstantMatches): Boolean { - positionResolver.resolve(condition.position).onSome { value -> - return value.matches(condition.pattern) - } - return false - } - - override fun visit(condition: SourceFunctionMatches): Boolean { - TODO("Not implemented yet") - } - - override fun visit(condition: ContainsMark): Boolean { - error("This visitor does not support condition $condition. Use FactAwareConditionEvaluator instead") - } - - override fun visit(condition: TypeMatches): Boolean { - positionResolver.resolve(condition.position).onSome { value -> - return when (value) { - is JcValue -> { - value.type.isAssignable(condition.type) - } - - else -> error("Cannot evaluate $condition for $value") - } - } - return false - } -} - -context(Traits) -class FactAwareConditionEvaluator( - private val fact: Tainted, - positionResolver: PositionResolver>, -) : BasicConditionEvaluator(positionResolver) { - - override fun visit(condition: ContainsMark): Boolean { - if (fact.mark != condition.mark) return false - positionResolver.resolve(condition.position).onSome { value -> - val variable = value.toPath() - - // FIXME: Adhoc for arrays - val variableWithoutStars = variable.removeTrailingElementAccessors() - val factWithoutStars = fact.variable.removeTrailingElementAccessors() - if (variableWithoutStars == factWithoutStars) return true - - return variable == fact.variable - } - return false - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/Position.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/Position.kt deleted file mode 100644 index e0842c397..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/Position.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.config - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.ElementAccessor -import org.jacodb.analysis.ifds.Maybe -import org.jacodb.analysis.ifds.fmap -import org.jacodb.analysis.ifds.toMaybe -import org.jacodb.analysis.util.Traits -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.CommonProject -import org.jacodb.api.common.cfg.CommonAssignInst -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.common.cfg.CommonInstanceCallExpr -import org.jacodb.api.common.cfg.CommonValue -import org.jacodb.taint.configuration.AnyArgument -import org.jacodb.taint.configuration.Argument -import org.jacodb.taint.configuration.Position -import org.jacodb.taint.configuration.PositionResolver -import org.jacodb.taint.configuration.Result -import org.jacodb.taint.configuration.ResultAnyElement -import org.jacodb.taint.configuration.This - -context(Traits) -class CallPositionToAccessPathResolver( - private val callStatement: CommonInst, -) : PositionResolver> { - private val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - - override fun resolve(position: Position): Maybe = when (position) { - AnyArgument -> Maybe.none() - is Argument -> callExpr.args[position.index].toPathOrNull().toMaybe() - This -> (callExpr as? CommonInstanceCallExpr)?.instance?.toPathOrNull().toMaybe() - Result -> (callStatement as? CommonAssignInst)?.lhv?.toPathOrNull().toMaybe() - ResultAnyElement -> (callStatement as? CommonAssignInst)?.lhv?.toPathOrNull().toMaybe() - .fmap { it + ElementAccessor } - } -} - -context(Traits) -class CallPositionToValueResolver( - private val callStatement: CommonInst, -) : PositionResolver> { - private val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - - override fun resolve(position: Position): Maybe = when (position) { - AnyArgument -> Maybe.none() - is Argument -> Maybe.some(callExpr.args[position.index]) - This -> (callExpr as? CommonInstanceCallExpr)?.instance.toMaybe() - Result -> (callStatement as? CommonAssignInst)?.lhv.toMaybe() - ResultAnyElement -> Maybe.none() - } -} - -context(Traits) -class EntryPointPositionToValueResolver( - private val method: CommonMethod, -) : PositionResolver> { - override fun resolve(position: Position): Maybe = when (position) { - This -> Maybe.some(method.thisInstance) - - is Argument -> { - val p = method.parameters[position.index] - getArgument(p).toMaybe() - } - - AnyArgument, Result, ResultAnyElement -> error("Unexpected $position") - } -} - -context(Traits) -class EntryPointPositionToAccessPathResolver( - private val method: CommonMethod, -) : PositionResolver> { - override fun resolve(position: Position): Maybe = when (position) { - This -> method.thisInstance.toPathOrNull().toMaybe() - - is Argument -> { - val p = method.parameters[position.index] - getArgument(p)?.toPathOrNull().toMaybe() - } - - AnyArgument, Result, ResultAnyElement -> error("Unexpected $position") - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/TaintAction.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/TaintAction.kt deleted file mode 100644 index 59403b099..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/TaintAction.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.config - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.Maybe -import org.jacodb.analysis.ifds.fmap -import org.jacodb.analysis.ifds.map -import org.jacodb.analysis.taint.Tainted -import org.jacodb.taint.configuration.AssignMark -import org.jacodb.taint.configuration.CopyAllMarks -import org.jacodb.taint.configuration.CopyMark -import org.jacodb.taint.configuration.PositionResolver -import org.jacodb.taint.configuration.RemoveAllMarks -import org.jacodb.taint.configuration.RemoveMark - -class TaintActionEvaluator( - private val positionResolver: PositionResolver>, -) { - fun evaluate(action: CopyAllMarks, fact: Tainted): Maybe> = - positionResolver.resolve(action.from).map { from -> - if (from != fact.variable) return@map Maybe.none() - positionResolver.resolve(action.to).fmap { to -> - setOf(fact, fact.copy(variable = to)) - } - } - - fun evaluate(action: CopyMark, fact: Tainted): Maybe> { - if (fact.mark != action.mark) return Maybe.none() - return positionResolver.resolve(action.from).map { from -> - if (from != fact.variable) return@map Maybe.none() - positionResolver.resolve(action.to).fmap { to -> - setOf(fact, fact.copy(variable = to)) - } - } - } - - fun evaluate(action: AssignMark): Maybe> = - positionResolver.resolve(action.position).fmap { variable -> - setOf(Tainted(variable, action.mark)) - } - - fun evaluate(action: RemoveAllMarks, fact: Tainted): Maybe> = - positionResolver.resolve(action.position).map { variable -> - if (variable != fact.variable) return@map Maybe.none() - Maybe.some(emptySet()) - } - - fun evaluate(action: RemoveMark, fact: Tainted): Maybe> { - if (fact.mark != action.mark) return Maybe.none() - return positionResolver.resolve(action.position).map { variable -> - if (variable != fact.variable) return@map Maybe.none() - Maybe.some(emptySet()) - } - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt deleted file mode 100644 index 026256ffb..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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. - */ - -@file:JvmName("ApplicationGraphFactory") - -package org.jacodb.analysis.graph - -import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.future.future -import org.jacodb.api.jvm.JcClasspath -import org.jacodb.api.jvm.analysis.JcApplicationGraph -import org.jacodb.impl.features.usagesExt -import java.util.concurrent.CompletableFuture - -/** - * Creates an instance of [SimplifiedJcApplicationGraph], see its docs for more info. - */ -suspend fun JcClasspath.newApplicationGraphForAnalysis( - bannedPackagePrefixes: List? = null, -): JcApplicationGraph { - val mainGraph = JcApplicationGraphImpl(this, usagesExt()) - return if (bannedPackagePrefixes != null) { - SimplifiedJcApplicationGraph(mainGraph, bannedPackagePrefixes) - } else { - SimplifiedJcApplicationGraph(mainGraph, defaultBannedPackagePrefixes) - } -} - -/** - * Async adapter for calling [newApplicationGraphForAnalysis] from Java. - * - * See also: [answer on StackOverflow](https://stackoverflow.com/a/52887677/3592218). - */ -@OptIn(DelicateCoroutinesApi::class) -fun JcClasspath.newApplicationGraphForAnalysisAsync( - bannedPackagePrefixes: List? = null, -): CompletableFuture = - GlobalScope.future { - newApplicationGraphForAnalysis(bannedPackagePrefixes) - } - -val defaultBannedPackagePrefixes: List = listOf( - "kotlin.", - "java.", - "jdk.internal.", - "sun.", - "com.sun.", - "javax.", -) diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/BackwardGraphs.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/BackwardGraphs.kt deleted file mode 100644 index f3bf2e601..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/BackwardGraphs.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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. - */ - -@file:JvmName("BackwardApplicationGraphs") - -package org.jacodb.analysis.graph - -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.jvm.JcClasspath -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.analysis.JcApplicationGraph -import org.jacodb.api.jvm.cfg.JcInst - -private class BackwardApplicationGraphImpl( - val forward: ApplicationGraph, -) : ApplicationGraph - where Method : CommonMethod, - Statement : CommonInst { - - override fun predecessors(node: Statement) = forward.successors(node) - override fun successors(node: Statement) = forward.predecessors(node) - - override fun callees(node: Statement) = forward.callees(node) - override fun callers(method: Method) = forward.callers(method) - - override fun entryPoints(method: Method) = forward.exitPoints(method) - override fun exitPoints(method: Method) = forward.entryPoints(method) - - override fun methodOf(node: Statement) = forward.methodOf(node) -} - -@Suppress("UNCHECKED_CAST") -val ApplicationGraph.reversed: ApplicationGraph - where Method : CommonMethod, - Statement : CommonInst - get() = when (this) { - is JcApplicationGraph -> this.reversed as ApplicationGraph - is BackwardApplicationGraphImpl -> this.forward - else -> BackwardApplicationGraphImpl(this) - } - -private class BackwardJcApplicationGraphImpl( - val forward: JcApplicationGraph, -) : JcApplicationGraph, - ApplicationGraph by BackwardApplicationGraphImpl(forward) { - - override val cp: JcClasspath - get() = forward.cp -} - -val JcApplicationGraph.reversed: JcApplicationGraph - get() = if (this is BackwardJcApplicationGraphImpl) { - this.forward - } else { - BackwardJcApplicationGraphImpl(this) - } diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt deleted file mode 100644 index c0001b11a..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.graph - -import org.jacodb.api.jvm.JcClasspath -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.analysis.JcApplicationGraph -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.ext.cfg.callExpr -import org.jacodb.impl.features.SyncUsagesExtension - -/** - * Possible we will need JcRawInst instead of JcInst - */ -open class JcApplicationGraphImpl( - override val cp: JcClasspath, - private val usages: SyncUsagesExtension, -) : JcApplicationGraph { - override fun predecessors(node: JcInst): Sequence { - val graph = node.location.method.flowGraph() - val predecessors = graph.predecessors(node) - val throwers = graph.throwers(node) - return predecessors.asSequence() + throwers.asSequence() - } - - override fun successors(node: JcInst): Sequence { - val graph = node.location.method.flowGraph() - val successors = graph.successors(node) - val catchers = graph.catchers(node) - return successors.asSequence() + catchers.asSequence() - } - - override fun callees(node: JcInst): Sequence { - val callExpr = node.callExpr ?: return emptySequence() - return sequenceOf(callExpr.method.method) - } - - override fun callers(method: JcMethod): Sequence { - return usages.findUsages(method).flatMap { - it.flowGraph().instructions.asSequence().filter { inst -> - val callExpr = inst.callExpr ?: return@filter false - callExpr.method.method == method - } - } - } - - override fun entryPoints(method: JcMethod): Sequence { - return method.flowGraph().entries.asSequence() - } - - override fun exitPoints(method: JcMethod): Sequence { - return method.flowGraph().exits.asSequence() - } - - override fun methodOf(node: JcInst): JcMethod { - return node.location.method - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/JcNoopInst.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/JcNoopInst.kt deleted file mode 100644 index c57d9123d..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/JcNoopInst.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.graph - -import org.jacodb.api.jvm.cfg.JcExpr -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.cfg.JcInstLocation -import org.jacodb.api.jvm.cfg.JcInstVisitor - -data class JcNoopInst(override val location: JcInstLocation) : JcInst { - override val operands: List - get() = emptyList() - - override fun accept(visitor: JcInstVisitor): T { - return visitor.visitExternalJcInst(this) - } - - override fun toString(): String = "noop" -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/SimplifiedJcApplicationGraph.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/SimplifiedJcApplicationGraph.kt deleted file mode 100644 index 83388c0f9..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/SimplifiedJcApplicationGraph.kt +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.graph - -import kotlinx.coroutines.runBlocking -import org.jacodb.api.jvm.JcClassType -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.analysis.JcApplicationGraph -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.cfg.JcVirtualCallExpr -import org.jacodb.api.jvm.ext.cfg.callExpr -import org.jacodb.api.jvm.ext.isSubClassOf -import org.jacodb.impl.cfg.JcInstLocationImpl -import org.jacodb.impl.features.hierarchyExt - -/** - * This is adopted specially for IFDS [JcApplicationGraph] that - * 1. Ignores method calls matching [bannedPackagePrefixes] (i.e., treats them as simple instructions with no callees) - * 2. In [callers] returns only call sites that were visited before - * 3. Adds a special [JcNoopInst] instruction to the beginning of each method - * (because backward analysis may want for method to start with neutral instruction) - */ -internal class SimplifiedJcApplicationGraph( - private val graph: JcApplicationGraph, - private val bannedPackagePrefixes: List, -) : JcApplicationGraph by graph { - private val hierarchyExtension = runBlocking { - cp.hierarchyExt() - } - - private val visitedCallers: MutableMap> = mutableMapOf() - - private val cache: MutableMap> = mutableMapOf() - - // For backward analysis we may want for method to start with "neutral" operation => - // we add noop to the beginning of every method - private fun getStartInst(method: JcMethod): JcNoopInst { - val lineNumber = method.flowGraph().entries.firstOrNull()?.lineNumber?.let { it - 1 } ?: -1 - return JcNoopInst(JcInstLocationImpl(method, -1, lineNumber)) - } - - override fun predecessors(node: JcInst): Sequence { - val method = methodOf(node) - return when (node) { - getStartInst(method) -> { - emptySequence() - } - - in graph.entryPoints(method) -> { - sequenceOf(getStartInst(method)) - } - - else -> { - graph.predecessors(node) - } - } - } - - override fun successors(node: JcInst): Sequence { - val method = methodOf(node) - return when (node) { - getStartInst(method) -> { - graph.entryPoints(method) - } - - else -> { - graph.successors(node) - } - } - } - - private fun getOverrides(method: JcMethod): List { - return if (cache.containsKey(method)) { - cache[method]!! - } else { - val res = hierarchyExtension.findOverrides(method).toList() - cache[method] = res - res - } - } - - private fun calleesUnmarked(node: JcInst): Sequence { - val callees = graph.callees(node).filterNot { callee -> - bannedPackagePrefixes.any { callee.enclosingClass.name.startsWith(it) } - } - - val callExpr = node.callExpr as? JcVirtualCallExpr ?: return callees - val instanceClass = (callExpr.instance.type as? JcClassType)?.jcClass ?: return callees - - return callees - .flatMap { callee -> - val allOverrides = getOverrides(callee) - .filter { - it.enclosingClass isSubClassOf instanceClass || - // TODO: use only down-most override here - instanceClass isSubClassOf it.enclosingClass - } - - // TODO: maybe filter inaccessible methods here? - allOverrides + sequenceOf(callee) - } - } - - override fun callees(node: JcInst): Sequence { - return calleesUnmarked(node).also { - it.forEach { method -> - visitedCallers.getOrPut(method) { mutableSetOf() }.add(node) - } - } - } - - /** - * This is IFDS-algorithm aware optimization. - * In IFDS we don't need all method callers, we need only method callers which we visited earlier. - */ - // TODO: Think if this optimization is really needed - override fun callers(method: JcMethod): Sequence = - visitedCallers[method].orEmpty().asSequence() - - override fun entryPoints(method: JcMethod): Sequence = try { - sequenceOf(getStartInst(method)) - } catch (e: Throwable) { - // we couldn't find instructions list - // TODO: maybe fix flowGraph() - emptySequence() - } - - override fun exitPoints(method: JcMethod): Sequence = try { - graph.exitPoints(method) - } catch (e: Throwable) { - // we couldn't find instructions list - // TODO: maybe fix flowGraph() - emptySequence() - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/AccessPath.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/AccessPath.kt deleted file mode 100644 index ad7ba3123..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/AccessPath.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.ifds - -import org.jacodb.api.common.cfg.CommonValue - -data class AccessPath internal constructor( - val value: CommonValue?, - val accesses: List, -) { - init { - if (value == null) { - require(accesses.isNotEmpty()) - val a = accesses[0] - require(a is FieldAccessor) - require(a.isStatic) - } - } - - fun limit(n: Int): AccessPath = AccessPath(value, accesses.take(n)) - - operator fun plus(accesses: List): AccessPath { - for (accessor in accesses) { - if (accessor is FieldAccessor && accessor.isStatic) { - throw IllegalArgumentException("Unexpected static field: ${accessor.name}") - } - } - - return AccessPath(value, this.accesses + accesses) - } - - operator fun plus(accessor: Accessor): AccessPath { - if (accessor is FieldAccessor && accessor.isStatic) { - throw IllegalArgumentException("Unexpected static field: ${accessor.name}") - } - - return AccessPath(value, this.accesses + accessor) - } - - override fun toString(): String { - return value.toString() + accesses.joinToString("") { it.toSuffix() } - } -} - -val AccessPath.isOnHeap: Boolean - get() = accesses.isNotEmpty() - -val AccessPath.isStatic: Boolean - get() = value == null - -operator fun AccessPath.minus(other: AccessPath): List? { - if (value != other.value) return null - if (accesses.take(other.accesses.size) != other.accesses) return null - return accesses.drop(other.accesses.size) -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Accessors.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Accessors.kt deleted file mode 100644 index 22a29c38e..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Accessors.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.ifds - -sealed interface Accessor { - fun toSuffix(): String -} - -data class FieldAccessor( - val name: String, - val isStatic: Boolean = false, -) : Accessor { - override fun toSuffix(): String = ".${name}" - override fun toString(): String = name -} - -object ElementAccessor : Accessor { - override fun toSuffix(): String = "[*]" - override fun toString(): String = "*" -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt deleted file mode 100644 index 00e24c1ca..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.ifds - -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.cfg.CommonInst - -interface Analyzer - where Method : CommonMethod, - Statement : CommonInst { - - val flowFunctions: FlowFunctions - - fun handleNewEdge( - edge: Edge, - ): List - - fun handleCrossUnitCall( - caller: Vertex, - callee: Vertex, - ): List -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Edge.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Edge.kt deleted file mode 100644 index 9ed0e27cc..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Edge.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.ifds - -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.cfg.CommonInst - -data class Edge( - val from: Vertex, - val to: Vertex, -) { - init { - require(from.method == to.method) - } - - val method: CommonMethod - get() = from.method - - override fun toString(): String { - return "(${from.fact} at ${from.statement}) -> (${to.fact} at ${to.statement}) in $method" - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt deleted file mode 100644 index c6878bc39..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.ifds - -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.cfg.CommonInst - -fun interface FlowFunction { - fun compute(fact: Fact): Collection -} - -interface FlowFunctions - where Method : CommonMethod, - Statement : CommonInst { - - /** - * Method for obtaining initial domain facts at the method entrypoint. - * Commonly, it is only `listOf(Zero)`. - */ - fun obtainPossibleStartFacts(method: Method): Collection - - /** - * Sequent flow function. - * - * ``` - * [ DO() ] :: current - * | - * | (sequent edge) - * | - * [ DO() ] - * ``` - */ - fun obtainSequentFlowFunction( - current: Statement, - next: Statement, - ): FlowFunction - - /** - * Call-to-return-site flow function. - * - * ``` - * [ CALL p ] :: callStatement - * : - * : (call-to-return-site edge) - * : - * [ RETURN FROM p ] :: returnSite - * ``` - */ - fun obtainCallToReturnSiteFlowFunction( - callStatement: Statement, - returnSite: Statement, - ): FlowFunction - - /** - * Call-to-start flow function. - * - * ``` - * [ CALL p ] :: callStatement - * : \ - * : \ (call-to-start edge) - * : \ - * : [ START p ] - * : | - * : [ EXIT p ] - * : / - * : / - * [ RETURN FROM p ] - * ``` - */ - fun obtainCallToStartFlowFunction( - callStatement: Statement, - calleeStart: Statement, - ): FlowFunction - - /** - * Exit-to-return-site flow function. - * - * ``` - * [ CALL p ] :: callStatement - * : \ - * : \ - * : [ START p ] - * : | - * : [ EXIT p ] :: exitStatement - * : / - * : / (exit-to-return-site edge) - * : / - * [ RETURN FROM p ] :: returnSite - * ``` - */ - fun obtainExitToReturnSiteFlowFunction( - callStatement: Statement, - returnSite: Statement, - exitStatement: Statement, - ): FlowFunction -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/IfdsResult.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/IfdsResult.kt deleted file mode 100644 index 51e2e6fa1..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/IfdsResult.kt +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.ifds - -import org.jacodb.api.common.cfg.CommonInst - -/** - * Aggregates all facts and edges found by the tabulation algorithm. - */ -class IfdsResult internal constructor( - val pathEdgesBySink: Map, Collection>>, - val facts: Map>, - val reasons: Map, Set>>, - val zeroFact: Fact, -) { - - constructor( - pathEdges: Collection>, - facts: Map>, - reasons: Map, Set>>, - zeroFact: Fact, - ) : this( - pathEdges.groupByTo(HashMap()) { it.to }, - facts, - reasons, - zeroFact - ) - - fun buildTraceGraph(sink: Vertex): TraceGraph { - val sources: MutableSet> = - hashSetOf() - val edges: MutableMap, MutableSet>> = - hashMapOf() - val unresolvedCrossUnitCalls: MutableMap, MutableSet>> = - hashMapOf() - val visited: MutableSet, Vertex>> = - hashSetOf() - - fun addEdge( - from: Vertex, - to: Vertex, - ) { - if (from != to) { - edges.getOrPut(from) { hashSetOf() }.add(to) - } - } - - fun dfs( - edge: Edge, - lastVertex: Vertex, - stopAtMethodStart: Boolean, - ) { - if (!visited.add(edge to lastVertex)) { - return - } - - // Note: loop-edge represents method start - if (stopAtMethodStart && edge.from == edge.to) { - addEdge(edge.from, lastVertex) - return - } - - val vertex = edge.to - if (vertex.fact == zeroFact) { - addEdge(vertex, lastVertex) - sources.add(vertex) - return - } - - for (reason in reasons[edge].orEmpty()) { - when (reason) { - is Reason.Sequent -> { - val predEdge = reason.edge - if (predEdge.to.fact == vertex.fact) { - dfs(predEdge, lastVertex, stopAtMethodStart) - } else { - addEdge(predEdge.to, lastVertex) - dfs(predEdge, predEdge.to, stopAtMethodStart) - } - } - - is Reason.CallToStart -> { - val predEdge = reason.edge - if (!stopAtMethodStart) { - addEdge(predEdge.to, lastVertex) - dfs(predEdge, predEdge.to, false) - } - } - - is Reason.ThroughSummary -> { - val predEdge = reason.edge - val summaryEdge = reason.summaryEdge - addEdge(summaryEdge.to, lastVertex) // Return to next vertex - addEdge(predEdge.to, summaryEdge.from) // Call to start - dfs(summaryEdge, summaryEdge.to, true) // Expand summary edge - dfs(predEdge, predEdge.to, stopAtMethodStart) // Continue normal analysis - } - - is Reason.CrossUnitCall -> { - addEdge(edge.to, lastVertex) - unresolvedCrossUnitCalls.getOrPut(reason.caller) { hashSetOf() }.add(edge.to) - } - - is Reason.External -> { - TODO("External reason is not supported yet") - } - - is Reason.Initial -> { - sources.add(vertex) - addEdge(edge.to, lastVertex) - } - } - } - } - - for (edge in pathEdgesBySink[sink].orEmpty()) { - dfs(edge, edge.to, false) - } - return TraceGraph(sink, sources, edges, unresolvedCrossUnitCalls) - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Manager.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Manager.kt deleted file mode 100644 index 85541f581..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Manager.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.ifds - -import kotlinx.coroutines.CoroutineScope -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.cfg.CommonInst - -interface Manager - where Method : CommonMethod, - Statement : CommonInst { - - fun handleEvent(event: Event) - - fun handleControlEvent(event: ControlEvent) - - fun subscribeOnSummaryEdges( - method: @UnsafeVariance Method, - scope: CoroutineScope, - handler: (Edge) -> Unit, - ) -} - -sealed interface ControlEvent - -data class QueueEmptinessChanged( - val runner: Runner<*, *, *>, - val isEmpty: Boolean, -) : ControlEvent diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Reason.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Reason.kt deleted file mode 100644 index a0a3396bf..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Reason.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.ifds - -import org.jacodb.api.common.cfg.CommonInst - -sealed interface Reason { - - object Initial : Reason - - object External : Reason - - data class CrossUnitCall( - val caller: Vertex, - ) : Reason - - data class Sequent( - val edge: Edge, - ) : Reason - - data class CallToStart( - val edge: Edge, - ) : Reason - - data class ThroughSummary( - val edge: Edge, - val summaryEdge: Edge, - ) : Reason -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Runner.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Runner.kt deleted file mode 100644 index 06b7f2ea2..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Runner.kt +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.ifds - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.channels.getOrElse -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.isActive -import org.jacodb.analysis.graph.JcNoopInst -import org.jacodb.analysis.taint.TaintZeroFact -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonCallExpr -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.ets.base.EtsStmt -import java.util.concurrent.ConcurrentHashMap -import org.jacodb.api.jvm.ext.cfg.callExpr as jcCallExpr -import org.jacodb.ets.utils.callExpr as etsCallExpr -import org.jacodb.panda.staticvm.cfg.PandaInst as StaticPandaInst -import org.jacodb.panda.staticvm.utils.callExpr as staticPandaCallExpr - -private val logger = mu.KotlinLogging.logger {} - -interface Runner - where Method : CommonMethod, - Statement : CommonInst { - - val graph: ApplicationGraph - val unit: UnitType - - suspend fun run(startMethods: List) - fun submitNewEdge(edge: Edge, reason: Reason) - fun getIfdsResult(): IfdsResult -} - -class UniRunner( - private val manager: Manager, - override val graph: ApplicationGraph, - private val analyzer: Analyzer, - private val unitResolver: UnitResolver, - override val unit: UnitType, - private val zeroFact: Fact, -) : Runner - where Method : CommonMethod, - Statement : CommonInst { - - private val Statement.callExpr: CommonCallExpr? - get() = when (this) { - is JcInst -> jcCallExpr - is StaticPandaInst -> staticPandaCallExpr - is EtsStmt -> etsCallExpr - else -> error("Unsupported statement type: $this") - } - - private val flowSpace: FlowFunctions = analyzer.flowFunctions - private val workList: Channel> = Channel(Channel.UNLIMITED) - internal val pathEdges: MutableSet> = ConcurrentHashMap.newKeySet() - private val reasons = - ConcurrentHashMap, MutableSet>>() - - private val summaryEdges: MutableMap, MutableSet>> = - hashMapOf() - private val callerPathEdgeOf: MutableMap, MutableSet>> = - hashMapOf() - - private val queueIsEmpty = QueueEmptinessChanged(runner = this, isEmpty = true) - private val queueIsNotEmpty = QueueEmptinessChanged(runner = this, isEmpty = false) - - override suspend fun run(startMethods: List) { - for (method in startMethods) { - addStart(method) - } - - tabulationAlgorithm() - } - - private fun addStart(method: Method) { - require(unitResolver.resolve(method) == unit) - val startFacts = flowSpace.obtainPossibleStartFacts(method) - for (startFact in startFacts) { - for (start in graph.entryPoints(method)) { - val vertex = Vertex(start, startFact) - val edge = Edge(vertex, vertex) // loop - propagate(edge, Reason.Initial) - } - } - } - - override fun submitNewEdge(edge: Edge, reason: Reason) { - propagate(edge, reason) - } - - private fun propagate( - edge: Edge, - reason: Reason, - ): Boolean { - val method = graph.methodOf(edge.from.statement) - require(unitResolver.resolve(method) == unit) { - "Propagated edge must be in the same unit" - } - - reasons.computeIfAbsent(edge) { ConcurrentHashMap.newKeySet() }.add(reason) - - // Handle only NEW edges: - if (pathEdges.add(edge)) { - val doPrintOnlyForward = true - val doPrintZero = false - if (!doPrintOnlyForward || edge.from.statement is JcNoopInst) { - if (doPrintZero || edge.to.fact != TaintZeroFact) { - logger.trace { - "Propagating edge=${edge} in method=${method.name} with reason=${reason}" - } - } - } - - // Send edge to analyzer/manager: - for (event in analyzer.handleNewEdge(edge)) { - manager.handleEvent(event) - } - - // Add edge to worklist: - workList.trySend(edge).getOrThrow() - - return true - } - - return false - } - - private suspend fun tabulationAlgorithm() = coroutineScope { - while (isActive) { - val edge = workList.tryReceive().getOrElse { - manager.handleControlEvent(queueIsEmpty) - val edge = workList.receive() - manager.handleControlEvent(queueIsNotEmpty) - edge - } - tabulationAlgorithmStep(edge, this@coroutineScope) - } - } - - private val Method.isExtern: Boolean - get() = unitResolver.resolve(this) != unit - - private fun tabulationAlgorithmStep( - currentEdge: Edge, - scope: CoroutineScope, - ) { - val (startVertex, currentVertex) = currentEdge - val (current, currentFact) = currentVertex - - val currentCallees = graph.callees(current).toList() - val currentIsCall = current.callExpr != null - val currentIsExit = current in graph.exitPoints(graph.methodOf(current)) - - if (currentIsCall) { - // Propagate through the call-to-return-site edge: - for (returnSite in graph.successors(current)) { - val factsAtReturnSite = flowSpace - .obtainCallToReturnSiteFlowFunction(current, returnSite) - .compute(currentFact) - for (returnSiteFact in factsAtReturnSite) { - val returnSiteVertex = Vertex(returnSite, returnSiteFact) - val newEdge = Edge(startVertex, returnSiteVertex) - propagate(newEdge, Reason.Sequent(currentEdge)) - } - } - - // Propagate through the call: - for (callee in currentCallees) { - for (calleeStart in graph.entryPoints(callee)) { - val factsAtCalleeStart = flowSpace - .obtainCallToStartFlowFunction(current, calleeStart) - .compute(currentFact) - for (calleeStartFact in factsAtCalleeStart) { - val calleeStartVertex = Vertex(calleeStart, calleeStartFact) - - if (callee.isExtern) { - // Initialize analysis of callee: - for (event in analyzer.handleCrossUnitCall(currentVertex, calleeStartVertex)) { - manager.handleEvent(event) - } - - // Subscribe on summary edges: - manager.subscribeOnSummaryEdges(callee, scope) { summaryEdge -> - if (summaryEdge.from == calleeStartVertex) { - handleSummaryEdge(currentEdge, summaryEdge) - } else { - logger.trace { "Skipping unsuitable summary edge: $summaryEdge" } - } - } - } else { - // Save info about the call for summary edges that will be found later: - callerPathEdgeOf.getOrPut(calleeStartVertex) { hashSetOf() }.add(currentEdge) - - // Initialize analysis of callee: - run { - val newEdge = Edge(calleeStartVertex, calleeStartVertex) // loop - propagate(newEdge, Reason.CallToStart(currentEdge)) - } - - // Handle already-found summary edges: - for (exitVertex in summaryEdges[calleeStartVertex].orEmpty()) { - val summaryEdge = Edge(calleeStartVertex, exitVertex) - handleSummaryEdge(currentEdge, summaryEdge) - } - } - } - } - } - } else { - if (currentIsExit) { - // Propagate through the summary edge: - for (callerPathEdge in callerPathEdgeOf[startVertex].orEmpty()) { - handleSummaryEdge(currentEdge = callerPathEdge, summaryEdge = currentEdge) - } - - // Add new summary edge: - summaryEdges.getOrPut(startVertex) { hashSetOf() }.add(currentVertex) - } - - // Simple (sequential) propagation to the next instruction: - for (next in graph.successors(current)) { - val factsAtNext = flowSpace - .obtainSequentFlowFunction(current, next) - .compute(currentFact) - for (nextFact in factsAtNext) { - val nextVertex = Vertex(next, nextFact) - val newEdge = Edge(startVertex, nextVertex) - propagate(newEdge, Reason.Sequent(currentEdge)) - } - } - } - } - - private fun handleSummaryEdge( - currentEdge: Edge, - summaryEdge: Edge, - ) { - val (startVertex, currentVertex) = currentEdge - val caller = currentVertex.statement - for (returnSite in graph.successors(caller)) { - val (exit, exitFact) = summaryEdge.to - val finalFacts = flowSpace - .obtainExitToReturnSiteFlowFunction(caller, returnSite, exit) - .compute(exitFact) - for (returnSiteFact in finalFacts) { - val returnSiteVertex = Vertex(returnSite, returnSiteFact) - val newEdge = Edge(startVertex, returnSiteVertex) - propagate(newEdge, Reason.ThroughSummary(currentEdge, summaryEdge)) - } - } - } - - private fun getFinalFacts(): Map> { - val resultFacts: MutableMap> = hashMapOf() - for (edge in pathEdges) { - resultFacts.getOrPut(edge.to.statement) { hashSetOf() }.add(edge.to.fact) - } - return resultFacts - } - - override fun getIfdsResult(): IfdsResult { - val facts = getFinalFacts() - return IfdsResult(pathEdges, facts, reasons, zeroFact) - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt deleted file mode 100644 index c7e06ef31..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.ifds - -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.SharedFlow -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.cfg.CommonInst -import java.util.concurrent.ConcurrentHashMap - -/** - * A common interface for anything that should be remembered - * and used after the analysis of some unit is completed. - */ -interface Summary { - val method: Method -} - -interface SummaryEdge : Summary { - - val edge: Edge - - override val method: CommonMethod - get() = edge.method -} - -interface Vulnerability : Summary { - val message: String - val sink: Vertex - - override val method: CommonMethod - get() = sink.method -} - -/** - * Contains summaries for many methods and allows to update them and subscribe for them. - */ -interface SummaryStorage> { - - /** - * A list of all methods for which summaries are not empty. - */ - val knownMethods: List - - /** - * Adds [summary] the summaries storage of its method. - */ - fun add(summary: T) - - /** - * @return a flow with all facts summarized for the given [method]. - * Already received facts, along with the facts that will be sent to this storage later, - * will be emitted to the returned flow. - */ - fun getFacts(method: CommonMethod): Flow - - /** - * @return a list will all facts summarized for the given [method] so far. - */ - fun getCurrentFacts(method: CommonMethod): List -} - -class SummaryStorageImpl> : SummaryStorage { - - private val summaries = ConcurrentHashMap>() - private val outFlows = ConcurrentHashMap>() - - override val knownMethods: List - get() = summaries.keys.toList() - - private fun getFlow(method: CommonMethod): MutableSharedFlow { - return outFlows.computeIfAbsent(method) { - MutableSharedFlow(replay = Int.MAX_VALUE) - } - } - - override fun add(summary: T) { - val isNew = summaries.computeIfAbsent(summary.method) { - ConcurrentHashMap.newKeySet() - }.add(summary) - if (isNew) { - val flow = getFlow(summary.method) - check(flow.tryEmit(summary)) - } - } - - override fun getFacts(method: CommonMethod): SharedFlow { - return getFlow(method) - } - - override fun getCurrentFacts(method: CommonMethod): List { - return getFacts(method).replayCache - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/TraceGraph.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/TraceGraph.kt deleted file mode 100644 index 13de77959..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/TraceGraph.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.ifds - -import org.jacodb.api.common.cfg.CommonInst - -data class TraceGraph( - val sink: Vertex, - val sources: MutableSet>, - val edges: MutableMap, MutableSet>>, - val unresolvedCrossUnitCalls: Map, Set>>, -) { - - /** - * Returns all traces from [sources] to [sink]. - */ - fun getAllTraces(): Sequence>> = - sources.asSequence().flatMap { getAllTraces(mutableListOf(it)) } - - private fun getAllTraces( - trace: MutableList>, - ): Sequence>> = sequence { - val v = trace.last() - if (v == sink) { - yield(trace.toList()) // copy list - return@sequence - } - for (u in edges[v].orEmpty()) { - if (u !in trace) { - trace.add(u) - yieldAll(getAllTraces(trace)) - trace.removeLast() - } - } - } - - /** - * Merges [upGraph] into this graph. - */ - fun mergeWithUpGraph( - upGraph: TraceGraph, - entryPoints: Set>, - ) { - sources.addAll(upGraph.sources) - - for (edge in upGraph.edges) { - edges.getOrPut(edge.key) { hashSetOf() }.addAll(edge.value) - } - - edges.getOrPut(upGraph.sink) { hashSetOf() }.addAll(entryPoints) - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/UnitResolver.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/UnitResolver.kt deleted file mode 100644 index 5afa581af..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/UnitResolver.kt +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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. - */ - -@file:Suppress("FunctionName") - -package org.jacodb.analysis.ifds - -import org.jacodb.api.jvm.JcClassOrInterface -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.ext.packageName - -interface UnitType - -data class MethodUnit(val method: JcMethod) : UnitType { - override fun toString(): String { - return "MethodUnit(${method.name})" - } -} - -data class ClassUnit(val clazz: JcClassOrInterface) : UnitType { - override fun toString(): String { - return "ClassUnit(${clazz.simpleName})" - } -} - -data class PackageUnit(val packageName: String) : UnitType { - override fun toString(): String { - return "PackageUnit($packageName)" - } -} - -object SingletonUnit : UnitType { - override fun toString(): String = javaClass.simpleName -} - -object UnknownUnit : UnitType { - override fun toString(): String = javaClass.simpleName -} - -/** - * Sets a mapping from a [Method] to abstract domain [UnitType]. - * - * Therefore, it splits all methods into units, containing one or more method each - * (unit is a set of methods with same value of [UnitType] returned by [resolve]). - * - * To get more info about how it is used in analysis, see [runAnalysis]. - */ -fun interface UnitResolver { - fun resolve(method: Method): UnitType - - companion object { - fun getByName(name: String): UnitResolver = when (name) { - "method" -> MethodUnitResolver - "class" -> ClassUnitResolver(false) - "package" -> PackageUnitResolver - "singleton" -> SingletonUnitResolver - else -> error("Unknown unit resolver '$name'") - } - } -} - -fun interface JcUnitResolver : UnitResolver - -val MethodUnitResolver = JcUnitResolver { method -> - MethodUnit(method) -} - -private val ClassUnitResolverWithNested = JcUnitResolver { method -> - val clazz = generateSequence(method.enclosingClass) { it.outerClass }.last() - ClassUnit(clazz) -} -private val ClassUnitResolverWithoutNested = JcUnitResolver { method -> - val clazz = method.enclosingClass - ClassUnit(clazz) -} - -fun ClassUnitResolver(includeNested: Boolean) = - if (includeNested) { - ClassUnitResolverWithNested - } else { - ClassUnitResolverWithoutNested - } - -val PackageUnitResolver = JcUnitResolver { method -> - PackageUnit(method.enclosingClass.packageName) -} - -val SingletonUnitResolver = JcUnitResolver { - SingletonUnit -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Vertex.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Vertex.kt deleted file mode 100644 index a3830ee6b..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Vertex.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.ifds - -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.cfg.CommonInst - -data class Vertex( - val statement: Statement, - val fact: Fact, -) { - val method: CommonMethod - get() = statement.method - - override fun toString(): String { - return "$fact at $statement in $method" - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/AbstractFlowAnalysis.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/AbstractFlowAnalysis.kt deleted file mode 100644 index 492c41c86..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/AbstractFlowAnalysis.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.impl.custom - -import org.jacodb.api.jvm.cfg.JcBytecodeGraph - -abstract class AbstractFlowAnalysis(override val graph: JcBytecodeGraph) : FlowAnalysis { - - override fun newEntryFlow(): T = newFlow() - - protected open fun merge(successor: NODE, income1: T, income2: T, outcome: T) { - merge(income1, income2, outcome) - } - - open fun ins(s: NODE): T? { - return ins[s] - } - - protected fun mergeInto(successor: NODE, input: T, incoming: T) { - val tmp = newFlow() - merge(successor, input, incoming, tmp) - copy(tmp, input) - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/BackwardFlowAnalysis.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/BackwardFlowAnalysis.kt deleted file mode 100644 index 53c35774b..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/BackwardFlowAnalysis.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.impl.custom - -import org.jacodb.api.jvm.cfg.JcBytecodeGraph - -abstract class BackwardFlowAnalysis(graph: JcBytecodeGraph) : FlowAnalysisImpl(graph) { - - override val isForward: Boolean = false - - override fun run() { - runAnalysis(FlowAnalysisDirection.BACKWARD, outs, ins) - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysis.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysis.kt deleted file mode 100644 index 105ed664d..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysis.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.impl.custom - -import org.jacodb.api.jvm.cfg.JcBytecodeGraph - -interface FlowAnalysis { - - val ins: MutableMap - val outs: MutableMap - - val graph: JcBytecodeGraph - - val isForward: Boolean - - fun newFlow(): T - - fun newEntryFlow(): T - - fun merge(in1: T, in2: T, out: T) - - fun copy(source: T?, dest: T) - - fun run() -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysisImpl.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysisImpl.kt deleted file mode 100644 index 454436c19..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysisImpl.kt +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.impl.custom - -import org.jacodb.api.jvm.cfg.JcBytecodeGraph -import org.jacodb.api.jvm.cfg.JcGotoInst -import java.util.* - -enum class Flow { - IN { - override fun getFlow(e: FlowEntry): F? { - return e.inFlow - } - }, - OUT { - override fun getFlow(e: FlowEntry): F? { - return e.outFlow - } - }; - - abstract fun getFlow(e: FlowEntry): F? -} - -/** - * Creates a new `Entry` graph based on a `JcGraph`. This includes pseudo topological order, local - * access for predecessors and successors, a graph entry-point, connected component marker. - */ -private fun JcBytecodeGraph.newScope( - direction: FlowAnalysisDirection, - entryFlow: T, - isForward: Boolean, -): List> { - val size = toList().size - val s = ArrayDeque>(size) - val scope = ArrayList>(size) - val visited = HashMap>((size + 1) * 4 / 3) - - // out of scope node - val instructions: List? - val actualEntries = direction.entries(this) - if (actualEntries.isNotEmpty()) { - // normal cases: there is at least - // one return statement for a backward analysis - // or one entry statement for a forward analysis - instructions = actualEntries - } else { - // cases without any entry statement - if (isForward) { - // case of a forward flow analysis on - // a method without any entry point - throw RuntimeException("No entry point for method in forward analysis") - } else { - // case of backward analysis on - // a method which potentially has - // an infinite loop and no return statement - instructions = ArrayList() - val head = entries.first() - - // collect all 'goto' statements to catch the 'goto' from the infinite loop - val visitedInst = HashSet() - val list = arrayListOf(head) - var temp: NODE - while (list.isNotEmpty()) { - temp = list.removeAt(0) - visitedInst.add(temp) - - // only add 'goto' statements - if (temp is JcGotoInst) { - instructions.add(temp) - } - for (next in successors(temp)) { - if (visitedInst.contains(next)) { - continue - } - list.add(next) - } - } - - if (instructions.isEmpty()) { - throw RuntimeException("Backward analysis on an empty entry set.") - } - } - } - val root = RootEntry() - root.visitEntry(instructions, visited) - root.inFlow = entryFlow - root.outFlow = entryFlow - - val sv: Array?> = arrayOfNulls(size) - val si = IntArray(size) - var index = 0 - var i = 0 - var entry: FlowEntry = root - while (true) { - if (i < entry.outs.size) { - val next = entry.outs[i++] - - // an unvisited child node - if (next.number == Int.MIN_VALUE) { - next.number = s.size - s.add(next) - next.visitEntry(direction.outOf(this, next.data), visited) - - // save old - si[index] = i - sv[index] = entry - index++ - i = 0 - entry = next - } - } else { - if (index == 0) { - assert(scope.size <= size) - scope.reverse() - return scope - } - scope.add(entry) - s.pop(entry) - - // restore old - index-- - entry = sv[index]!! - i = si[index] - } - } -} - -private fun FlowEntry.visitEntry( - instructions: List, - visited: MutableMap>, -): Array> { - val n = instructions.size - return Array(n) { - instructions[it].toEntry(this, visited) - }.also { - outs = it - } -} - -private fun NODE.toEntry( - pred: FlowEntry, - visited: MutableMap>, -): FlowEntry { - // either we reach a new node or a merge node, the latter one is rare - // so put and restore should be better that a lookup - - val newEntry = LeafEntry(this, pred) - val oldEntry = visited.putIfAbsent(this, newEntry) ?: return newEntry - - // no restore required - - // adding self ref (real strongly connected with itself) - if (oldEntry === pred) { - oldEntry.isStronglyConnected = true - } - - // merge nodes are rare, so this is ok - val length = oldEntry.ins.size - oldEntry.ins = Arrays.copyOf(oldEntry.ins, length + 1) - oldEntry.ins[length] = pred - return oldEntry -} - -private fun Deque>.pop(entry: FlowEntry) { - var min = entry.number - for (e in entry.outs) { - assert(e.number > Int.MIN_VALUE) - min = min.coerceAtMost(e.number) - } - - // not our SCC - if (min != entry.number) { - entry.number = min - return - } - - // we only want real SCCs (size > 1) - var last = removeLast() - last.number = Int.MAX_VALUE - if (last === entry) { - return - } - last.isStronglyConnected = true - while (true) { - last = removeLast() - assert(last.number >= entry.number) - last.isStronglyConnected = true - last.number = Int.MAX_VALUE - if (last === entry) { - assert(last.ins.size >= 2) - return - } - } -} - -enum class FlowAnalysisDirection { - BACKWARD { - override fun entries(g: JcBytecodeGraph): List { - return g.exits - } - - override fun outOf(g: JcBytecodeGraph, s: NODE): List { - return g.predecessors(s).toList() - } - }, - FORWARD { - override fun entries(g: JcBytecodeGraph): List { - return g.entries - } - - override fun outOf(g: JcBytecodeGraph, s: NODE): List { - return g.successors(s).toList() - } - }; - - abstract fun entries(g: JcBytecodeGraph): List - abstract fun outOf(g: JcBytecodeGraph, s: NODE): List -} - -abstract class FlowEntry(pred: FlowEntry?) { - - abstract val data: NODE - - var number = Int.MIN_VALUE - var isStronglyConnected = false - var ins: Array> = pred?.let { arrayOf(pred) } ?: emptyArray() - var outs: Array> = emptyArray() - var inFlow: T? = null - var outFlow: T? = null - - override fun toString(): String { - return data.toString() - } - -} - -class RootEntry : FlowEntry(null) { - override val data: NODE get() = throw IllegalStateException() -} - -class LeafEntry(override val data: NODE, pred: FlowEntry?) : FlowEntry(pred) - -abstract class FlowAnalysisImpl(graph: JcBytecodeGraph) : AbstractFlowAnalysis(graph) { - - protected abstract fun flowThrough(instIn: T?, ins: NODE, instOut: T) - - fun outs(s: NODE): T { - return outs[s] ?: newFlow() - } - - override fun ins(s: NODE): T { - return ins[s] ?: newFlow() - } - - private fun Iterable>.initFlow() { - // If a node has only a single in-flow, the in-flow is always equal - // to the out-flow if its predecessor, so we use the same object. - // this saves memory and requires less object creation and copy calls. - - // Furthermore a node can be marked as `canSkip`, this allows us to use - // the same "flow-set" for out-flow and in-flow. T merge node with within - // a real scc cannot be omitted, as it could cause endless loops within - // the fixpoint-iteration! - for (node in this) { - var omit = true - val inFlow: T - val outFlow: T - - if (node.ins.size > 1) { - inFlow = newFlow() - - // no merge points in loops - omit = !node.isStronglyConnected - } else { - assert(node.ins.size == 1) { "Missing head" } - val flow = getFlow(node.ins.first(), node) - assert(flow != null) { "Topological order is broken" } - inFlow = flow!! - } - if (omit && node.data.canSkip) { - // We could recalculate the graph itself but that is more expensive than - // just falling through such nodes. - outFlow = inFlow - } else { - outFlow = newFlow() - } - node.inFlow = inFlow - node.outFlow = outFlow - - ins[node.data] = inFlow - outs[node.data] = outFlow - } - } - - /** - * If a flow node can be skipped return `true`, otherwise `false`. There is no guarantee a node will - * be omitted. `canSkip` node does not influence the result of an analysis. - * - * If you are unsure, don't overwrite this method - */ - protected open val NODE.canSkip: Boolean - get() { - return false - } - - protected open fun getFlow(from: NODE, mergeNode: NODE) = Flow.OUT - - private fun getFlow(o: FlowEntry, e: FlowEntry): T? { - return if (o.inFlow === o.outFlow) { - o.outFlow - } else { - getFlow(o.data, e.data).getFlow(o) - } - } - - private fun FlowEntry.meetFlows() { - assert(ins.isNotEmpty()) - if (ins.size > 1) { - var copy = true - for (o in ins) { - val flow = getFlow(o, this) - val inFlow = inFlow - if (flow != null && inFlow != null) { - if (copy) { - copy = false - copy(flow, inFlow) - } else { - mergeInto(data, inFlow, flow) - } - } - } - } - } - - open fun runAnalysis( - direction: FlowAnalysisDirection, - inFlow: Map, - outFlow: Map, - ): Int { - val scope = graph.newScope(direction, newEntryFlow(), isForward).also { - it.initFlow() - } - val queue = PriorityQueue> { o1, o2 -> o1.number.compareTo(o2.number) } - .also { it.addAll(scope) } - - // Perform fixed point flow analysis - var numComputations = 0 - while (true) { - val entry = queue.poll() ?: return numComputations - entry.meetFlows() - - val hasChanged = flowThrough(entry) - - // Update queue appropriately - if (hasChanged) { - queue.addAll(entry.outs.toList()) - } - numComputations++ - } - } - - private fun flowThrough(entry: FlowEntry): Boolean { - if (entry.inFlow === entry.outFlow) { - assert(!entry.isStronglyConnected || entry.ins.size == 1) - return true - } - if (entry.isStronglyConnected) { - // A flow node that is influenced by at least one back-reference. - // It's essential to check if "flowThrough" changes the result. - // This requires the calculation of "equals", which itself - // can be really expensive - depending on the used flow-model. - // Depending on the "merge"+"flowThrough" costs, it can be cheaper - // to fall through. Only nodes with real back-references always - // need to be checked for changes - val out = newFlow() - flowThrough(entry.inFlow, entry.data, out) - if (out == entry.outFlow) { - return false - } - // copy back the result, as it has changed - entry.outFlow?.let { - copy(out, it) - } - return true - } - - // no back-references, just calculate "flowThrough" - val outFlow = entry.outFlow - if (outFlow != null) { - flowThrough(entry.inFlow, entry.data, outFlow) - } - return true - } - -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/ForwardFlowAnalysis.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/ForwardFlowAnalysis.kt deleted file mode 100644 index 935283ca3..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/ForwardFlowAnalysis.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.impl.custom - -import org.jacodb.api.jvm.cfg.JcBytecodeGraph - -abstract class ForwardFlowAnalysis(graph: JcBytecodeGraph) : FlowAnalysisImpl(graph) { - - override val isForward = true - - override fun run() { - runAnalysis(FlowAnalysisDirection.FORWARD, ins, outs) - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/NullAssumptionAnalysis.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/NullAssumptionAnalysis.kt deleted file mode 100644 index 091762420..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/NullAssumptionAnalysis.kt +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.impl.custom - -import org.jacodb.api.jvm.JcRefType -import org.jacodb.api.jvm.cfg.JcArrayAccess -import org.jacodb.api.jvm.cfg.JcAssignInst -import org.jacodb.api.jvm.cfg.JcCallExpr -import org.jacodb.api.jvm.cfg.JcCastExpr -import org.jacodb.api.jvm.cfg.JcEnterMonitorInst -import org.jacodb.api.jvm.cfg.JcFieldRef -import org.jacodb.api.jvm.cfg.JcGraph -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.cfg.JcInstanceCallExpr -import org.jacodb.api.jvm.cfg.JcLocal -import org.jacodb.api.jvm.cfg.JcValue -import org.jacodb.api.jvm.ext.cfg.arrayRef -import org.jacodb.api.jvm.ext.cfg.callExpr -import org.jacodb.api.jvm.ext.cfg.fieldRef - -class NullAnalysisMap : HashMap { - - constructor() : super() - constructor(m: Map) : super(m) - - override fun get(key: JcValue): NullableState { - return super.get(key) ?: NullableState.UNKNOWN - } -} - -/** - * An inter-procedural nullness assumption analysis that computes for each location and each value in a method if the value - * (before or after that location) is treated as definitely null, definitely non-null or neither. This information could be - * useful in deciding whether to insert code that accesses a potentially null object. - * - * If the original program assumes a value is non-null, then adding a use of that value will not introduce any NEW nullness - * errors into the program. This code may be buggy, or just plain wrong. It has not been checked. - */ -open class NullAssumptionAnalysis(graph: JcGraph) : BackwardFlowAnalysis(graph) { - - override val ins: MutableMap = HashMap() - override val outs: MutableMap = HashMap() - - override fun flowThrough( - instIn: NullAnalysisMap?, - ins: JcInst, - instOut: NullAnalysisMap, - ) { - val out = instIn?.let { NullAnalysisMap(it) } ?: NullAnalysisMap() - - // programmer assumes we have a non-null value - if (ins is JcEnterMonitorInst) { - out[ins.monitor] = NullableState.NON_NULL - } - - // if we have an array ref, set the info for this ref to TOP, - // because we need to be conservative here - ins.arrayRef?.let { - onArrayAccess(it, out) - } - // same for field refs, but also set the receiver object to non-null, if there is one - ins.fieldRef?.let { - onFieldRef(it, out) - } - // same for invoke expr., also set the receiver object to non-null, if there is one - ins.callExpr?.let { - onCallExpr(it, out) - } - - // allow sublasses to define certain values as always-non-null - for (entry in out.entries) { - if (isAlwaysNonNull(entry.key)) { - entry.setValue(NullableState.NON_NULL) - } - } - - // if we have a definition (assignment) statement to a ref-like type, handle it, - if (ins is JcAssignInst) { - // need to copy the current out set because we need to assign under this assumption; - // so this copy becomes the in-set to handleRefTypeAssignment - if (ins.lhv.type is JcRefType) { - onRefTypeAssignment(ins, NullAnalysisMap(out), out) - } - } - - // save memory by only retaining information about locals - val outIter = out.keys.iterator() - while (outIter.hasNext()) { - val v = outIter.next() - if (!(v is JcLocal)) { - outIter.remove() - } - } - - // now copy the computed info to out - copy(out, instOut) - } - - protected open fun isAlwaysNonNull(v: JcValue): Boolean { - return false - } - - private fun onArrayAccess(arrayRef: JcArrayAccess, out: NullAnalysisMap) { - // here we know that the array must point to an object, but the array value might be anything - out[arrayRef.array] = NullableState.NON_NULL - } - - private fun onFieldRef(fieldRef: JcFieldRef, out: NullAnalysisMap) { - // here we know that the receiver must point to an object - val instance = fieldRef.instance - if (instance != null) { - out[instance] = NullableState.NON_NULL - } - } - - private fun onCallExpr(invokeExpr: JcCallExpr, out: NullAnalysisMap) { - if (invokeExpr is JcInstanceCallExpr) { - // here we know that the receiver must point to an object - out[invokeExpr.instance] = NullableState.NON_NULL - } - } - - private fun onRefTypeAssignment(assignStmt: JcAssignInst, rhsInfo: NullAnalysisMap, out: NullAnalysisMap) { - val right = when (val rhv = assignStmt.rhv) { - is JcCastExpr -> rhv.operand - is JcValue -> rhv - else -> null - } - if (right != null) { - - // An assignment invalidates any assumptions of null/non-null for lhs - // We COULD be more accurate by assigning those assumptions to the rhs prior to this statement - rhsInfo[right] = NullableState.UNKNOWN - - // assign from rhs to lhs - out[assignStmt.lhv] = rhsInfo[right] - } - } - - override fun copy(source: NullAnalysisMap?, dest: NullAnalysisMap) { - dest.clear() - if (source != null) { - dest.putAll(source) - } - } - - override fun newEntryFlow(): NullAnalysisMap { - return NullAnalysisMap() - } - - override fun newFlow(): NullAnalysisMap { - return NullAnalysisMap() - } - - override fun merge(in1: NullAnalysisMap, in2: NullAnalysisMap, out: NullAnalysisMap) { - val values = HashSet() - values.addAll(in1.keys) - values.addAll(in2.keys) - out.clear() - for (v in values) { - val leftAndRight = HashSet() - leftAndRight.add(in1[v]) - leftAndRight.add(in2[v]) - val result = if (leftAndRight.contains(NullableState.UNKNOWN)) { - // if on either side we know nothing... then together we know nothing for sure - NullableState.UNKNOWN - } else if (leftAndRight.contains(NullableState.NON_NULL)) { - if (leftAndRight.contains(NullableState.NULL)) { - // NULL and NON_NULL merges to BOTTOM - NullableState.UNKNOWN - } else { - // NON_NULL and NON_NULL stays NON_NULL - NullableState.NON_NULL - } - } else if (leftAndRight.contains(NullableState.NULL)) { - // NULL and NULL stays NULL - NullableState.NULL - } else { - // only BOTTOM remains - NullableState.UNKNOWN - } - out[v] = result - } - } - - /** - * Returns `true` if the analysis could determine that `value` is always treated as null after and including the instruction inst. - * - * @param inst instruction of the respective body - * @param value a local or constant value of that body - * @return true if value is always null right before this statement - */ - fun isAssumedNullBefore(inst: JcInst, value: JcValue): Boolean { - return ins(inst)[value] == NullableState.NULL - } - - /** - * Returns `true` if the analysis could determine that value is always treated as non-null after and including the - * statement s. - * - * @param inst instruction of the respective body - * @param value a local or constant value of that body - * @return true if value is always non-null right before this statement - */ - fun isAssumedNonNullBefore(inst: JcInst, value: JcValue): Boolean { - return ins(inst)[value] == NullableState.NON_NULL - } - -} - -enum class NullableState { - UNKNOWN, - NULL, - NON_NULL -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/ReachingDefinitionsAnalysis.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/ReachingDefinitionsAnalysis.kt deleted file mode 100644 index 31a93398a..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/ReachingDefinitionsAnalysis.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.impl.custom - -import org.jacodb.api.jvm.cfg.JcAssignInst -import org.jacodb.api.jvm.cfg.JcBasicBlock -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.cfg.JcInstRef -import org.jacodb.api.jvm.cfg.JcValue -import org.jacodb.impl.cfg.JcBlockGraphImpl -import java.util.BitSet - -class ReachingDefinitionsAnalysis(val blockGraph: JcBlockGraphImpl) { - val jcGraph get() = blockGraph.jcGraph - - private val nDefinitions = jcGraph.instructions.size - private val ins = mutableMapOf() - private val outs = mutableMapOf() - private val assignmentsMap = mutableMapOf>() - - init { - initAssignmentsMap() - val entry = blockGraph.entry - for (block in blockGraph) - outs[block] = emptySet() - - val queue = ArrayDeque().also { it += entry } - val notVisited = blockGraph.toMutableSet() - while (queue.isNotEmpty() || notVisited.isNotEmpty()) { - val current = when { - queue.isNotEmpty() -> queue.removeFirst() - else -> notVisited.random() - } - notVisited -= current - - ins[current] = fullPredecessors(current).map { outs[it]!! }.fold(emptySet()) { acc, bitSet -> - acc.or(bitSet) - acc - } - - val oldOut = outs[current]!!.clone() as BitSet - val newOut = gen(current) - - if (oldOut != newOut) { - outs[current] = newOut - for (successor in fullSuccessors(current)) { - queue += successor - } - } - } - } - - private fun initAssignmentsMap() { - for (inst in jcGraph) { - if (inst is JcAssignInst) { - assignmentsMap.getOrPut(inst.lhv, ::mutableSetOf) += jcGraph.ref(inst) - } - } - } - - private fun emptySet(): BitSet = BitSet(nDefinitions) - - private fun gen(block: JcBasicBlock): BitSet { - val inSet = ins[block]!!.clone() as BitSet - for (inst in blockGraph.instructions(block)) { - if (inst is JcAssignInst) { - for (kill in assignmentsMap.getOrDefault(inst.lhv, mutableSetOf())) { - inSet[kill] = false - } - inSet[jcGraph.ref(inst)] = true - } - } - return inSet - } - - private fun fullPredecessors(block: JcBasicBlock) = blockGraph.predecessors(block) + blockGraph.throwers(block) - private fun fullSuccessors(block: JcBasicBlock) = blockGraph.successors(block) + blockGraph.catchers(block) - - private operator fun BitSet.set(ref: JcInstRef, value: Boolean) { - this.set(ref.index, value) - } - - fun outs(block: JcBasicBlock): List { - val defs = outs.getOrDefault(block, emptySet()) - return (0 until nDefinitions).filter { defs[it] }.map { jcGraph.instructions[it] } - } - -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt deleted file mode 100644 index aef9e63a7..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.npe - -import org.jacodb.analysis.config.CallPositionToValueResolver -import org.jacodb.analysis.config.FactAwareConditionEvaluator -import org.jacodb.analysis.ifds.Analyzer -import org.jacodb.analysis.ifds.Reason -import org.jacodb.analysis.taint.EdgeForOtherRunner -import org.jacodb.analysis.taint.NewSummaryEdge -import org.jacodb.analysis.taint.NewVulnerability -import org.jacodb.analysis.taint.TaintDomainFact -import org.jacodb.analysis.taint.TaintEdge -import org.jacodb.analysis.taint.TaintEvent -import org.jacodb.analysis.taint.TaintVertex -import org.jacodb.analysis.taint.TaintVulnerability -import org.jacodb.analysis.taint.Tainted -import org.jacodb.analysis.util.Traits -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.jvm.JcMethod -import org.jacodb.taint.configuration.TaintConfigurationFeature -import org.jacodb.taint.configuration.TaintMark -import org.jacodb.taint.configuration.TaintMethodSink - -private val logger = mu.KotlinLogging.logger {} - -context(Traits) -class NpeAnalyzer( - private val graph: ApplicationGraph, -) : Analyzer, Method, Statement> - where Method : CommonMethod, - Statement : CommonInst { - - override val flowFunctions: ForwardNpeFlowFunctions by lazy { - ForwardNpeFlowFunctions(graph) - } - - private val taintConfigurationFeature: TaintConfigurationFeature? - get() = flowFunctions.taintConfigurationFeature - - private fun isExitPoint(statement: Statement): Boolean { - return statement in graph.exitPoints(graph.methodOf(statement)) - } - - override fun handleNewEdge( - edge: TaintEdge, - ): List> = buildList { - if (isExitPoint(edge.to.statement)) { - add(NewSummaryEdge(edge)) - } - - if (edge.to.fact is Tainted && edge.to.fact.mark == TaintMark.NULLNESS) { - if (edge.to.fact.variable.isDereferencedAt(edge.to.statement)) { - val message = "NPE" // TODO - val vulnerability = TaintVulnerability(message, sink = edge.to) - logger.info { - val m = graph.methodOf(vulnerability.sink.statement) - "Found sink=${vulnerability.sink} in $m" - } - add(NewVulnerability(vulnerability)) - } - } - - run { - val callExpr = edge.to.statement.getCallExpr() ?: return@run - val callee = callExpr.callee - - val config = taintConfigurationFeature?.let { feature -> - if (callee is JcMethod) { - logger.trace { "Extracting config for $callee" } - feature.getConfigForMethod(callee) - } else { - error("Cannot extract config for $callee") - } - } ?: return@run - - // TODO: not always we want to skip sinks on Zero facts. - // Some rules might have ConstantTrue or just true (when evaluated with Zero fact) condition. - if (edge.to.fact !is Tainted) { - return@run - } - - // Determine whether 'edge.to' is a sink via config: - val conditionEvaluator = FactAwareConditionEvaluator( - edge.to.fact, - CallPositionToValueResolver(edge.to.statement), - ) - for (item in config.filterIsInstance()) { - if (item.condition.accept(conditionEvaluator)) { - val message = item.ruleNote - val vulnerability = TaintVulnerability(message, sink = edge.to, rule = item) - logger.trace { - val m = graph.methodOf(vulnerability.sink.statement) - "Found sink=${vulnerability.sink} in $m on $item" - } - add(NewVulnerability(vulnerability)) - } - } - } - } - - override fun handleCrossUnitCall( - caller: TaintVertex, - callee: TaintVertex, - ): List> = buildList { - add(EdgeForOtherRunner(TaintEdge(callee, callee), Reason.CrossUnitCall(caller))) - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt deleted file mode 100644 index c2144b76b..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt +++ /dev/null @@ -1,665 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.npe - -import org.jacodb.analysis.config.BasicConditionEvaluator -import org.jacodb.analysis.config.CallPositionToAccessPathResolver -import org.jacodb.analysis.config.CallPositionToValueResolver -import org.jacodb.analysis.config.EntryPointPositionToAccessPathResolver -import org.jacodb.analysis.config.EntryPointPositionToValueResolver -import org.jacodb.analysis.config.FactAwareConditionEvaluator -import org.jacodb.analysis.config.TaintActionEvaluator -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.ElementAccessor -import org.jacodb.analysis.ifds.FlowFunction -import org.jacodb.analysis.ifds.FlowFunctions -import org.jacodb.analysis.ifds.isOnHeap -import org.jacodb.analysis.ifds.isStatic -import org.jacodb.analysis.ifds.minus -import org.jacodb.analysis.ifds.onSome -import org.jacodb.analysis.taint.TaintDomainFact -import org.jacodb.analysis.taint.TaintZeroFact -import org.jacodb.analysis.taint.Tainted -import org.jacodb.analysis.util.Traits -import org.jacodb.analysis.util.startsWith -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonAssignInst -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.common.cfg.CommonThis -import org.jacodb.api.common.cfg.CommonValue -import org.jacodb.api.jvm.JcArrayType -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.analysis.JcApplicationGraph -import org.jacodb.api.jvm.cfg.JcArgument -import org.jacodb.api.jvm.cfg.JcAssignInst -import org.jacodb.api.jvm.cfg.JcCallExpr -import org.jacodb.api.jvm.cfg.JcDynamicCallExpr -import org.jacodb.api.jvm.cfg.JcEqExpr -import org.jacodb.api.jvm.cfg.JcExpr -import org.jacodb.api.jvm.cfg.JcIfInst -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.cfg.JcInstanceCallExpr -import org.jacodb.api.jvm.cfg.JcNeqExpr -import org.jacodb.api.jvm.cfg.JcNewArrayExpr -import org.jacodb.api.jvm.cfg.JcNullConstant -import org.jacodb.api.jvm.cfg.JcReturnInst -import org.jacodb.api.jvm.ext.findType -import org.jacodb.impl.bytecode.isNullable -import org.jacodb.taint.configuration.AssignMark -import org.jacodb.taint.configuration.CopyAllMarks -import org.jacodb.taint.configuration.CopyMark -import org.jacodb.taint.configuration.RemoveAllMarks -import org.jacodb.taint.configuration.RemoveMark -import org.jacodb.taint.configuration.TaintCleaner -import org.jacodb.taint.configuration.TaintConfigurationFeature -import org.jacodb.taint.configuration.TaintEntryPointSource -import org.jacodb.taint.configuration.TaintMark -import org.jacodb.taint.configuration.TaintMethodSource -import org.jacodb.taint.configuration.TaintPassThrough - -private val logger = mu.KotlinLogging.logger {} - -context(Traits) -class ForwardNpeFlowFunctions( - private val graph: ApplicationGraph, -) : FlowFunctions - where Method : CommonMethod, - Statement : CommonInst { - - internal val taintConfigurationFeature: TaintConfigurationFeature? by lazy { - if (graph is JcApplicationGraph) { - graph.cp.features - ?.singleOrNull { it is TaintConfigurationFeature } - ?.let { it as TaintConfigurationFeature } - } else { - null - } - } - - override fun obtainPossibleStartFacts( - method: Method, - ): Collection = buildSet { - addAll(obtainPossibleStartFactsBasic(method)) - - // TODO: use common - if (method !is JcMethod) return@buildSet - - // Possibly null arguments: - for (p in method.parameters.filter { it.isNullable != false }) { - val t = (graph as JcApplicationGraph).cp.findType(p.type.typeName) - val arg = JcArgument.of(p.index, p.name, t) - val path = arg.toPath() - add(Tainted(path, TaintMark.NULLNESS)) - } - } - - private fun obtainPossibleStartFactsBasic( - method: Method, - ): Collection = buildSet { - // Zero (reachability) fact always present at entrypoint: - add(TaintZeroFact) - - // Extract initial facts from the config: - val config = taintConfigurationFeature?.let { feature -> - if (method is JcMethod) { - logger.trace { "Extracting config for $method" } - feature.getConfigForMethod(method) - } else { - error("Cannot extract config for $method") - } - } - if (config != null) { - val conditionEvaluator = BasicConditionEvaluator(EntryPointPositionToValueResolver(method)) - val actionEvaluator = TaintActionEvaluator(EntryPointPositionToAccessPathResolver(method)) - - // Handle EntryPointSource config items: - for (item in config.filterIsInstance()) { - if (item.condition.accept(conditionEvaluator)) { - for (action in item.actionsAfter) { - val result = when (action) { - is AssignMark -> actionEvaluator.evaluate(action) - else -> error("$action is not supported for $item") - } - result.onSome { addAll(it) } - } - } - } - } - } - - private fun transmitTaintAssign( - fact: Tainted, - from: JcExpr, - to: CommonValue, - ): Collection { - val toPath = to.toPath() - val fromPath = from.toPathOrNull() - - if (fact.mark == TaintMark.NULLNESS) { - // TODO: consider - // if (from is JcNewExpr - // || from is JcNewArrayExpr - // || from is JcConstant - // || (from is JcCallExpr && from.method.method.isNullable != true)) - if (fact.variable.startsWith(toPath)) { - // NULLNESS is overridden: - return emptySet() - } - } - - if (fromPath != null) { - // Adhoc taint array: - if (fromPath.accesses.isNotEmpty() - && fromPath.accesses.last() is ElementAccessor - && fromPath == (fact.variable + ElementAccessor) - ) { - val newTaint = fact.copy(variable = toPath) - return setOf(fact, newTaint) - } - - val tail = fact.variable - fromPath - if (tail != null) { - // Both 'from' and 'to' are tainted now: - val newPath = toPath + tail - val newTaint = fact.copy(variable = newPath) - return setOf(fact, newTaint) - } - } - - return buildSet { - if (from is JcNullConstant) { - add(Tainted(toPath, TaintMark.NULLNESS)) - } - - if (fact.variable.startsWith(toPath)) { - // 'to' was (sub-)tainted, but it is now overridden by 'from': - return@buildSet - } else { - // Neither 'from' nor 'to' are tainted: - add(fact) - } - } - } - - private fun transmitTaintNormal( - fact: Tainted, - inst: Statement, - ): List { - // Pass-through: - return listOf(fact) - } - - private fun generates( - inst: Statement, - ): Collection = buildList { - if (inst is CommonAssignInst) { - val toPath = inst.lhv.toPath() - val from = inst.rhv - if (from is JcNullConstant || (from is JcCallExpr && from.method.method.isNullable == true)) { - add(Tainted(toPath, TaintMark.NULLNESS)) - } else if (from is JcNewArrayExpr && (from.type as JcArrayType).elementType.nullable != false) { - val accessors = List((from.type as JcArrayType).dimensions) { ElementAccessor } - val path = toPath + accessors - add(Tainted(path, TaintMark.NULLNESS)) - } - } - } - - private val JcIfInst.pathComparedWithNull: AccessPath? - get() { - val expr = condition - return if (expr.rhv is JcNullConstant) { - expr.lhv.toPathOrNull() - } else if (expr.lhv is JcNullConstant) { - expr.rhv.toPathOrNull() - } else { - null - } - } - - override fun obtainSequentFlowFunction( - current: Statement, - next: Statement, - ) = FlowFunction { fact -> - if (fact is Tainted && fact.mark == TaintMark.NULLNESS) { - if (fact.variable.isDereferencedAt(current)) { - return@FlowFunction emptySet() - } - } - - if (current is JcIfInst) { - check(next is JcInst) - val nextIsTrueBranch = next.location.index == current.trueBranch.index - val pathComparedWithNull = current.pathComparedWithNull - if (fact == TaintZeroFact) { - if (pathComparedWithNull != null) { - if ((current.condition is JcEqExpr && nextIsTrueBranch) || - (current.condition is JcNeqExpr && !nextIsTrueBranch) - ) { - // This is a hack: instructions like `return null` in branch of next will be considered only if - // the fact holds (otherwise we could not get there) - // Note the absence of 'Zero' here! - return@FlowFunction listOf(Tainted(pathComparedWithNull, TaintMark.NULLNESS)) - } - } - } else if (fact is Tainted && fact.mark == TaintMark.NULLNESS) { - val expr = current.condition - if (pathComparedWithNull != fact.variable) { - return@FlowFunction listOf(fact) - } - if ((expr is JcEqExpr && nextIsTrueBranch) || (expr is JcNeqExpr && !nextIsTrueBranch)) { - // comparedPath is null in this branch - return@FlowFunction listOf(TaintZeroFact) - } else { - return@FlowFunction emptyList() - } - } - } - - if (fact is TaintZeroFact) { - return@FlowFunction listOf(TaintZeroFact) + generates(current) - } - check(fact is Tainted) - - if (current is JcAssignInst) { - transmitTaintAssign(fact, from = current.rhv, to = current.lhv) - } else { - transmitTaintNormal(fact, current) - } - } - - private fun transmitTaint( - fact: Tainted, - at: Statement, - from: CommonValue, - to: CommonValue, - ): Collection = buildSet { - if (fact.mark == TaintMark.NULLNESS) { - if (fact.variable.isDereferencedAt(at)) { - return@buildSet - } - } - - val fromPath = from.toPath() - val toPath = to.toPath() - - val tail = (fact.variable - fromPath) ?: return@buildSet - val newPath = toPath + tail - val newTaint = fact.copy(variable = newPath) - add(newTaint) - } - - private fun transmitTaintArgumentActualToFormal( - fact: Tainted, - at: Statement, - from: CommonValue, // actual - to: CommonValue, // formal - ): Collection = transmitTaint(fact, at, from, to) - - private fun transmitTaintArgumentFormalToActual( - fact: Tainted, - at: Statement, - from: CommonValue, // formal - to: CommonValue, // actual - ): Collection = transmitTaint(fact, at, from, to) - - private fun transmitTaintInstanceToThis( - fact: Tainted, - at: Statement, - from: CommonValue, // instance - to: CommonThis, // this - ): Collection = transmitTaint(fact, at, from, to) - - private fun transmitTaintThisToInstance( - fact: Tainted, - at: Statement, - from: CommonThis, // this - to: CommonValue, // instance - ): Collection = transmitTaint(fact, at, from, to) - - private fun transmitTaintReturn( - fact: Tainted, - at: Statement, - from: CommonValue, - to: CommonValue, - ): Collection = transmitTaint(fact, at, from, to) - - override fun obtainCallToReturnSiteFlowFunction( - callStatement: Statement, - returnSite: Statement, // FIXME: unused? - ) = FlowFunction { fact -> - if (fact is Tainted && fact.mark == TaintMark.NULLNESS) { - if (fact.variable.isDereferencedAt(callStatement)) { - return@FlowFunction emptySet() - } - } - - val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - - val callee = callExpr.callee - - // FIXME: handle taint pass-through on invokedynamic-based String concatenation: - if (fact is Tainted - && callExpr is JcDynamicCallExpr - && (callee as JcMethod).enclosingClass.name == "java.lang.invoke.StringConcatFactory" - && callStatement is JcAssignInst - ) { - for (arg in callExpr.args) { - if (arg.toPath() == fact.variable) { - return@FlowFunction setOf( - fact, - fact.copy(variable = callStatement.lhv.toPath()) - ) - } - } - return@FlowFunction setOf(fact) - } - - val config = taintConfigurationFeature?.let { feature -> - if (callee is JcMethod) { - logger.trace { "Extracting config for $callee" } - feature.getConfigForMethod(callee) - } else { - error("Cannot extract config for $callee") - } - } - - if (fact == TaintZeroFact) { - return@FlowFunction buildSet { - add(TaintZeroFact) - - if (callStatement is JcAssignInst) { - val toPath = callStatement.lhv.toPath() - val from = callStatement.rhv - if (from is JcNullConstant || (from is JcCallExpr && from.method.method.isNullable == true)) { - add(Tainted(toPath, TaintMark.NULLNESS)) - } else if (from is JcNewArrayExpr && (from.type as JcArrayType).elementType.nullable != false) { - val size = (from.type as JcArrayType).dimensions - val accessors = List(size) { ElementAccessor } - val path = toPath + accessors - add(Tainted(path, TaintMark.NULLNESS)) - } - } - - if (config != null) { - val conditionEvaluator = BasicConditionEvaluator( - CallPositionToValueResolver(callStatement) - ) - val actionEvaluator = TaintActionEvaluator( - CallPositionToAccessPathResolver(callStatement) - ) - - // Handle MethodSource config items: - for (item in config.filterIsInstance()) { - if (item.condition.accept(conditionEvaluator)) { - for (action in item.actionsAfter) { - val result = when (action) { - is AssignMark -> actionEvaluator.evaluate(action) - else -> error("$action is not supported for $item") - } - result.onSome { - addAll(it) - } - } - } - } - } - } - } - check(fact is Tainted) - - if (config != null) { - // FIXME: adhoc - if (callee is JcMethod - && callee.enclosingClass.name == "java.lang.StringBuilder" - && callee.name == "append" - ) { - // Skip rules for StringBuilder::append in NPE analysis. - } else { - val facts = mutableSetOf() - val conditionEvaluator = FactAwareConditionEvaluator( - fact, CallPositionToValueResolver(callStatement) - ) - val actionEvaluator = TaintActionEvaluator( - CallPositionToAccessPathResolver(callStatement) - ) - var defaultBehavior = true - - // Handle PassThrough config items: - for (item in config.filterIsInstance()) { - if (item.condition.accept(conditionEvaluator)) { - for (action in item.actionsAfter) { - val result = when (action) { - is CopyMark -> actionEvaluator.evaluate(action, fact) - is CopyAllMarks -> actionEvaluator.evaluate(action, fact) - is RemoveMark -> actionEvaluator.evaluate(action, fact) - is RemoveAllMarks -> actionEvaluator.evaluate(action, fact) - else -> error("$action is not supported for $item") - } - result.onSome { - facts += it - defaultBehavior = false - } - } - } - } - - // Handle Cleaner config items: - for (item in config.filterIsInstance()) { - if (item.condition.accept(conditionEvaluator)) { - for (action in item.actionsAfter) { - val result = when (action) { - is RemoveMark -> actionEvaluator.evaluate(action, fact) - is RemoveAllMarks -> actionEvaluator.evaluate(action, fact) - else -> error("$action is not supported for $item") - } - result.onSome { - facts += it - defaultBehavior = false - } - } - } - } - - if (!defaultBehavior) { - if (facts.size > 0) { - logger.trace { "Got ${facts.size} facts from config for $callee: $facts" } - } - return@FlowFunction facts - } else { - // Fall back to the default behavior, as if there were no config at all. - } - } - } - - // FIXME: adhoc for constructors: - if (callee.isConstructor) { - return@FlowFunction listOf(fact) - } - - // TODO: CONSIDER REFACTORING THIS - // Default behavior for "analyzable" method calls is to remove ("temporarily") - // all the marks from the 'instance' and arguments, in order to allow them "pass through" - // the callee (when it is going to be analyzed), i.e. through "call-to-start" and - // "exit-to-return" flow functions. - // When we know that we are NOT going to analyze the callee, we do NOT need - // to remove any marks from 'instance' and arguments. - // Currently, "analyzability" of the callee depends on the fact that the callee - // is "accessible" through the JcApplicationGraph::callees(). - if (callee in graph.callees(callStatement)) { - - if (fact.variable.isStatic) { - return@FlowFunction emptyList() - } - - for (actual in callExpr.args) { - // Possibly tainted actual parameter: - if (fact.variable.startsWith(actual.toPathOrNull())) { - return@FlowFunction emptyList() // Will be handled by summary edge - } - } - - if (callExpr is JcInstanceCallExpr) { - // Possibly tainted instance: - if (fact.variable.startsWith(callExpr.instance.toPathOrNull())) { - return@FlowFunction emptyList() // Will be handled by summary edge - } - } - - } - - if (callStatement is JcAssignInst) { - // Possibly tainted lhv: - if (fact.variable.startsWith(callStatement.lhv.toPathOrNull())) { - return@FlowFunction emptyList() // Overridden by rhv - } - } - - // The "most default" behaviour is encapsulated here: - transmitTaintNormal(fact, callStatement) - } - - override fun obtainCallToStartFlowFunction( - callStatement: Statement, - calleeStart: Statement, - ) = FlowFunction { fact -> - val callee = graph.methodOf(calleeStart) - - if (fact == TaintZeroFact) { - return@FlowFunction obtainPossibleStartFactsBasic(callee) - } - check(fact is Tainted) - - val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - - buildSet { - // Transmit facts on arguments (from 'actual' to 'formal'): - val actualParams = callExpr.args - val formalParams = getArgumentsOf(callee) - for ((formal, actual) in formalParams.zip(actualParams)) { - addAll( - transmitTaintArgumentActualToFormal( - fact = fact, - at = callStatement, - from = actual, - to = formal - ) - ) - } - - // Transmit facts on instance (from 'instance' to 'this'): - if (callExpr is JcInstanceCallExpr) { - addAll( - transmitTaintInstanceToThis( - fact = fact, - at = callStatement, - from = callExpr.instance, - to = callee.thisInstance - ) - ) - } - - // Transmit facts on static values: - if (fact.variable.isStatic) { - add(fact) - } - } - } - - override fun obtainExitToReturnSiteFlowFunction( - callStatement: Statement, - returnSite: Statement, // unused - exitStatement: Statement, - ) = FlowFunction { fact -> - // TODO: do we even need to return non-empty list for zero fact here? - if (fact == TaintZeroFact) { - // return@FlowFunction listOf(Zero) - return@FlowFunction buildSet { - add(TaintZeroFact) - if (exitStatement is JcReturnInst && callStatement is JcAssignInst) { - // Note: returnValue can be null here in some weird cases, e.g. in lambda. - exitStatement.returnValue?.let { returnValue -> - if (returnValue is JcNullConstant) { - val toPath = callStatement.lhv.toPath() - add(Tainted(toPath, TaintMark.NULLNESS)) - } - } - } - } - } - check(fact is Tainted) - - val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - val callee = graph.methodOf(exitStatement) - - buildSet { - // Transmit facts on arguments (from 'formal' back to 'actual'), if they are passed by-ref: - if (fact.variable.isOnHeap) { - val actualParams = callExpr.args - val formalParams = getArgumentsOf(callee) - for ((formal, actual) in formalParams.zip(actualParams)) { - addAll( - transmitTaintArgumentFormalToActual( - fact = fact, - at = callStatement, - from = formal, - to = actual - ) - ) - } - } - - // Transmit facts on instance (from 'this' to 'instance'): - if (callExpr is JcInstanceCallExpr) { - addAll( - transmitTaintThisToInstance( - fact = fact, - at = callStatement, - from = callee.thisInstance, - to = callExpr.instance - ) - ) - } - - // Transmit facts on static values: - if (fact.variable.isStatic) { - add(fact) - } - - // Transmit facts on return value (from 'returnValue' to 'lhv'): - if (exitStatement is JcReturnInst && callStatement is JcAssignInst) { - // Note: returnValue can be null here in some weird cases, e.g. in lambda. - exitStatement.returnValue?.let { returnValue -> - addAll( - transmitTaintReturn( - fact = fact, - at = callStatement, - from = returnValue, - to = callStatement.lhv - ) - ) - } - } - } - } -} - -// TODO: class BackwardNpeFlowFunctions diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeManager.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeManager.kt deleted file mode 100644 index a9e52776d..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeManager.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.npe - -import org.jacodb.analysis.ifds.UniRunner -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.ifds.UnitType -import org.jacodb.analysis.ifds.UnknownUnit -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.taint.TaintRunner -import org.jacodb.analysis.taint.TaintZeroFact -import org.jacodb.analysis.util.Traits -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonInst - -private val logger = mu.KotlinLogging.logger {} - -context(Traits) -class NpeManager( - graph: ApplicationGraph, - unitResolver: UnitResolver, -) : TaintManager(graph, unitResolver, useBidiRunner = false) - where Method : CommonMethod, - Statement : CommonInst { - - override fun newRunner( - unit: UnitType, - ): TaintRunner { - check(unit !in runnerForUnit) { "Runner for $unit already exists" } - - val analyzer = NpeAnalyzer(graph) - val runner = UniRunner( - graph = graph, - analyzer = analyzer, - manager = this@NpeManager, - unitResolver = unitResolver, - unit = unit, - zeroFact = TaintZeroFact - ) - - runnerForUnit[unit] = runner - return runner - } - - override fun addStart(method: Method) { - logger.info { "Adding start method: $method" } - val unit = unitResolver.resolve(method) - if (unit == UnknownUnit) return - methodsForUnit.getOrPut(unit) { hashSetOf() }.add(method) - // Note: DO NOT add deps here! - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/Utils.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/Utils.kt deleted file mode 100644 index 05c07efac..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/Utils.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.npe - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.minus -import org.jacodb.analysis.util.Traits -import org.jacodb.analysis.util.startsWith -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.cfg.CommonExpr -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.jvm.cfg.JcInstanceCallExpr -import org.jacodb.api.jvm.cfg.JcLengthExpr - -context(Traits) -internal fun AccessPath?.isDereferencedAt(expr: CommonExpr): Boolean { - if (this == null) { - return false - } - - if (expr is JcInstanceCallExpr) { - val instancePath = expr.instance.toPathOrNull() - if (instancePath.startsWith(this)) { - return true - } - } - - if (expr is JcLengthExpr) { - val arrayPath = expr.array.toPathOrNull() - if (arrayPath.startsWith(this)) { - return true - } - } - - return expr - .getValues() - .mapNotNull { it.toPathOrNull() } - .any { (it - this)?.isNotEmpty() == true } -} - -context(Traits) -internal fun AccessPath?.isDereferencedAt(inst: CommonInst): Boolean { - if (this == null) return false - return inst.getOperands().any { isDereferencedAt(it) } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/Sarif.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/Sarif.kt deleted file mode 100644 index 0746983d4..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/Sarif.kt +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.sarif - -import io.github.detekt.sarif4k.ArtifactLocation -import io.github.detekt.sarif4k.CodeFlow -import io.github.detekt.sarif4k.Location -import io.github.detekt.sarif4k.LogicalLocation -import io.github.detekt.sarif4k.Message -import io.github.detekt.sarif4k.MultiformatMessageString -import io.github.detekt.sarif4k.PhysicalLocation -import io.github.detekt.sarif4k.Region -import io.github.detekt.sarif4k.Result -import io.github.detekt.sarif4k.Run -import io.github.detekt.sarif4k.SarifSchema210 -import io.github.detekt.sarif4k.ThreadFlow -import io.github.detekt.sarif4k.ThreadFlowLocation -import io.github.detekt.sarif4k.Tool -import io.github.detekt.sarif4k.ToolComponent -import io.github.detekt.sarif4k.Version -import org.jacodb.analysis.ifds.Vertex -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.jvm.cfg.JcInst - -private const val SARIF_SCHEMA = - "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json" -private const val JACODB_INFORMATION_URI = - "https://github.com/UnitTestBot/jacodb/blob/develop/jacodb-analysis/README.md" -private const val DEFAULT_PATH_COUNT = 3 - -fun sarifReportFromVulnerabilities( - vulnerabilities: List>, - maxPathsCount: Int = DEFAULT_PATH_COUNT, - isDeduplicate: Boolean = true, - sourceFileResolver: SourceFileResolver = SourceFileResolver { null }, -): SarifSchema210 { - return SarifSchema210( - schema = SARIF_SCHEMA, - version = Version.The210, - runs = listOf( - Run( - tool = Tool( - driver = ToolComponent( - name = "jacodb-analysis", - organization = "UnitTestBot", - version = "1.4.5", - informationURI = JACODB_INFORMATION_URI, - ) - ), - results = vulnerabilities.map { instance -> - Result( - ruleID = instance.description.ruleId, - message = Message( - text = instance.description.message - ), - level = instance.description.level, - locations = listOfNotNull( - instToSarifLocation( - instance.traceGraph.sink.statement, - sourceFileResolver - ) - ), - codeFlows = instance.traceGraph - .getAllTraces() - .take(maxPathsCount) - .map { traceToSarifCodeFlow(it, sourceFileResolver, isDeduplicate) } - .toList(), - ) - } - ) - ) - ) -} - -private fun instToSarifLocation( - inst: Statement, - sourceFileResolver: SourceFileResolver, -): Location? { - val sourceLocation = sourceFileResolver.resolve(inst) ?: return null - return Location( - physicalLocation = PhysicalLocation( - artifactLocation = ArtifactLocation( - uri = sourceLocation - ), - region = Region( - startLine = if (inst is JcInst) inst.location.lineNumber.toLong() else null, - ) - ), - logicalLocations = listOf( - LogicalLocation( - fullyQualifiedName = if (inst is JcInst) { - val method = inst.location.method - "${method.enclosingClass.name}#${method.name}" - } else { - null - } - ) - ) - ) -} - -private fun traceToSarifCodeFlow( - trace: List>, - sourceFileResolver: SourceFileResolver, - isDeduplicate: Boolean = true, -): CodeFlow { - return CodeFlow( - threadFlows = listOf( - ThreadFlow( - locations = trace.map { - ThreadFlowLocation( - location = instToSarifLocation(it.statement, sourceFileResolver), - state = mapOf( - "fact" to MultiformatMessageString( - text = it.fact.toString() - ) - ) - ) - }.let { - if (isDeduplicate) it.deduplicate() else it - } - ) - ) - ) -} - -private fun List.deduplicate(): List { - if (isEmpty()) return emptyList() - - return listOf(first()) + zipWithNext { a, b -> - val aLine = a.location?.physicalLocation?.region?.startLine - val bLine = b.location?.physicalLocation?.region?.startLine - if (aLine != bLine) { - b - } else { - null - } - }.filterNotNull() -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/SourceFileResolver.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/SourceFileResolver.kt deleted file mode 100644 index 089b97784..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/SourceFileResolver.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.sarif - -import org.jacodb.api.common.cfg.CommonInst - -fun interface SourceFileResolver { - fun resolve(inst: Statement): String? -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/Vulnerability.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/Vulnerability.kt deleted file mode 100644 index 576f4b0f4..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/Vulnerability.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.sarif - -import io.github.detekt.sarif4k.Level -import org.jacodb.analysis.ifds.TraceGraph -import org.jacodb.api.common.cfg.CommonInst - -data class VulnerabilityInstance( - val traceGraph: TraceGraph, - val description: VulnerabilityDescription, -) - -data class VulnerabilityDescription( - val ruleId: String?, - val message: String?, - val level: Level = Level.Warning, -) diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/Sarif.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/Sarif.kt deleted file mode 100644 index 97a7541c3..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/Sarif.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.taint - -import org.jacodb.analysis.ifds.TraceGraph -import org.jacodb.analysis.sarif.VulnerabilityDescription -import org.jacodb.analysis.sarif.VulnerabilityInstance -import org.jacodb.api.common.cfg.CommonInst - -fun TaintVulnerability.toSarif( - graph: TraceGraph, -): VulnerabilityInstance = - VulnerabilityInstance( - graph, - VulnerabilityDescription( - ruleId = null, - message = rule?.ruleNote - ) - ) diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalysisOptions.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalysisOptions.kt deleted file mode 100644 index 61ce97425..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalysisOptions.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.taint - -object TaintAnalysisOptions { - var UNTRUSTED_LOOP_BOUND_SINK = false - var UNTRUSTED_ARRAY_SIZE_SINK = false - var UNTRUSTED_INDEX_ARRAY_ACCESS_SINK = false -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt deleted file mode 100644 index 675c9c2a1..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.taint - -import org.jacodb.analysis.config.CallPositionToValueResolver -import org.jacodb.analysis.config.FactAwareConditionEvaluator -import org.jacodb.analysis.ifds.Analyzer -import org.jacodb.analysis.ifds.Edge -import org.jacodb.analysis.ifds.Reason -import org.jacodb.analysis.util.Traits -import org.jacodb.analysis.util.toPath -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.jvm.cfg.JcIfInst -import org.jacodb.impl.cfg.util.loops -import org.jacodb.ets.base.EtsArrayAccess -import org.jacodb.ets.base.EtsAssignStmt -import org.jacodb.ets.base.EtsIfStmt -import org.jacodb.ets.base.EtsNewArrayExpr -import org.jacodb.ets.base.EtsStmt -import org.jacodb.ets.graph.loops -import org.jacodb.ets.utils.getOperands -import org.jacodb.panda.staticvm.utils.loops -import org.jacodb.taint.configuration.TaintConfigurationItem -import org.jacodb.taint.configuration.TaintMethodSink -import org.jacodb.panda.staticvm.cfg.PandaIfInst as StaticPandaIfInst - -private val logger = mu.KotlinLogging.logger {} - -context(Traits) -class TaintAnalyzer( - private val graph: ApplicationGraph, - private val getConfigForMethod: (ForwardTaintFlowFunctions.(Method) -> List?)? = null, -) : Analyzer, Method, Statement> - where Method : CommonMethod, - Statement : CommonInst { - - override val flowFunctions: ForwardTaintFlowFunctions by lazy { - if (getConfigForMethod != null) { - ForwardTaintFlowFunctions(graph, getConfigForMethod) - } else { - ForwardTaintFlowFunctions(graph) - } - } - - private fun isExitPoint(statement: Statement): Boolean { - return statement in graph.exitPoints(graph.methodOf(statement)) - } - - override fun handleNewEdge( - edge: TaintEdge, - ): List> = buildList { - if (isExitPoint(edge.to.statement)) { - add(NewSummaryEdge(edge)) - } - - run { - val callExpr = edge.to.statement.getCallExpr() ?: return@run - - val callee = callExpr.callee - - val config = with(flowFunctions) { getConfigForMethod(callee) } ?: return@run - - // TODO: not always we want to skip sinks on Zero facts. - // Some rules might have ConstantTrue or just true (when evaluated with Zero fact) condition. - if (edge.to.fact !is Tainted) { - return@run - } - - // Determine whether 'edge.to' is a sink via config: - val conditionEvaluator = FactAwareConditionEvaluator( - edge.to.fact, - CallPositionToValueResolver(edge.to.statement), - ) - for (item in config.filterIsInstance()) { - if (item.condition.accept(conditionEvaluator)) { - val message = item.ruleNote - val vulnerability = TaintVulnerability(message, sink = edge.to, rule = item) - logger.info { - "Found sink=${vulnerability.sink} in ${vulnerability.method} on $item" - } - add(NewVulnerability(vulnerability)) - } - } - } - - if (TaintAnalysisOptions.UNTRUSTED_LOOP_BOUND_SINK) { - val statement = edge.to.statement - val fact = edge.to.fact - if (fact is Tainted && fact.mark.name == "UNTRUSTED") { - if (statement is JcIfInst) { - val loops = statement.location.method.flowGraph().loops - val loopHeads = loops.map { it.head } - if (statement in loopHeads) { - for (s in statement.condition.operands) { - val p = s.toPath() - if (p == fact.variable) { - val message = "Untrusted loop bound" - val vulnerability = TaintVulnerability(message, sink = edge.to) - add(NewVulnerability(vulnerability)) - } - } - } - } else if (statement is StaticPandaIfInst) { - val loops = statement.location.method.flowGraph().loops - if (loops.any { statement in it.instructions }) { - for (s in statement.condition.operands) { - val p = s.toPath() - if (p == fact.variable) { - val message = "Untrusted loop bound" - val vulnerability = TaintVulnerability(message, sink = edge.to) - add(NewVulnerability(vulnerability)) - } - } - } - } else if (statement is EtsIfStmt) { - val pandaGraph = statement.location.method.flowGraph() - val loops = pandaGraph.loops - if (loops.any { statement in it.instructions }) { - for (s in statement.condition.getOperands()) { - val p = s.toPath() - if (p == fact.variable) { - val message = "Untrusted loop bound" - val vulnerability = TaintVulnerability(message, sink = edge.to) - add(NewVulnerability(vulnerability)) - } - } - } - } - } - } - if (TaintAnalysisOptions.UNTRUSTED_ARRAY_SIZE_SINK) { - val statement = edge.to.statement - val fact = edge.to.fact - if (fact is Tainted && fact.mark.name == "UNTRUSTED") { - if (statement is EtsAssignStmt) { - val expr = statement.rhv - if (expr is EtsNewArrayExpr) { - val arg = expr.size - if (arg.toPathOrNull() == fact.variable) { - val message = "Untrusted array size" - val vulnerability = TaintVulnerability(message, sink = edge.to) - add(NewVulnerability(vulnerability)) - } - } - } - } - } - if (TaintAnalysisOptions.UNTRUSTED_INDEX_ARRAY_ACCESS_SINK) { - val statement = edge.to.statement - val fact = edge.to.fact - if (fact is Tainted && fact.mark.name == "UNTRUSTED") { - if (statement is EtsStmt) { - for (op in statement.getOperands()) { - if (op is EtsArrayAccess) { - val arg = op.index - if (arg.toPathOrNull() == fact.variable) { - val message = "Untrusted index for access array" - val vulnerability = TaintVulnerability(message, sink = edge.to) - add(NewVulnerability(vulnerability)) - } - } - } - } - } - } - } - - override fun handleCrossUnitCall( - caller: TaintVertex, - callee: TaintVertex, - ): List> = buildList { - add(EdgeForOtherRunner(TaintEdge(callee, callee), Reason.CrossUnitCall(caller))) - } -} - -context(Traits) -class BackwardTaintAnalyzer( - private val graph: ApplicationGraph, -) : Analyzer, Method, Statement> - where Method : CommonMethod, - Statement : CommonInst { - - override val flowFunctions: BackwardTaintFlowFunctions by lazy { - BackwardTaintFlowFunctions(graph) - } - - private fun isExitPoint(statement: Statement): Boolean { - return statement in graph.exitPoints(graph.methodOf(statement)) - } - - override fun handleNewEdge( - edge: TaintEdge, - ): List> = buildList { - if (isExitPoint(edge.to.statement)) { - add(EdgeForOtherRunner(Edge(edge.to, edge.to), reason = Reason.External)) - } - } - - override fun handleCrossUnitCall( - caller: TaintVertex, - callee: TaintVertex, - ): List> { - return emptyList() - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintBidiRunner.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintBidiRunner.kt deleted file mode 100644 index f21a41da2..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintBidiRunner.kt +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.taint - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.CoroutineStart -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.launch -import org.jacodb.analysis.ifds.ControlEvent -import org.jacodb.analysis.ifds.Edge -import org.jacodb.analysis.ifds.IfdsResult -import org.jacodb.analysis.ifds.Manager -import org.jacodb.analysis.ifds.QueueEmptinessChanged -import org.jacodb.analysis.ifds.Reason -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.ifds.UnitType -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonInst - -class TaintBidiRunner( - val manager: TaintManager, - override val graph: ApplicationGraph, - val unitResolver: UnitResolver, - override val unit: UnitType, - newForwardRunner: (Manager, Method, Statement>) -> TaintRunner, - newBackwardRunner: (Manager, Method, Statement>) -> TaintRunner, -) : TaintRunner - where Method : CommonMethod, - Statement : CommonInst { - - @Volatile - private var forwardQueueIsEmpty: Boolean = false - - @Volatile - private var backwardQueueIsEmpty: Boolean = false - - private val forwardManager: Manager, Method, Statement> = - object : Manager, Method, Statement> { - override fun handleEvent(event: TaintEvent) { - when (event) { - is EdgeForOtherRunner -> { - val m = graph.methodOf(event.edge.from.statement) - if (unitResolver.resolve(m) == unit) { - // Submit new edge directly to the backward runner: - backwardRunner.submitNewEdge(event.edge, event.reason) - } else { - // Submit new edge via the manager: - manager.handleEvent(event) - } - } - - else -> manager.handleEvent(event) - } - } - - override fun handleControlEvent(event: ControlEvent) { - when (event) { - is QueueEmptinessChanged -> { - forwardQueueIsEmpty = event.isEmpty - val newEvent = QueueEmptinessChanged(event.runner, forwardQueueIsEmpty && backwardQueueIsEmpty) - manager.handleControlEvent(newEvent) - } - } - } - - override fun subscribeOnSummaryEdges( - method: Method, - scope: CoroutineScope, - handler: (TaintEdge) -> Unit, - ) { - manager.subscribeOnSummaryEdges(method, scope, handler) - } - } - - private val backwardManager: Manager, Method, Statement> = - object : Manager, Method, Statement> { - override fun handleEvent(event: TaintEvent) { - when (event) { - is EdgeForOtherRunner -> { - val m = graph.methodOf(event.edge.from.statement) - check(unitResolver.resolve(m) == unit) - // Submit new edge directly to the forward runner: - forwardRunner.submitNewEdge(event.edge, event.reason) - } - - else -> manager.handleEvent(event) - } - } - - override fun handleControlEvent(event: ControlEvent) { - when (event) { - is QueueEmptinessChanged -> { - backwardQueueIsEmpty = event.isEmpty - val newEvent = QueueEmptinessChanged(event.runner, forwardQueueIsEmpty && backwardQueueIsEmpty) - manager.handleControlEvent(newEvent) - } - } - } - - override fun subscribeOnSummaryEdges( - method: Method, - scope: CoroutineScope, - handler: (TaintEdge) -> Unit, - ) { - // TODO: ignore? - manager.subscribeOnSummaryEdges(method, scope, handler) - } - } - - val forwardRunner: TaintRunner = newForwardRunner(forwardManager) - val backwardRunner: TaintRunner = newBackwardRunner(backwardManager) - - init { - check(forwardRunner.unit == unit) - check(backwardRunner.unit == unit) - } - - override fun submitNewEdge( - edge: Edge, - reason: Reason, - ) { - forwardRunner.submitNewEdge(edge, reason) - } - - override suspend fun run(startMethods: List) = coroutineScope { - val backwardRunnerJob = launch(start = CoroutineStart.LAZY) { backwardRunner.run(startMethods) } - val forwardRunnerJob = launch(start = CoroutineStart.LAZY) { forwardRunner.run(startMethods) } - - backwardRunnerJob.start() - forwardRunnerJob.start() - - backwardRunnerJob.join() - forwardRunnerJob.join() - } - - override fun getIfdsResult(): IfdsResult { - return forwardRunner.getIfdsResult() - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt deleted file mode 100644 index 47c12fb44..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.taint - -import org.jacodb.analysis.ifds.Reason -import org.jacodb.api.common.cfg.CommonInst - -sealed interface TaintEvent - -data class NewSummaryEdge( - val edge: TaintEdge, -) : TaintEvent - -data class NewVulnerability( - val vulnerability: TaintVulnerability, -) : TaintEvent - -data class EdgeForOtherRunner( - val edge: TaintEdge, - val reason: Reason, -) : TaintEvent { - init { - // TODO: remove this check - check(edge.from == edge.to) { "Edge for another runner must be a loop" } - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintFacts.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintFacts.kt deleted file mode 100644 index 0fec8b62c..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintFacts.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.taint - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.taint.configuration.TaintMark - -sealed interface TaintDomainFact - -object TaintZeroFact : TaintDomainFact { - override fun toString(): String = "Zero" -} - -data class Tainted( - val variable: AccessPath, - val mark: TaintMark, -) : TaintDomainFact diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt deleted file mode 100644 index f028b72be..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt +++ /dev/null @@ -1,827 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.taint - -import org.jacodb.analysis.config.BasicConditionEvaluator -import org.jacodb.analysis.config.CallPositionToAccessPathResolver -import org.jacodb.analysis.config.CallPositionToValueResolver -import org.jacodb.analysis.config.EntryPointPositionToAccessPathResolver -import org.jacodb.analysis.config.EntryPointPositionToValueResolver -import org.jacodb.analysis.config.FactAwareConditionEvaluator -import org.jacodb.analysis.config.TaintActionEvaluator -import org.jacodb.analysis.ifds.ElementAccessor -import org.jacodb.analysis.ifds.FlowFunction -import org.jacodb.analysis.ifds.FlowFunctions -import org.jacodb.analysis.ifds.isOnHeap -import org.jacodb.analysis.ifds.isStatic -import org.jacodb.analysis.ifds.minus -import org.jacodb.analysis.ifds.onSome -import org.jacodb.analysis.util.Traits -import org.jacodb.analysis.util.startsWith -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonAssignInst -import org.jacodb.api.common.cfg.CommonExpr -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.common.cfg.CommonInstanceCallExpr -import org.jacodb.api.common.cfg.CommonReturnInst -import org.jacodb.api.common.cfg.CommonThis -import org.jacodb.api.common.cfg.CommonValue -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.analysis.JcApplicationGraph -import org.jacodb.api.jvm.cfg.JcAssignInst -import org.jacodb.api.jvm.cfg.JcBinaryExpr -import org.jacodb.api.jvm.cfg.JcCastExpr -import org.jacodb.api.jvm.cfg.JcDynamicCallExpr -import org.jacodb.api.jvm.cfg.JcNegExpr -import org.jacodb.ets.base.EtsBinaryExpr -import org.jacodb.ets.base.EtsCastExpr -import org.jacodb.ets.base.EtsUnaryExpr -import org.jacodb.ets.utils.getOperands -import org.jacodb.taint.configuration.AssignMark -import org.jacodb.taint.configuration.CopyAllMarks -import org.jacodb.taint.configuration.CopyMark -import org.jacodb.taint.configuration.RemoveAllMarks -import org.jacodb.taint.configuration.RemoveMark -import org.jacodb.taint.configuration.TaintCleaner -import org.jacodb.taint.configuration.TaintConfigurationFeature -import org.jacodb.taint.configuration.TaintConfigurationItem -import org.jacodb.taint.configuration.TaintEntryPointSource -import org.jacodb.taint.configuration.TaintMethodSource -import org.jacodb.taint.configuration.TaintPassThrough -import org.jacodb.panda.staticvm.cfg.PandaBinaryExpr as StaticPandaBinaryExpr -import org.jacodb.panda.staticvm.cfg.PandaCastExpr as StaticPandaCastExpr -import org.jacodb.panda.staticvm.cfg.PandaNegExpr as StaticPandaNegExpr -import org.jacodb.panda.staticvm.cfg.PandaNotExpr as StaticPandaNotExpr -import org.jacodb.panda.staticvm.cfg.PandaPhiExpr as StaticPandaPhiExpr -import org.jacodb.panda.staticvm.cfg.PandaPhiInst as StaticPandaPhiInst - -private val logger = mu.KotlinLogging.logger {} - -// TODO: replace with CommonMethod, with CommonInst -context(Traits) -class ForwardTaintFlowFunctions( - private val graph: ApplicationGraph, - val getConfigForMethod: ForwardTaintFlowFunctions.(Method) -> List? = { method -> - taintConfigurationFeature?.let { feature -> - if (method is JcMethod) { - logger.trace { "Extracting config for $method" } - feature.getConfigForMethod(method) - } else { - error("Cannot extract config for $method") - } - } - }, -) : FlowFunctions - where Method : CommonMethod, - Statement : CommonInst { - - // // TODO: inline - // private fun CommonExpr.toPathOrNull(): AccessPath? = traits.toPathOrNull(this) - // private fun CommonValue.toPath(): AccessPath = traits.toPath(this) - - private val taintConfigurationFeature: TaintConfigurationFeature? by lazy { - if (graph is JcApplicationGraph) { - graph.cp.features - ?.singleOrNull { it is TaintConfigurationFeature } - ?.let { it as TaintConfigurationFeature } - } else { - null - } - } - - override fun obtainPossibleStartFacts( - method: Method, - ): Collection = buildSet { - // Zero (reachability) fact always present at entrypoint: - add(TaintZeroFact) - - // Extract initial facts from the config: - val config = getConfigForMethod(method) - if (config != null) { - val conditionEvaluator = BasicConditionEvaluator( - EntryPointPositionToValueResolver(method) - ) - val actionEvaluator = TaintActionEvaluator( - EntryPointPositionToAccessPathResolver(method) - ) - - // Handle EntryPointSource config items: - for (item in config.filterIsInstance()) { - if (item.condition.accept(conditionEvaluator)) { - for (action in item.actionsAfter) { - val result = when (action) { - is AssignMark -> actionEvaluator.evaluate(action) - else -> error("$action is not supported for $item") - } - result.onSome { addAll(it) } - } - } - } - } - } - - private fun transmitTaintAssign( - fact: Tainted, - from: CommonExpr, - to: CommonValue, - ): Collection { - val toPath = to.toPath() - val fromPath = from.toPathOrNull() - - if (fromPath != null) { - // Adhoc taint array: - if (fromPath.accesses.isNotEmpty() - && fromPath.accesses.last() is ElementAccessor - && fromPath == (fact.variable + ElementAccessor) - ) { - val newTaint = fact.copy(variable = toPath) - return setOf(fact, newTaint) - } - - val tail = fact.variable - fromPath - if (tail != null) { - // Both 'from' and 'to' are tainted now: - val newPath = toPath + tail - val newTaint = fact.copy(variable = newPath) - return setOf(fact, newTaint) - } - } - - if (fact.variable.startsWith(toPath)) { - // 'to' was (sub-)tainted, but it is now overridden by 'from': - return emptySet() - } else { - // Neither 'from' nor 'to' are tainted: - return setOf(fact) - } - } - - private fun transmitTaintNormal( - fact: Tainted, - inst: Statement, - ): List { - // Pass-through: - return listOf(fact) - } - - override fun obtainSequentFlowFunction( - current: Statement, - next: Statement, - ) = FlowFunction { fact -> - if (fact is TaintZeroFact) { - return@FlowFunction listOf(TaintZeroFact) - } - check(fact is Tainted) - - if (current is CommonAssignInst) { - when (val rhv = current.rhv) { - is StaticPandaPhiExpr -> { - val facts: MutableSet = mutableSetOf() - for (input in rhv.inputs) { - facts += transmitTaintAssign(fact, from = input, to = current.lhv) - } - // For empty phi, pass-through: - val pass = transmitTaintNormal(fact, current) - facts + pass - } - - is JcBinaryExpr -> { - val facts: MutableSet = mutableSetOf() - facts += transmitTaintAssign(fact, from = rhv.lhv, to = current.lhv) - facts += transmitTaintAssign(fact, from = rhv.rhv, to = current.lhv) - facts - } - - is JcNegExpr -> { - transmitTaintAssign(fact, from = rhv.operand, to = current.lhv) - } - - is JcCastExpr -> { - transmitTaintAssign(fact, from = rhv.operand, to = current.lhv) - } - - is StaticPandaBinaryExpr -> { - val facts: MutableSet = mutableSetOf() - facts += transmitTaintAssign(fact, from = rhv.lhv, to = current.lhv) - facts += transmitTaintAssign(fact, from = rhv.rhv, to = current.lhv) - facts - } - - is EtsBinaryExpr -> { - val facts: MutableSet = mutableSetOf() - facts += transmitTaintAssign(fact, from = rhv.left, to = current.lhv) - facts += transmitTaintAssign(fact, from = rhv.right, to = current.lhv) - facts - } - - is StaticPandaNegExpr -> { - transmitTaintAssign(fact, from = rhv.arg, to = current.lhv) - } - - is EtsUnaryExpr -> { - transmitTaintAssign(fact, from = rhv.getOperands().first(), to = current.lhv) - } - - is StaticPandaNotExpr -> { - transmitTaintAssign(fact, from = rhv.arg, to = current.lhv) - } - - is StaticPandaCastExpr -> { - transmitTaintAssign(fact, from = rhv.arg, to = current.lhv) - } - - is EtsCastExpr -> { - transmitTaintAssign(fact, from = rhv.getOperands().first(), to = current.lhv) - } - - else -> { - transmitTaintAssign(fact, from = current.rhv, to = current.lhv) - } - } - } else if (current is StaticPandaPhiInst) { - val facts: MutableSet = mutableSetOf() - for (input in current.inputs) { - facts += transmitTaintAssign(fact, from = input, to = current.lhv) - } - // For empty phi, pass-through: - val pass = transmitTaintNormal(fact, current) - facts + pass - } else { - transmitTaintNormal(fact, current) - } - } - - private fun transmitTaint( - fact: Tainted, - from: CommonValue, - to: CommonValue, - ): Collection = buildSet { - val fromPath = from.toPath() - val toPath = to.toPath() - - val tail = (fact.variable - fromPath) ?: return@buildSet - val newPath = toPath + tail - val newTaint = fact.copy(variable = newPath) - add(newTaint) - } - - private fun transmitTaintArgumentActualToFormal( - fact: Tainted, - from: CommonValue, // actual - to: CommonValue, // formal - ): Collection = transmitTaint(fact, from, to) - - private fun transmitTaintArgumentFormalToActual( - fact: Tainted, - from: CommonValue, // formal - to: CommonValue, // actual - ): Collection = transmitTaint(fact, from, to) - - private fun transmitTaintInstanceToThis( - fact: Tainted, - from: CommonValue, // instance - to: CommonThis, // this - ): Collection = transmitTaint(fact, from, to) - - private fun transmitTaintThisToInstance( - fact: Tainted, - from: CommonThis, // this - to: CommonValue, // instance - ): Collection = transmitTaint(fact, from, to) - - private fun transmitTaintReturn( - fact: Tainted, - from: CommonValue, - to: CommonValue, - ): Collection = transmitTaint(fact, from, to) - - override fun obtainCallToReturnSiteFlowFunction( - callStatement: Statement, - returnSite: Statement, // FIXME: unused? - ) = FlowFunction { fact -> - val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - - val callee = callExpr.callee - - // FIXME: handle taint pass-through on invokedynamic-based String concatenation: - if (fact is Tainted - && callExpr is JcDynamicCallExpr - && (callee as JcMethod).enclosingClass.name == "java.lang.invoke.StringConcatFactory" - && callStatement is JcAssignInst - ) { - for (arg in callExpr.args) { - if (arg.toPath() == fact.variable) { - return@FlowFunction setOf( - fact, - fact.copy(variable = callStatement.lhv.toPath()) - ) - } - } - return@FlowFunction setOf(fact) - } - - val config = getConfigForMethod(callee) - - if (fact == TaintZeroFact) { - return@FlowFunction buildSet { - add(TaintZeroFact) - - if (config != null) { - val conditionEvaluator = BasicConditionEvaluator( - CallPositionToValueResolver(callStatement) - ) - val actionEvaluator = TaintActionEvaluator( - CallPositionToAccessPathResolver(callStatement) - ) - - // Handle MethodSource config items: - for (item in config.filterIsInstance()) { - if (item.condition.accept(conditionEvaluator)) { - for (action in item.actionsAfter) { - val result = when (action) { - is AssignMark -> actionEvaluator.evaluate(action) - else -> error("$action is not supported for $item") - } - result.onSome { addAll(it) } - } - } - } - } - } - } - check(fact is Tainted) - - if (config != null) { - val facts = mutableSetOf() - val conditionEvaluator = FactAwareConditionEvaluator( - fact, CallPositionToValueResolver(callStatement) - ) - val actionEvaluator = TaintActionEvaluator( - CallPositionToAccessPathResolver(callStatement) - ) - var defaultBehavior = true - - // Handle PassThrough config items: - for (item in config.filterIsInstance()) { - if (item.condition.accept(conditionEvaluator)) { - for (action in item.actionsAfter) { - val result = when (action) { - is CopyMark -> actionEvaluator.evaluate(action, fact) - is CopyAllMarks -> actionEvaluator.evaluate(action, fact) - is RemoveMark -> actionEvaluator.evaluate(action, fact) - is RemoveAllMarks -> actionEvaluator.evaluate(action, fact) - else -> error("$action is not supported for $item") - } - result.onSome { - facts += it - defaultBehavior = false - } - } - } - } - - // Handle Cleaner config items: - for (item in config.filterIsInstance()) { - if (item.condition.accept(conditionEvaluator)) { - for (action in item.actionsAfter) { - val result = when (action) { - is RemoveMark -> actionEvaluator.evaluate(action, fact) - is RemoveAllMarks -> actionEvaluator.evaluate(action, fact) - else -> error("$action is not supported for $item") - } - result.onSome { - facts += it - defaultBehavior = false - } - } - } - } - - if (!defaultBehavior) { - if (facts.size > 0) { - logger.trace { "Got ${facts.size} facts from config for $callee: $facts" } - } - return@FlowFunction facts - } else { - // Fall back to the default behavior, as if there were no config at all. - } - } - - // FIXME: adhoc for constructors: - if (callee.isConstructor) { - return@FlowFunction listOf(fact) - } - - // TODO: CONSIDER REFACTORING THIS - // Default behavior for "analyzable" method calls is to remove ("temporarily") - // all the marks from the 'instance' and arguments, in order to allow them "pass through" - // the callee (when it is going to be analyzed), i.e. through "call-to-start" and - // "exit-to-return" flow functions. - // When we know that we are NOT going to analyze the callee, we do NOT need - // to remove any marks from 'instance' and arguments. - // Currently, "analyzability" of the callee depends on the fact that the callee - // is "accessible" through the JcApplicationGraph::callees(). - if (callee in graph.callees(callStatement)) { - - if (fact.variable.isStatic) { - return@FlowFunction emptyList() - } - - for (actual in callExpr.args) { - // Possibly tainted actual parameter: - if (fact.variable.startsWith(actual.toPathOrNull())) { - return@FlowFunction emptyList() // Will be handled by summary edge - } - } - - if (callExpr is CommonInstanceCallExpr) { - // Possibly tainted instance: - if (fact.variable.startsWith(callExpr.instance.toPathOrNull())) { - return@FlowFunction emptyList() // Will be handled by summary edge - } - } - - } - - if (callStatement is CommonAssignInst) { - // Possibly tainted lhv: - if (fact.variable.startsWith(callStatement.lhv.toPathOrNull())) { - return@FlowFunction emptyList() // Overridden by rhv - } - } - - // The "most default" behaviour is encapsulated here: - transmitTaintNormal(fact, callStatement) - } - - override fun obtainCallToStartFlowFunction( - callStatement: Statement, - calleeStart: Statement, - ) = FlowFunction { fact -> - val callee = graph.methodOf(calleeStart) - - if (fact == TaintZeroFact) { - return@FlowFunction obtainPossibleStartFacts(callee) - } - check(fact is Tainted) - - val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - - buildSet { - // Transmit facts on arguments (from 'actual' to 'formal'): - val actualParams = callExpr.args - val formalParams = getArgumentsOf(callee) - for ((formal, actual) in formalParams.zip(actualParams)) { - addAll(transmitTaintArgumentActualToFormal(fact, from = actual, to = formal)) - } - - // Transmit facts on instance (from 'instance' to 'this'): - if (callExpr is CommonInstanceCallExpr) { - addAll( - transmitTaintInstanceToThis( - fact = fact, - from = callExpr.instance, - to = callee.thisInstance - ) - ) - } - - // Transmit facts on static values: - if (fact.variable.isStatic) { - add(fact) - } - } - } - - override fun obtainExitToReturnSiteFlowFunction( - callStatement: Statement, - returnSite: Statement, // unused - exitStatement: Statement, - ) = FlowFunction { fact -> - if (fact == TaintZeroFact) { - return@FlowFunction listOf(TaintZeroFact) - } - check(fact is Tainted) - - val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - val callee = graph.methodOf(exitStatement) - - buildSet { - // Transmit facts on arguments (from 'formal' back to 'actual'), if they are passed by-ref: - if (fact.variable.isOnHeap) { - val actualParams = callExpr.args - val formalParams = getArgumentsOf(callee) - for ((formal, actual) in formalParams.zip(actualParams)) { - addAll( - transmitTaintArgumentFormalToActual( - fact = fact, - from = formal, - to = actual - ) - ) - } - } - - // Transmit facts on instance (from 'this' to 'instance'): - if (callExpr is CommonInstanceCallExpr) { - addAll( - transmitTaintThisToInstance( - fact = fact, - from = callee.thisInstance, - to = callExpr.instance - ) - ) - } - - // Transmit facts on static values: - if (fact.variable.isStatic) { - add(fact) - } - - // Transmit facts on return value (from 'returnValue' to 'lhv'): - if (exitStatement is CommonReturnInst && callStatement is CommonAssignInst) { - // Note: returnValue can be null here in some weird cases, e.g. in lambda. - exitStatement.returnValue?.let { returnValue -> - addAll(transmitTaintReturn(fact, from = returnValue, to = callStatement.lhv)) - } - } - } - } -} - -context(Traits) -class BackwardTaintFlowFunctions( - private val graph: ApplicationGraph, -) : FlowFunctions - where Method : CommonMethod, - Statement : CommonInst { - - override fun obtainPossibleStartFacts( - method: Method, - ): Collection { - return listOf(TaintZeroFact) - } - - private fun transmitTaintBackwardAssign( - fact: Tainted, - from: CommonValue, - to: CommonExpr, - ): Collection { - val fromPath = from.toPath() - val toPath = to.toPathOrNull() - - if (toPath != null) { - val tail = fact.variable - fromPath - if (tail != null) { - // Both 'from' and 'to' are tainted now: - val newPath = toPath + tail - val newTaint = fact.copy(variable = newPath) - return setOf(fact, newTaint) - } - - if (fact.variable.startsWith(toPath)) { - // 'to' was (sub-)tainted, but it is now overridden by 'from': - return emptySet() - } - } - - // Pass-through: - return setOf(fact) - } - - private fun transmitTaintBackwardNormal( - fact: Tainted, - inst: Statement, - ): List { - // Pass-through: - return listOf(fact) - } - - override fun obtainSequentFlowFunction( - current: Statement, - next: Statement, - ) = FlowFunction { fact -> - if (fact is TaintZeroFact) { - return@FlowFunction listOf(TaintZeroFact) - } - check(fact is Tainted) - - if (current is CommonAssignInst) { - transmitTaintBackwardAssign(fact, from = current.lhv, to = current.rhv) - } else { - transmitTaintBackwardNormal(fact, current) - } - } - - private fun transmitTaint( - fact: Tainted, - from: CommonValue, - to: CommonValue, - ): Collection = buildSet { - val fromPath = from.toPath() - val toPath = to.toPath() - - val tail = (fact.variable - fromPath) ?: return@buildSet - val newPath = toPath + tail - val newTaint = fact.copy(variable = newPath) - add(newTaint) - } - - private fun transmitTaintArgumentActualToFormal( - fact: Tainted, - from: CommonValue, // actual - to: CommonValue, // formal - ): Collection = transmitTaint(fact, from, to) - - private fun transmitTaintArgumentFormalToActual( - fact: Tainted, - from: CommonValue, // formal - to: CommonValue, // actual - ): Collection = transmitTaint(fact, from, to) - - private fun transmitTaintInstanceToThis( - fact: Tainted, - from: CommonValue, // instance - to: CommonThis, // this - ): Collection = transmitTaint(fact, from, to) - - private fun transmitTaintThisToInstance( - fact: Tainted, - from: CommonThis, // this - to: CommonValue, // instance - ): Collection = transmitTaint(fact, from, to) - - private fun transmitTaintReturn( - fact: Tainted, - from: CommonValue, - to: CommonValue, - ): Collection = transmitTaint(fact, from, to) - - override fun obtainCallToReturnSiteFlowFunction( - callStatement: Statement, - returnSite: Statement, // FIXME: unused? - ) = FlowFunction { fact -> - // TODO: pass-through on invokedynamic-based String concatenation - - if (fact == TaintZeroFact) { - return@FlowFunction listOf(TaintZeroFact) - } - check(fact is Tainted) - - val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - val callee = callExpr.callee - - if (callee in graph.callees(callStatement)) { - - if (fact.variable.isStatic) { - return@FlowFunction emptyList() - } - - for (actual in callExpr.args) { - // Possibly tainted actual parameter: - if (fact.variable.startsWith(actual.toPathOrNull())) { - return@FlowFunction emptyList() // Will be handled by summary edge - } - } - - if (callExpr is CommonInstanceCallExpr) { - // Possibly tainted instance: - if (fact.variable.startsWith(callExpr.instance.toPathOrNull())) { - return@FlowFunction emptyList() // Will be handled by summary edge - } - } - - } - - if (callStatement is CommonAssignInst) { - // Possibly tainted rhv: - if (fact.variable.startsWith(callStatement.rhv.toPathOrNull())) { - return@FlowFunction emptyList() // Overridden by lhv - } - } - - // The "most default" behaviour is encapsulated here: - transmitTaintBackwardNormal(fact, callStatement) - } - - override fun obtainCallToStartFlowFunction( - callStatement: Statement, - calleeStart: Statement, - ) = FlowFunction { fact -> - val callee = graph.methodOf(calleeStart) - - if (fact == TaintZeroFact) { - return@FlowFunction obtainPossibleStartFacts(callee) - } - check(fact is Tainted) - - val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - - buildSet { - // Transmit facts on arguments (from 'actual' to 'formal'): - val actualParams = callExpr.args - val formalParams = getArgumentsOf(callee) - for ((formal, actual) in formalParams.zip(actualParams)) { - addAll(transmitTaintArgumentActualToFormal(fact, from = actual, to = formal)) - } - - // Transmit facts on instance (from 'instance' to 'this'): - if (callExpr is CommonInstanceCallExpr) { - addAll( - transmitTaintInstanceToThis( - fact = fact, - from = callExpr.instance, - to = callee.thisInstance - ) - ) - } - - // Transmit facts on static values: - if (fact.variable.isStatic) { - add(fact) - } - - // Transmit facts on return value (from 'returnValue' to 'lhv'): - if (calleeStart is CommonReturnInst && callStatement is CommonAssignInst) { - // Note: returnValue can be null here in some weird cases, e.g. in lambda. - calleeStart.returnValue?.let { returnValue -> - addAll( - transmitTaintReturn( - fact = fact, - from = callStatement.lhv, - to = returnValue - ) - ) - } - } - } - } - - override fun obtainExitToReturnSiteFlowFunction( - callStatement: Statement, - returnSite: Statement, - exitStatement: Statement, - ) = FlowFunction { fact -> - if (fact == TaintZeroFact) { - return@FlowFunction listOf(TaintZeroFact) - } - check(fact is Tainted) - - val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - val callee = graph.methodOf(exitStatement) - - buildSet { - // Transmit facts on arguments (from 'formal' back to 'actual'), if they are passed by-ref: - if (fact.variable.isOnHeap) { - val actualParams = callExpr.args - val formalParams = getArgumentsOf(callee) - for ((formal, actual) in formalParams.zip(actualParams)) { - addAll( - transmitTaintArgumentFormalToActual( - fact = fact, - from = formal, - to = actual - ) - ) - } - } - - // Transmit facts on instance (from 'this' to 'instance'): - if (callExpr is CommonInstanceCallExpr) { - addAll( - transmitTaintThisToInstance( - fact = fact, - from = callee.thisInstance, - to = callExpr.instance - ) - ) - } - - // Transmit facts on static values: - if (fact.variable.isStatic) { - add(fact) - } - } - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintManager.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintManager.kt deleted file mode 100644 index 641092696..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintManager.kt +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.taint - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.CoroutineStart -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.cancelAndJoin -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.isActive -import kotlinx.coroutines.joinAll -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.withTimeoutOrNull -import org.jacodb.analysis.graph.reversed -import org.jacodb.analysis.ifds.ControlEvent -import org.jacodb.analysis.ifds.IfdsResult -import org.jacodb.analysis.ifds.Manager -import org.jacodb.analysis.ifds.QueueEmptinessChanged -import org.jacodb.analysis.ifds.SummaryStorageImpl -import org.jacodb.analysis.ifds.TraceGraph -import org.jacodb.analysis.ifds.UniRunner -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.ifds.UnitType -import org.jacodb.analysis.ifds.UnknownUnit -import org.jacodb.analysis.ifds.Vertex -import org.jacodb.analysis.util.Traits -import org.jacodb.analysis.util.getPathEdges -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.taint.configuration.TaintConfigurationItem -import java.util.concurrent.ConcurrentHashMap -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds -import kotlin.time.DurationUnit -import kotlin.time.ExperimentalTime -import kotlin.time.TimeSource - -private val logger = mu.KotlinLogging.logger {} - -context(Traits) -open class TaintManager( - protected val graph: ApplicationGraph, - protected val unitResolver: UnitResolver, - private val useBidiRunner: Boolean = false, - private val getConfigForMethod: (ForwardTaintFlowFunctions.(Method) -> List?)? = null, -) : Manager, Method, Statement> - where Method : CommonMethod, - Statement : CommonInst { - - protected val methodsForUnit: MutableMap> = hashMapOf() - val runnerForUnit: MutableMap> = hashMapOf() - private val queueIsEmpty = ConcurrentHashMap() - - private val summaryEdgesStorage = SummaryStorageImpl>() - private val vulnerabilitiesStorage = SummaryStorageImpl>() - - private val stopRendezvous = Channel(Channel.RENDEZVOUS) - - protected open fun newRunner( - unit: UnitType, - ): TaintRunner { - // check(unit !in runnerForUnit) { "Runner for $unit already exists" } - if (unit in runnerForUnit) { - return runnerForUnit[unit]!! - } - - logger.debug { "Creating a new runner for $unit" } - val runner = if (useBidiRunner) { - TaintBidiRunner( - manager = this@TaintManager, - graph = graph, - unitResolver = unitResolver, - unit = unit, - { manager -> - val analyzer = TaintAnalyzer(graph, getConfigForMethod) - UniRunner( - manager = manager, - graph = graph, - analyzer = analyzer, - unitResolver = unitResolver, - unit = unit, - zeroFact = TaintZeroFact - ) - }, - { manager -> - val analyzer = BackwardTaintAnalyzer(graph) - UniRunner( - manager = manager, - graph = graph.reversed, - analyzer = analyzer, - unitResolver = unitResolver, - unit = unit, - zeroFact = TaintZeroFact - ) - } - ) - } else { - val analyzer = TaintAnalyzer(graph, getConfigForMethod) - UniRunner( - manager = this@TaintManager, - graph = graph, - analyzer = analyzer, - unitResolver = unitResolver, - unit = unit, - zeroFact = TaintZeroFact - ) - } - - runnerForUnit[unit] = runner - return runner - } - - private fun getAllCallees(method: Method): Set { - val result: MutableSet = hashSetOf() - for (inst in method.flowGraph().instructions) { - @Suppress("UNCHECKED_CAST") - result += graph.callees(inst as Statement) - } - return result - } - - protected open fun addStart(method: Method) { - logger.info { "Adding start method: $method" } - val unit = unitResolver.resolve(method) - if (unit == UnknownUnit) return - val isNew = methodsForUnit.getOrPut(unit) { hashSetOf() }.add(method) - if (isNew) { - for (dep in getAllCallees(method)) { - addStart(dep) - } - } - } - - @JvmName("analyze") // needed for Java interop because of inline class (Duration) - @OptIn(ExperimentalTime::class) - fun analyze( - startMethods: List, - timeout: Duration = 3600.seconds, - ): List> = runBlocking(Dispatchers.Default) { - val timeStart = TimeSource.Monotonic.markNow() - - // Add start methods: - for (method in startMethods) { - addStart(method) - } - - // Determine all units: - val allUnits = methodsForUnit.keys.toList() - logger.info { - "Starting analysis of ${ - methodsForUnit.values.sumOf { it.size } - } methods in ${allUnits.size} units" - } - - // Spawn runner jobs: - val allJobs = allUnits.map { unit -> - // Create the runner: - val runner = newRunner(unit) - - // Start the runner: - launch(start = CoroutineStart.LAZY) { - val methods = methodsForUnit[unit]!!.toList() - runner.run(methods) - } - } - - // Spawn progress job: - val progress = launch(Dispatchers.IO) { - while (isActive) { - delay(1.seconds) - logger.info { - "Progress: propagated ${ - runnerForUnit.values.sumOf { it.getPathEdges().size } - } path edges" - } - } - } - - // Spawn stopper job: - val stopper = launch(Dispatchers.IO) { - stopRendezvous.receive() - logger.info { "Stopping all runners..." } - allJobs.forEach { it.cancel() } - } - - // Start all runner jobs: - val timeStartJobs = TimeSource.Monotonic.markNow() - allJobs.forEach { it.start() } - - // Await all runners: - withTimeoutOrNull(timeout) { - allJobs.joinAll() - } ?: run { - logger.info { "Timeout!" } - allJobs.forEach { it.cancel() } - allJobs.joinAll() - } - progress.cancelAndJoin() - stopper.cancelAndJoin() - logger.info { - "All ${allJobs.size} jobs completed in %.1f s".format( - timeStartJobs.elapsedNow().toDouble(DurationUnit.SECONDS) - ) - } - - // Extract found vulnerabilities (sinks): - val foundVulnerabilities = vulnerabilitiesStorage.knownMethods - .flatMap { method -> - vulnerabilitiesStorage.getCurrentFacts(method) - } - if (logger.isDebugEnabled) { - logger.debug { "Total found ${foundVulnerabilities.size} vulnerabilities" } - for (vulnerability in foundVulnerabilities) { - logger.debug { "$vulnerability in ${vulnerability.method}" } - } - } - logger.info { "Total sinks: ${foundVulnerabilities.size}" } - logger.info { - "Total propagated ${ - runnerForUnit.values.sumOf { it.getPathEdges().size } - } path edges" - } - logger.info { - "Analysis done in %.1f s".format( - timeStart.elapsedNow().toDouble(DurationUnit.SECONDS) - ) - } - foundVulnerabilities - } - - override fun handleEvent(event: TaintEvent) { - when (event) { - is NewSummaryEdge -> { - summaryEdgesStorage.add(TaintSummaryEdge(event.edge)) - } - - is NewVulnerability -> { - vulnerabilitiesStorage.add(event.vulnerability) - } - - is EdgeForOtherRunner -> { - val method = graph.methodOf(event.edge.from.statement) - val unit = unitResolver.resolve(method) - val otherRunner = runnerForUnit[unit] ?: run { - // error("No runner for $unit") - logger.trace { "Ignoring event=$event for non-existing runner for unit=$unit" } - return - } - otherRunner.submitNewEdge(event.edge, event.reason) - } - } - } - - override fun handleControlEvent(event: ControlEvent) { - when (event) { - is QueueEmptinessChanged -> { - queueIsEmpty[event.runner.unit] = event.isEmpty - if (event.isEmpty) { - if (runnerForUnit.keys.all { queueIsEmpty[it] == true }) { - logger.debug { "All runners are empty" } - stopRendezvous.trySend(Unit).getOrNull() - } - } - } - } - } - - override fun subscribeOnSummaryEdges( - method: Method, - scope: CoroutineScope, - handler: (TaintEdge) -> Unit, - ) { - summaryEdgesStorage - .getFacts(method) - .onEach { handler(it.edge) } - .launchIn(scope) - } - - fun vulnerabilityTraceGraph( - vulnerability: TaintVulnerability, - ): TraceGraph { - @Suppress("UNCHECKED_CAST") - val result = getIfdsResultForMethod(vulnerability.method as Method) - val initialGraph = result.buildTraceGraph(vulnerability.sink) - val resultGraph = initialGraph.copy(unresolvedCrossUnitCalls = emptyMap()) - - val resolvedCrossUnitEdges = - hashSetOf, Vertex>>() - val unresolvedCrossUnitCalls = initialGraph.unresolvedCrossUnitCalls.entries.toMutableList() - while (unresolvedCrossUnitCalls.isNotEmpty()) { - val (caller, callees) = unresolvedCrossUnitCalls.removeLast() - - val unresolvedCallees = hashSetOf>() - for (callee in callees) { - if (resolvedCrossUnitEdges.add(caller to callee)) { - unresolvedCallees.add(callee) - } - } - - if (unresolvedCallees.isEmpty()) continue - - @Suppress("UNCHECKED_CAST") - val callerResult = getIfdsResultForMethod(caller.method as Method) - val callerGraph = callerResult.buildTraceGraph(caller) - resultGraph.mergeWithUpGraph(callerGraph, unresolvedCallees) - unresolvedCrossUnitCalls += callerGraph.unresolvedCrossUnitCalls.entries - } - - return resultGraph - } - - private fun getIfdsResultForMethod(method: Method): IfdsResult { - val unit = unitResolver.resolve(method) - val runner = runnerForUnit[unit] ?: error("No runner for $unit") - return runner.getIfdsResult() - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintSummaries.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintSummaries.kt deleted file mode 100644 index a97a03af8..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintSummaries.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.taint - -import org.jacodb.analysis.ifds.SummaryEdge -import org.jacodb.analysis.ifds.Vulnerability -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.taint.configuration.TaintMethodSink - -data class TaintSummaryEdge( - override val edge: TaintEdge, -) : SummaryEdge - -data class TaintVulnerability( - override val message: String, - override val sink: TaintVertex, - val rule: TaintMethodSink? = null, -) : Vulnerability diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/Types.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/Types.kt deleted file mode 100644 index 39e8e0aab..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/Types.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.taint - -import org.jacodb.analysis.ifds.Edge -import org.jacodb.analysis.ifds.Runner -import org.jacodb.analysis.ifds.Vertex - -typealias TaintVertex = Vertex -typealias TaintEdge = Edge -typealias TaintRunner = Runner diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/Sarif.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/Sarif.kt deleted file mode 100644 index 261924328..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/Sarif.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.unused - -import org.jacodb.analysis.ifds.TraceGraph -import org.jacodb.analysis.sarif.VulnerabilityDescription -import org.jacodb.analysis.sarif.VulnerabilityInstance -import org.jacodb.api.common.cfg.CommonInst - -fun UnusedVariableVulnerability.toSarif(): - VulnerabilityInstance = - VulnerabilityInstance( - TraceGraph(sink, mutableSetOf(sink), mutableMapOf(), emptyMap()), - VulnerabilityDescription(ruleId = null, message = message) - ) diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt deleted file mode 100644 index 148e04b9c..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.unused - -import org.jacodb.analysis.ifds.Analyzer -import org.jacodb.analysis.ifds.Edge -import org.jacodb.analysis.ifds.Vertex -import org.jacodb.analysis.util.Traits -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonInst - -context(Traits) -class UnusedVariableAnalyzer( - private val graph: ApplicationGraph, -) : Analyzer, Method, Statement> - where Method : CommonMethod, - Statement : CommonInst { - - override val flowFunctions: UnusedVariableFlowFunctions by lazy { - UnusedVariableFlowFunctions(graph) - } - - private fun isExitPoint(statement: Statement): Boolean { - return statement in graph.exitPoints(graph.methodOf(statement)) - } - - override fun handleNewEdge( - edge: Edge, - ): List> = buildList { - if (isExitPoint(edge.to.statement)) { - add(NewSummaryEdge(edge)) - } - } - - override fun handleCrossUnitCall( - caller: Vertex, - callee: Vertex, - ): List> { - return emptyList() - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableEvents.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableEvents.kt deleted file mode 100644 index d4d323cd6..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableEvents.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.unused - -import org.jacodb.analysis.ifds.Edge -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.cfg.CommonInst - -sealed interface UnusedVariableEvent - where Method : CommonMethod, - Statement : CommonInst - -data class NewSummaryEdge( - val edge: Edge, -) : UnusedVariableEvent - where Method : CommonMethod, - Statement : CommonInst diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFacts.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFacts.kt deleted file mode 100644 index 894aaa75e..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFacts.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.unused - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.api.common.cfg.CommonInst - -sealed interface UnusedVariableDomainFact - -object UnusedVariableZeroFact : UnusedVariableDomainFact { - override fun toString(): String = "Zero" -} - -data class UnusedVariable( - val variable: AccessPath, - val initStatement: CommonInst, -) : UnusedVariableDomainFact diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt deleted file mode 100644 index 2f3d9aa08..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.unused - -import org.jacodb.analysis.ifds.FlowFunction -import org.jacodb.analysis.ifds.FlowFunctions -import org.jacodb.analysis.ifds.isOnHeap -import org.jacodb.analysis.util.Traits -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.CommonProject -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonAssignInst -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.jvm.cfg.JcSpecialCallExpr -import org.jacodb.api.jvm.cfg.JcStaticCallExpr - -context(Traits) -class UnusedVariableFlowFunctions( - private val graph: ApplicationGraph, -) : FlowFunctions - where Method : CommonMethod, - Statement : CommonInst { - - override fun obtainPossibleStartFacts( - method: Method, - ): Collection { - return setOf(UnusedVariableZeroFact) - } - - override fun obtainSequentFlowFunction( - current: Statement, - next: Statement, - ) = FlowFunction { fact -> - if (current !is CommonAssignInst) { - return@FlowFunction setOf(fact) - } - - if (fact == UnusedVariableZeroFact) { - val toPath = current.lhv.toPath() - if (!toPath.isOnHeap) { - return@FlowFunction setOf(UnusedVariableZeroFact, UnusedVariable(toPath, current)) - } else { - return@FlowFunction setOf(UnusedVariableZeroFact) - } - } - check(fact is UnusedVariable) - - val toPath = current.lhv.toPath() - val default = if (toPath == fact.variable) emptySet() else setOf(fact) - val fromPath = current.rhv.toPathOrNull() - ?: return@FlowFunction default - - if (fromPath.isOnHeap || toPath.isOnHeap) { - return@FlowFunction default - } - - if (fromPath == fact.variable) { - return@FlowFunction default + fact.copy(variable = toPath) - } - - default - } - - override fun obtainCallToReturnSiteFlowFunction( - callStatement: Statement, - returnSite: Statement, - ) = obtainSequentFlowFunction(callStatement, returnSite) - - override fun obtainCallToStartFlowFunction( - callStatement: Statement, - calleeStart: Statement, - ) = FlowFunction { fact -> - val callExpr = callStatement.getCallExpr() - ?: error("Call statement should have non-null callExpr") - - if (fact == UnusedVariableZeroFact) { - // FIXME: use common? - if (callExpr !is JcStaticCallExpr && callExpr !is JcSpecialCallExpr) { - return@FlowFunction setOf(UnusedVariableZeroFact) - } - return@FlowFunction buildSet { - add(UnusedVariableZeroFact) - val callee = graph.methodOf(calleeStart) - val formalParams = getArgumentsOf(callee) - for (formal in formalParams) { - add(UnusedVariable(formal.toPath(), callStatement)) - } - } - } - check(fact is UnusedVariable) - - emptySet() - } - - override fun obtainExitToReturnSiteFlowFunction( - callStatement: Statement, - returnSite: Statement, - exitStatement: Statement, - ) = FlowFunction { fact -> - if (fact == UnusedVariableZeroFact) { - setOf(UnusedVariableZeroFact) - } else { - emptySet() - } - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableManager.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableManager.kt deleted file mode 100644 index 687465415..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableManager.kt +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.unused - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.CoroutineStart -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.cancelAndJoin -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.isActive -import kotlinx.coroutines.joinAll -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.withTimeoutOrNull -import org.jacodb.analysis.ifds.ControlEvent -import org.jacodb.analysis.ifds.Edge -import org.jacodb.analysis.ifds.Manager -import org.jacodb.analysis.ifds.QueueEmptinessChanged -import org.jacodb.analysis.ifds.Runner -import org.jacodb.analysis.ifds.SummaryStorageImpl -import org.jacodb.analysis.ifds.UniRunner -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.ifds.UnitType -import org.jacodb.analysis.ifds.UnknownUnit -import org.jacodb.analysis.ifds.Vertex -import org.jacodb.analysis.util.Traits -import org.jacodb.analysis.util.getPathEdges -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.CommonInst -import java.util.concurrent.ConcurrentHashMap -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds -import kotlin.time.DurationUnit -import kotlin.time.ExperimentalTime -import kotlin.time.TimeSource - -private val logger = mu.KotlinLogging.logger {} - -context(Traits) -class UnusedVariableManager( - private val graph: ApplicationGraph, - private val unitResolver: UnitResolver, -) : Manager, Method, Statement> - where Method : CommonMethod, - Statement : CommonInst { - - private val methodsForUnit: MutableMap> = hashMapOf() - private val runnerForUnit: MutableMap> = hashMapOf() - private val queueIsEmpty = ConcurrentHashMap() - - private val summaryEdgesStorage = - SummaryStorageImpl>() - private val vulnerabilitiesStorage = - SummaryStorageImpl>() - - private val stopRendezvous = Channel(Channel.RENDEZVOUS) - - private fun newRunner( - unit: UnitType, - ): Runner { - check(unit !in runnerForUnit) { "Runner for $unit already exists" } - - logger.debug { "Creating a new runner for $unit" } - val analyzer = UnusedVariableAnalyzer(graph) - val runner = UniRunner( - graph = graph, - analyzer = analyzer, - manager = this@UnusedVariableManager, - unitResolver = unitResolver, - unit = unit, - zeroFact = UnusedVariableZeroFact - ) - - runnerForUnit[unit] = runner - return runner - } - - private fun getAllCallees(method: Method): Set { - val result: MutableSet = hashSetOf() - for (inst in method.flowGraph().instructions) { - @Suppress("UNCHECKED_CAST") - result += graph.callees(inst as Statement) - } - return result - } - - private fun addStart(method: Method) { - logger.info { "Adding start method: $method" } - val unit = unitResolver.resolve(method) - if (unit == UnknownUnit) return - val isNew = methodsForUnit.getOrPut(unit) { hashSetOf() }.add(method) - if (isNew) { - for (dep in getAllCallees(method)) { - addStart(dep) - } - } - } - - @JvmName("analyze") // needed for Java interop because of inline class (Duration) - @OptIn(ExperimentalTime::class) - fun analyze( - startMethods: List, - timeout: Duration = 3600.seconds, - ): List> = runBlocking { - val timeStart = TimeSource.Monotonic.markNow() - - // Add start methods: - for (method in startMethods) { - addStart(method) - } - - // Determine all units: - val allUnits = methodsForUnit.keys.toList() - logger.info { - "Starting analysis of ${ - methodsForUnit.values.sumOf { it.size } - } methods in ${allUnits.size} units" - } - - // Spawn runner jobs: - val allJobs = allUnits.map { unit -> - // Create the runner: - val runner = newRunner(unit) - - // Start the runner: - launch(start = CoroutineStart.LAZY) { - val methods = methodsForUnit[unit]!!.toList() - runner.run(methods) - } - } - - // Spawn progress job: - val progress = launch(Dispatchers.IO) { - while (isActive) { - delay(1.seconds) - logger.info { - "Progress: propagated ${ - runnerForUnit.values.sumOf { it.getPathEdges().size } - } path edges" - } - } - } - - // Spawn stopper job: - val stopper = launch(Dispatchers.IO) { - stopRendezvous.receive() - logger.info { "Stopping all runners..." } - allJobs.forEach { it.cancel() } - } - - // Start all runner jobs: - val timeStartJobs = TimeSource.Monotonic.markNow() - allJobs.forEach { it.start() } - - // Await all runners: - withTimeoutOrNull(timeout) { - allJobs.joinAll() - } ?: run { - logger.info { "Timeout!" } - allJobs.forEach { it.cancel() } - allJobs.joinAll() - } - progress.cancelAndJoin() - stopper.cancelAndJoin() - logger.info { - "All ${allJobs.size} jobs completed in %.1f s".format( - timeStartJobs.elapsedNow().toDouble(DurationUnit.SECONDS) - ) - } - - // Extract found vulnerabilities (sinks): - val foundVulnerabilities = allUnits.flatMap { unit -> - val runner = runnerForUnit[unit] ?: error("No runner for $unit") - val result = runner.getIfdsResult() - val allFacts = result.facts - - val used = hashMapOf() - for ((inst, facts) in allFacts) { - for (fact in facts) { - if (fact is UnusedVariable) { - @Suppress("UNCHECKED_CAST") - used.putIfAbsent(fact.initStatement as Statement, false) - if (fact.variable.isUsedAt(inst)) { - used[fact.initStatement] = true - } - } - } - } - used.filterValues { !it }.keys.map { - UnusedVariableVulnerability( - message = "Assigned value is unused", - sink = Vertex(it, UnusedVariableZeroFact) - ) - } - } - - if (logger.isDebugEnabled) { - logger.debug { "Total found ${foundVulnerabilities.size} vulnerabilities" } - for (vulnerability in foundVulnerabilities) { - logger.debug { "$vulnerability in ${vulnerability.method}" } - } - } - logger.info { "Total sinks: ${foundVulnerabilities.size}" } - logger.info { - "Total propagated ${ - runnerForUnit.values.sumOf { it.getPathEdges().size } - } path edges" - } - logger.info { - "Analysis done in %.1f s".format( - timeStart.elapsedNow().toDouble(DurationUnit.SECONDS) - ) - } - foundVulnerabilities - } - - override fun handleEvent(event: UnusedVariableEvent) { - when (event) { - is NewSummaryEdge -> { - summaryEdgesStorage.add(UnusedVariableSummaryEdge(event.edge)) - } - } - } - - override fun handleControlEvent(event: ControlEvent) { - when (event) { - is QueueEmptinessChanged -> { - queueIsEmpty[event.runner.unit] = event.isEmpty - if (event.isEmpty) { - if (runnerForUnit.keys.all { queueIsEmpty[it] == true }) { - logger.debug { "All runners are empty" } - stopRendezvous.trySend(Unit).getOrNull() - } - } - } - } - } - - override fun subscribeOnSummaryEdges( - method: Method, - scope: CoroutineScope, - handler: (Edge) -> Unit, - ) { - summaryEdgesStorage - .getFacts(method) - .onEach { handler(it.edge) } - .launchIn(scope) - } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt deleted file mode 100644 index 86cd575c8..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.unused - -import org.jacodb.analysis.ifds.Edge -import org.jacodb.analysis.ifds.SummaryEdge -import org.jacodb.analysis.ifds.Vertex -import org.jacodb.analysis.ifds.Vulnerability -import org.jacodb.api.common.cfg.CommonInst - -data class UnusedVariableSummaryEdge( - override val edge: Edge, -) : SummaryEdge - -data class UnusedVariableVulnerability( - override val message: String, - override val sink: Vertex, -) : Vulnerability diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/Utils.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/Utils.kt deleted file mode 100644 index 6935c349d..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/Utils.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.unused - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.util.Traits -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.cfg.CommonExpr -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.jvm.cfg.JcArrayAccess -import org.jacodb.api.jvm.cfg.JcAssignInst -import org.jacodb.api.jvm.cfg.JcBranchingInst -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.cfg.JcLocal -import org.jacodb.api.jvm.cfg.JcSpecialCallExpr -import org.jacodb.api.jvm.cfg.JcTerminatingInst - -context(Traits) -internal fun AccessPath.isUsedAt( - expr: CommonExpr, -): Boolean { - return expr.getValues().any { it.toPathOrNull() == this } -} - -context(Traits) -internal fun AccessPath.isUsedAt( - inst: CommonInst, -): Boolean { - val callExpr = inst.getCallExpr() - - if (callExpr != null) { - // Don't count constructor calls as usages - if (callExpr is JcSpecialCallExpr - && callExpr.method.method.isConstructor - && isUsedAt(callExpr.instance) - ) { - return false - } - - return isUsedAt(callExpr) - } - if (inst is JcAssignInst) { - if (inst.lhv is JcArrayAccess && isUsedAt(inst.lhv)) { - return true - } - return isUsedAt(inst.rhv) && (inst.lhv !is JcLocal || inst.rhv !is JcLocal) - } - if (inst is JcTerminatingInst || inst is JcBranchingInst) { - inst as JcInst - return inst.operands.any { isUsedAt(it) } - } - return false -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/EtsTraits.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/EtsTraits.kt deleted file mode 100644 index eb11c3d10..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/EtsTraits.kt +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.util - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.ElementAccessor -import org.jacodb.analysis.ifds.FieldAccessor -import org.jacodb.analysis.util.toPathOrNull -import org.jacodb.api.common.CommonMethodParameter -import org.jacodb.api.common.cfg.CommonArgument -import org.jacodb.api.common.cfg.CommonCallExpr -import org.jacodb.api.common.cfg.CommonExpr -import org.jacodb.api.common.cfg.CommonValue -import org.jacodb.ets.base.EtsAnyType -import org.jacodb.ets.base.EtsArrayAccess -import org.jacodb.ets.base.EtsCallExpr -import org.jacodb.ets.base.EtsCastExpr -import org.jacodb.ets.base.EtsClassType -import org.jacodb.ets.base.EtsConstant -import org.jacodb.ets.base.EtsEntity -import org.jacodb.ets.base.EtsImmediate -import org.jacodb.ets.base.EtsInstanceFieldRef -import org.jacodb.ets.base.EtsParameterRef -import org.jacodb.ets.base.EtsStaticFieldRef -import org.jacodb.ets.base.EtsStmt -import org.jacodb.ets.base.EtsThis -import org.jacodb.ets.base.EtsValue -import org.jacodb.ets.model.EtsMethod -import org.jacodb.ets.model.EtsMethodImpl -import org.jacodb.ets.model.EtsMethodParameter -import org.jacodb.ets.utils.callExpr -import org.jacodb.taint.configuration.ConstantValue -import org.jacodb.analysis.util.toPath as _toPath -import org.jacodb.analysis.util.toPathOrNull as _toPathOrNull -import org.jacodb.ets.utils.getOperands as _getOperands -import org.jacodb.ets.utils.getValues as _getValues - -interface EtsTraits : Traits { - - companion object : EtsTraits { - // Note: unused for now - // lateinit var cp: EtsFile - } - - override val CommonCallExpr.callee: EtsMethod - get() { - check(this is EtsCallExpr) - // TODO: here, we should use the classpath to resolve the method by its signature, like so: - // `return cp.getMethodBySignature(method) ?: error("Method not found: $method")` - // However, currently EtsFile (classpath) is not able to perform method lookup by signature, - // and even is not available in this context. - // So, we just construct a new method instance with necessary signature, but without a CFG, for now. - return EtsMethodImpl(method) - } - - override val EtsMethod.thisInstance: EtsThis - get() = EtsThis(EtsClassType(enclosingClass)) - - override val EtsMethod.isConstructor: Boolean - get() = name == "constructor" - - override fun CommonExpr.toPathOrNull(): AccessPath? { - check(this is EtsEntity) - return this._toPathOrNull() - } - - override fun CommonValue.toPathOrNull(): AccessPath? { - check(this is EtsValue) - return this._toPathOrNull() - } - - override fun CommonValue.toPath(): AccessPath { - check(this is EtsValue) - return this._toPath() - } - - override fun getArgument(param: CommonMethodParameter): EtsParameterRef { - check(param is EtsMethodParameter) - return EtsParameterRef(index = param.index, type = param.type) - } - - override fun getArgumentsOf(method: EtsMethod): List { - return method.parameters.map { getArgument(it) } - } - - override fun CommonValue.isConstant(): Boolean { - check(this is EtsEntity) - return this is org.jacodb.ets.base.EtsConstant - } - - override fun CommonValue.eqConstant(constant: ConstantValue): Boolean { - TODO("Not yet implemented") - } - - override fun CommonValue.ltConstant(constant: ConstantValue): Boolean { - TODO("Not yet implemented") - } - - override fun CommonValue.gtConstant(constant: ConstantValue): Boolean { - TODO("Not yet implemented") - } - - override fun CommonValue.matches(pattern: String): Boolean { - TODO("Not yet implemented") - } - - override fun EtsStmt.getCallExpr(): EtsCallExpr? { - return callExpr - } - - override fun CommonExpr.getValues(): Set { - check(this is EtsEntity) - return _getValues().toSet() - } - - override fun EtsStmt.getOperands(): List { - return _getOperands().toList() - } -} - -fun EtsEntity.toPathOrNull(): AccessPath? = when (this) { - is EtsImmediate -> AccessPath(this, emptyList()) - - is EtsThis -> AccessPath(this, emptyList()) - - is EtsParameterRef -> AccessPath(this, emptyList()) - - is EtsArrayAccess -> { - array.toPathOrNull()?.let { - it + ElementAccessor - } - } - - is EtsInstanceFieldRef -> { - instance.toPathOrNull()?.let { - it + FieldAccessor(field.name) - } - } - - is EtsStaticFieldRef -> { - AccessPath(null, listOf(FieldAccessor(field.name, isStatic = true))) - } - - is EtsCastExpr -> arg.toPathOrNull() - - else -> null -} - -fun EtsEntity.toPath(): AccessPath { - return toPathOrNull() ?: error("Unable to build access path for value $this") -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/JcTraits.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/JcTraits.kt deleted file mode 100644 index b6556ac2b..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/JcTraits.kt +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.util - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.ElementAccessor -import org.jacodb.analysis.ifds.FieldAccessor -import org.jacodb.analysis.util.getArgument -import org.jacodb.analysis.util.toPathOrNull -import org.jacodb.api.common.CommonMethodParameter -import org.jacodb.api.common.cfg.CommonCallExpr -import org.jacodb.api.common.cfg.CommonExpr -import org.jacodb.api.common.cfg.CommonValue -import org.jacodb.api.jvm.JcClasspath -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.JcParameter -import org.jacodb.api.jvm.cfg.JcArgument -import org.jacodb.api.jvm.cfg.JcArrayAccess -import org.jacodb.api.jvm.cfg.JcBool -import org.jacodb.api.jvm.cfg.JcCallExpr -import org.jacodb.api.jvm.cfg.JcCastExpr -import org.jacodb.api.jvm.cfg.JcConstant -import org.jacodb.api.jvm.cfg.JcExpr -import org.jacodb.api.jvm.cfg.JcFieldRef -import org.jacodb.api.jvm.cfg.JcImmediate -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.cfg.JcInt -import org.jacodb.api.jvm.cfg.JcStringConstant -import org.jacodb.api.jvm.cfg.JcThis -import org.jacodb.api.jvm.cfg.JcValue -import org.jacodb.api.jvm.cfg.values -import org.jacodb.api.jvm.ext.toType -import org.jacodb.taint.configuration.ConstantBooleanValue -import org.jacodb.taint.configuration.ConstantIntValue -import org.jacodb.taint.configuration.ConstantStringValue -import org.jacodb.taint.configuration.ConstantValue -import org.jacodb.analysis.util.callee as _callee -import org.jacodb.analysis.util.getArgument as _getArgument -import org.jacodb.analysis.util.getArgumentsOf as _getArgumentsOf -import org.jacodb.analysis.util.thisInstance as _thisInstance -import org.jacodb.analysis.util.toPath as _toPath -import org.jacodb.analysis.util.toPathOrNull as _toPathOrNull -import org.jacodb.api.jvm.ext.cfg.callExpr as _callExpr - -/** - * JVM-specific extensions for analysis. - * - * ### Usage: - * ``` - * class MyClass { - * companion object : JcTraits - * } - * ``` - */ -interface JcTraits : Traits { - - val cp: JcClasspath - get() = JcTraits.cp - - override val JcMethod.thisInstance: JcThis - get() = _thisInstance - - @Suppress("EXTENSION_SHADOWED_BY_MEMBER") - override val JcMethod.isConstructor: Boolean - get() = isConstructor - - override fun CommonExpr.toPathOrNull(): AccessPath? { - check(this is JcExpr) - return _toPathOrNull() - } - - override fun CommonValue.toPathOrNull(): AccessPath? { - check(this is JcValue) - return _toPathOrNull() - } - - override fun CommonValue.toPath(): AccessPath { - check(this is JcValue) - return _toPath() - } - - override val CommonCallExpr.callee: JcMethod - get() { - check(this is JcCallExpr) - return _callee - } - - override fun getArgument(param: CommonMethodParameter): JcArgument? { - check(param is JcParameter) - return cp._getArgument(param) - } - - override fun getArgumentsOf(method: JcMethod): List { - return cp._getArgumentsOf(method) - } - - override fun CommonValue.isConstant(): Boolean { - check(this is JcValue) - return this is JcConstant - } - - override fun CommonValue.eqConstant(constant: ConstantValue): Boolean { - check(this is JcValue) - return when (constant) { - is ConstantBooleanValue -> { - this is JcBool && value == constant.value - } - - is ConstantIntValue -> { - this is JcInt && value == constant.value - } - - is ConstantStringValue -> { - // TODO: if 'value' is not string, convert it to string and compare with 'constant.value' - this is JcStringConstant && value == constant.value - } - } - } - - override fun CommonValue.ltConstant(constant: ConstantValue): Boolean { - check(this is JcValue) - return when (constant) { - is ConstantIntValue -> { - this is JcInt && value < constant.value - } - - else -> error("Unexpected constant: $constant") - } - } - - override fun CommonValue.gtConstant(constant: ConstantValue): Boolean { - check(this is JcValue) - return when (constant) { - is ConstantIntValue -> { - this is JcInt && value > constant.value - } - - else -> error("Unexpected constant: $constant") - } - } - - override fun CommonValue.matches(pattern: String): Boolean { - check(this is JcValue) - val s = this.toString() - val re = pattern.toRegex() - return re.matches(s) - } - - override fun JcInst.getCallExpr(): CommonCallExpr? { - return _callExpr - } - - override fun CommonExpr.getValues(): Set { - check(this is JcExpr) - return values - } - - override fun JcInst.getOperands(): List { - return operands - } - - // Ensure that all methods are default-implemented in the interface itself: - companion object : JcTraits { - override lateinit var cp: JcClasspath - } -} - -val JcMethod.thisInstance: JcThis - get() = JcThis(enclosingClass.toType()) - -val JcCallExpr.callee: JcMethod - get() = method.method - -fun JcExpr.toPathOrNull(): AccessPath? = when (this) { - is JcValue -> toPathOrNull() - is JcCastExpr -> operand.toPathOrNull() - else -> null -} - -fun JcValue.toPathOrNull(): AccessPath? = when (this) { - is JcImmediate -> AccessPath(this, emptyList()) - - is JcArrayAccess -> { - array.toPathOrNull()?.let { - it + ElementAccessor - } - } - - is JcFieldRef -> { - val instance = instance - if (instance == null) { - require(field.isStatic) { "Expected static field" } - AccessPath(null, listOf(FieldAccessor(field.name, isStatic = true))) - } else { - instance.toPathOrNull()?.let { - it + FieldAccessor(field.name) - } - } - } - - else -> null -} - -fun JcValue.toPath(): AccessPath { - return toPathOrNull() ?: error("Unable to build access path for value $this") -} - -fun JcClasspath.getArgument(param: JcParameter): JcArgument? { - val t = findTypeOrNull(param.type.typeName) ?: return null - return JcArgument.of(param.index, param.name, t) -} - -fun JcClasspath.getArgumentsOf(method: JcMethod): List { - return method.parameters.map { getArgument(it)!! } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/PandaStaticTraits.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/PandaStaticTraits.kt deleted file mode 100644 index d1295acf2..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/PandaStaticTraits.kt +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.util - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.ElementAccessor -import org.jacodb.analysis.ifds.FieldAccessor -import org.jacodb.analysis.util.getArgument -import org.jacodb.analysis.util.toPathOrNull -import org.jacodb.api.common.CommonMethodParameter -import org.jacodb.api.common.cfg.CommonCallExpr -import org.jacodb.api.common.cfg.CommonExpr -import org.jacodb.api.common.cfg.CommonValue -import org.jacodb.panda.staticvm.cfg.PandaArgument -import org.jacodb.panda.staticvm.cfg.PandaArrayAccess -import org.jacodb.panda.staticvm.cfg.PandaCallExpr -import org.jacodb.panda.staticvm.cfg.PandaCastExpr -import org.jacodb.panda.staticvm.cfg.PandaConstant -import org.jacodb.panda.staticvm.cfg.PandaExpr -import org.jacodb.panda.staticvm.cfg.PandaFieldRef -import org.jacodb.panda.staticvm.cfg.PandaInst -import org.jacodb.panda.staticvm.cfg.PandaPhiExpr -import org.jacodb.panda.staticvm.cfg.PandaSimpleValue -import org.jacodb.panda.staticvm.cfg.PandaThis -import org.jacodb.panda.staticvm.cfg.PandaValue -import org.jacodb.panda.staticvm.classpath.PandaClass -import org.jacodb.panda.staticvm.classpath.PandaClassType -import org.jacodb.panda.staticvm.classpath.PandaMethod -import org.jacodb.taint.configuration.ConstantBooleanValue -import org.jacodb.taint.configuration.ConstantIntValue -import org.jacodb.taint.configuration.ConstantStringValue -import org.jacodb.taint.configuration.ConstantValue -import org.jacodb.analysis.util.getArgument as _getArgument -import org.jacodb.analysis.util.getArgumentsOf as _getArgumentsOf -import org.jacodb.analysis.util.thisInstance as _thisInstance -import org.jacodb.analysis.util.toPath as _toPath -import org.jacodb.analysis.util.toPathOrNull as _toPathOrNull -import org.jacodb.analysis.util.toPaths as _toPaths -import org.jacodb.panda.staticvm.utils.callExpr as _callExpr - -/** - * Panda-specific extensions for analysis. - * - * ### Usage: - * ``` - * class MyClass { - * companion object : PandaTraits - * } - * ``` - */ -interface PandaStaticTraits : Traits { - - override val PandaMethod.thisInstance: PandaThis - get() = _thisInstance - - override val PandaMethod.isConstructor: Boolean - get() = name == "" - - override fun CommonExpr.toPathOrNull(): AccessPath? { - check(this is PandaExpr) - return _toPathOrNull() - } - - override fun CommonExpr.toPaths(): List { - check(this is PandaExpr) - return _toPaths() - } - - override fun CommonValue.toPathOrNull(): AccessPath? { - check(this is PandaValue) - return _toPathOrNull() - } - - override fun CommonValue.toPath(): AccessPath { - check(this is PandaValue) - return _toPath() - } - - override val CommonCallExpr.callee: PandaMethod - get() { - check(this is PandaCallExpr) - return method - } - - override fun PandaInst.getCallExpr(): CommonCallExpr? = _callExpr - - override fun getArgument(param: CommonMethodParameter): PandaArgument { - check(param is PandaMethod.Parameter) - return _getArgument(param) - } - - override fun getArgumentsOf(method: PandaMethod): List { - return _getArgumentsOf(method) - } - - override fun CommonValue.isConstant(): Boolean { - check(this is PandaValue) - return this is PandaConstant - } - - override fun CommonValue.eqConstant(constant: ConstantValue): Boolean { - check(this is PandaValue) - return when (constant) { - is ConstantBooleanValue -> { - // this is PandaBoolConstant && this.value == constant.value - TODO() - } - - is ConstantIntValue -> { - // this is PandaNumberConstant && this.value == constant.value - TODO() - } - - is ConstantStringValue -> { - // TODO: convert to string if necessary - // this is PandaStringConstant && this.value == constant.value - TODO() - } - } - } - - override fun CommonValue.ltConstant(constant: ConstantValue): Boolean { - check(this is PandaValue) - return when (constant) { - is ConstantIntValue -> { - // this is PandaNumberConstant && this.value < constant.value - TODO() - } - - else -> false - } - } - - override fun CommonValue.gtConstant(constant: ConstantValue): Boolean { - check(this is PandaValue) - return when (constant) { - is ConstantIntValue -> { - // this is PandaNumberConstant && this.value > constant.value - TODO() - } - - else -> false - } - } - - override fun CommonValue.matches(pattern: String): Boolean { - check(this is PandaValue) - val s = this.toString() - val re = pattern.toRegex() - return re.matches(s) - } - - override fun CommonExpr.getValues(): Set { - check(this is PandaExpr) - return TODO() - } - - override fun PandaInst.getOperands(): List { - return operands - } - - // Ensure that all methods are default-implemented in the interface itself: - companion object : PandaStaticTraits { - // Note: unused for now - // lateinit var cp: PandaProject - } -} - -val PandaMethod.thisInstance: PandaThis - get() = PandaThis("v0", enclosingClass.type) - -internal fun PandaClass.toType(): PandaClassType = type - -fun PandaExpr.toPathOrNull(): AccessPath? = when (this) { - is PandaValue -> toPathOrNull() - is PandaCastExpr -> arg.toPathOrNull() - else -> null -} - -fun PandaExpr.toPaths(): List = when (this) { - is PandaPhiExpr -> operands.mapNotNull(PandaValue::_toPathOrNull) - else -> listOfNotNull(_toPathOrNull()) -} - -fun PandaValue.toPathOrNull(): AccessPath? = when (this) { - is PandaSimpleValue -> AccessPath(this, emptyList()) - - is PandaArrayAccess -> { - array.toPathOrNull()?.let { - it + ElementAccessor - } - } - - is PandaFieldRef -> { - val instance = instance - if (instance == null) { - AccessPath(null, listOf(FieldAccessor(field.name, isStatic = true))) - } else { - instance.toPathOrNull()?.let { - it + FieldAccessor(field.name) - } - } - } - - else -> null -} - -fun PandaValue.toPath(): AccessPath { - return toPathOrNull() ?: error("Unable to build access path for value $this") -} - -fun getArgument(param: PandaMethod.Parameter): PandaArgument { - return PandaArgument(param.index, "arg${param.index}", param.type) -} - -fun getArgumentsOf(method: PandaMethod): List { - return method.parameters.map { getArgument(it) } -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/Traits.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/Traits.kt deleted file mode 100644 index 6e47f32c9..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/Traits.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.util - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.CommonMethodParameter -import org.jacodb.api.common.cfg.CommonArgument -import org.jacodb.api.common.cfg.CommonCallExpr -import org.jacodb.api.common.cfg.CommonExpr -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.common.cfg.CommonThis -import org.jacodb.api.common.cfg.CommonValue -import org.jacodb.taint.configuration.ConstantValue - -/** - * Extensions for analysis. - */ -interface Traits - where Method : CommonMethod, - Statement : CommonInst { - - val @UnsafeVariance Method.thisInstance: CommonThis - val @UnsafeVariance Method.isConstructor: Boolean - - fun CommonExpr.toPathOrNull(): AccessPath? - fun CommonValue.toPathOrNull(): AccessPath? - fun CommonValue.toPath(): AccessPath - - val CommonCallExpr.callee: Method - - fun getArgument(param: CommonMethodParameter): CommonArgument? - fun getArgumentsOf(method: @UnsafeVariance Method): List - - fun CommonValue.isConstant(): Boolean - fun CommonValue.eqConstant(constant: ConstantValue): Boolean - fun CommonValue.ltConstant(constant: ConstantValue): Boolean - fun CommonValue.gtConstant(constant: ConstantValue): Boolean - fun CommonValue.matches(pattern: String): Boolean - - // TODO: remove - fun CommonExpr.toPaths(): List = listOfNotNull(toPathOrNull()) - - fun @UnsafeVariance Statement.getCallExpr(): CommonCallExpr? - fun CommonExpr.getValues(): Set - fun @UnsafeVariance Statement.getOperands(): List -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/Utils.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/Utils.kt deleted file mode 100644 index aa6ae83f6..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/Utils.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.util - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.Edge -import org.jacodb.analysis.ifds.ElementAccessor -import org.jacodb.analysis.ifds.Runner -import org.jacodb.analysis.ifds.UniRunner -import org.jacodb.analysis.taint.TaintBidiRunner - -fun AccessPath?.startsWith(other: AccessPath?): Boolean { - if (this == null || other == null) { - return false - } - if (this.value != other.value) { - return false - } - return this.accesses.take(other.accesses.size) == other.accesses -} - -internal fun AccessPath.removeTrailingElementAccessors(): AccessPath { - var index = accesses.size - while (index > 0 && accesses[index - 1] is ElementAccessor) { - index-- - } - return AccessPath(value, accesses.subList(0, index)) -} - -fun Runner<*, *, *>.getPathEdges(): Set> = when (this) { - is UniRunner<*, *, *, *> -> pathEdges - is TaintBidiRunner<*, *> -> forwardRunner.getPathEdges() + backwardRunner.getPathEdges() - else -> error("Cannot extract pathEdges for $this") -} diff --git a/jacodb-analysis/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java b/jacodb-analysis/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java deleted file mode 100644 index 1bdda4a4b..000000000 --- a/jacodb-analysis/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.impl; - -import kotlin.time.DurationUnit; -import org.jacodb.analysis.graph.ApplicationGraphFactory; -import org.jacodb.analysis.ifds.UnitResolver; -import org.jacodb.analysis.ifds.UnitResolverKt; -import org.jacodb.analysis.taint.TaintManager; -import org.jacodb.analysis.util.JcTraits; -import org.jacodb.api.jvm.JcClassOrInterface; -import org.jacodb.api.jvm.JcClasspath; -import org.jacodb.api.jvm.JcDatabase; -import org.jacodb.api.jvm.JcMethod; -import org.jacodb.api.jvm.analysis.JcApplicationGraph; -import org.jacodb.api.jvm.cfg.JcInst; -import org.jacodb.impl.JacoDB; -import org.jacodb.impl.JcSettings; -import org.jacodb.impl.features.InMemoryHierarchy; -import org.jacodb.impl.features.Usages; -import org.jacodb.testing.LibrariesMixinKt; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutionException; - -import static kotlin.time.DurationKt.toDuration; - - -public class JavaAnalysisApiTest { - private static JcClasspath classpath; - - @BeforeAll - public static void initClasspath() throws ExecutionException, InterruptedException { - JcDatabase instance = JacoDB.async(new JcSettings().installFeatures(Usages.INSTANCE, InMemoryHierarchy.INSTANCE)).get(); - classpath = instance.asyncClasspath(LibrariesMixinKt.getAllClasspath()).get(); - } - - @Test - public void testJavaAnalysisApi() throws ExecutionException, InterruptedException { - JcClassOrInterface analyzedClass = classpath.findClassOrNull("org.jacodb.testing.analysis.NpeExamples"); - Assertions.assertNotNull(analyzedClass); - - List methodsToAnalyze = analyzedClass.getDeclaredMethods(); - JcApplicationGraph applicationGraph = ApplicationGraphFactory - .newApplicationGraphForAnalysisAsync(classpath, null) - .get(); - UnitResolver unitResolver = UnitResolverKt.getMethodUnitResolver(); - TaintManager manager = new TaintManager(JcTraits.Companion, applicationGraph, unitResolver, false, null); - manager.analyze(methodsToAnalyze, toDuration(30, DurationUnit.SECONDS)); - } - - @Test - public void testCustomBannedPackagesApi() throws ExecutionException, InterruptedException { - List bannedPackages = new ArrayList<>(ApplicationGraphFactory.getDefaultBannedPackagePrefixes()); - bannedPackages.add("my.package.that.wont.be.analyzed"); - - JcApplicationGraph customGraph = ApplicationGraphFactory - .newApplicationGraphForAnalysisAsync(classpath, bannedPackages) - .get(); - Assertions.assertNotNull(customGraph); - } -} diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt deleted file mode 100644 index 3be16d2e9..000000000 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.impl - -import juliet.support.AbstractTestCase -import kotlinx.coroutines.runBlocking -import org.jacodb.analysis.graph.newApplicationGraphForAnalysis -import org.jacodb.analysis.ifds.Vulnerability -import org.jacodb.analysis.util.JcTraits -import org.jacodb.api.jvm.JcClasspath -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.analysis.JcApplicationGraph -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.ext.findClass -import org.jacodb.api.jvm.ext.methods -import org.jacodb.impl.features.classpaths.UnknownClasses -import org.jacodb.impl.features.hierarchyExt -import org.jacodb.taint.configuration.TaintConfigurationFeature -import org.jacodb.testing.BaseTest -import org.jacodb.testing.WithGlobalDB -import org.jacodb.testing.allClasspath -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.params.provider.Arguments -import java.util.stream.Stream -import kotlin.streams.asStream - -private val logger = mu.KotlinLogging.logger {} - -abstract class BaseAnalysisTest : BaseTest() { - - companion object : WithGlobalDB(UnknownClasses), JcTraits { - - fun getJulietClasses( - cweNum: Int, - cweSpecificBans: List = emptyList(), - ): Sequence = runBlocking { - val cp = db.classpath(allClasspath) - val hierarchyExt = cp.hierarchyExt() - val baseClass = cp.findClass() - hierarchyExt.findSubClasses(baseClass, false) - .map { it.name } - .filter { it.contains("CWE${cweNum}_") } - .filterNot { className -> (commonJulietBans + cweSpecificBans).any { className.contains(it) } } - .sorted() - } - - @JvmStatic - fun provideClassesForJuliet( - cweNum: Int, - cweSpecificBans: List = emptyList(), - ): Stream = - getJulietClasses(cweNum, cweSpecificBans) - .map { Arguments.of(it) } - .asStream() - - private val commonJulietBans = listOf( - // TODO: containers not supported - "_72", "_73", "_74", - - // TODO/Won't fix(?): dead parts of switches shouldn't be analyzed - "_15", - - // TODO/Won't fix(?): passing through channels not supported - "_75", - - // TODO/Won't fix(?): constant private/static methods not analyzed - "_11", "_08", - - // TODO/Won't fix(?): unmodified non-final private variables not analyzed - "_05", "_07", - - // TODO/Won't fix(?): unmodified non-final static variables not analyzed - "_10", "_14", - ) - } - - override val cp: JcClasspath = runBlocking { - val configFileName = "config_small.json" - val configResource = this.javaClass.getResourceAsStream("/$configFileName") - if (configResource != null) { - val configJson = configResource.bufferedReader().readText() - val configurationFeature = TaintConfigurationFeature.fromJson(configJson) - db.classpath(allClasspath, listOf(configurationFeature) + classpathFeatures) - } else { - super.cp - } - }.also { - JcTraits.cp = it - } - - protected val graph: JcApplicationGraph by lazy { - runBlocking { - cp.newApplicationGraphForAnalysis() - } - } - - protected fun testSingleJulietClass( - className: String, - findSinks: (JcMethod) -> List>, - ) { - logger.info { className } - - val clazz = cp.findClass(className) - val badMethod = clazz.methods.single { it.name == "bad" } - val goodMethod = clazz.methods.single { it.name == "good" } - - logger.info { "Searching for sinks in BAD method: $badMethod" } - val badIssues = findSinks(badMethod) - logger.info { "Total ${badIssues.size} issues in BAD method" } - for (issue in badIssues) { - logger.debug { " - $issue" } - } - assertTrue(badIssues.isNotEmpty()) { "Must find some sinks in 'bad' for $className" } - - logger.info { "Searching for sinks in GOOD method: $goodMethod" } - val goodIssues = findSinks(goodMethod) - logger.info { "Total ${goodIssues.size} issues in GOOD method" } - for (issue in goodIssues) { - logger.debug { " - $issue" } - } - assertTrue(goodIssues.isEmpty()) { "Must NOT find any sinks in 'good' for $className" } - } -} diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt deleted file mode 100644 index c99bb98e8..000000000 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.impl - -import io.mockk.every -import io.mockk.mockk -import org.jacodb.analysis.config.BasicConditionEvaluator -import org.jacodb.analysis.config.FactAwareConditionEvaluator -import org.jacodb.analysis.ifds.Maybe -import org.jacodb.analysis.ifds.toMaybe -import org.jacodb.analysis.taint.Tainted -import org.jacodb.analysis.util.JcTraits -import org.jacodb.api.jvm.JcClasspath -import org.jacodb.api.jvm.JcPrimitiveType -import org.jacodb.api.jvm.JcType -import org.jacodb.api.jvm.PredefinedPrimitive -import org.jacodb.api.jvm.PredefinedPrimitives -import org.jacodb.api.jvm.cfg.JcBool -import org.jacodb.api.jvm.cfg.JcInt -import org.jacodb.api.jvm.cfg.JcStringConstant -import org.jacodb.api.jvm.cfg.JcThis -import org.jacodb.api.jvm.cfg.JcValue -import org.jacodb.taint.configuration.And -import org.jacodb.taint.configuration.AnnotationType -import org.jacodb.taint.configuration.Argument -import org.jacodb.taint.configuration.ConditionVisitor -import org.jacodb.taint.configuration.ConstantBooleanValue -import org.jacodb.taint.configuration.ConstantEq -import org.jacodb.taint.configuration.ConstantGt -import org.jacodb.taint.configuration.ConstantIntValue -import org.jacodb.taint.configuration.ConstantLt -import org.jacodb.taint.configuration.ConstantMatches -import org.jacodb.taint.configuration.ConstantStringValue -import org.jacodb.taint.configuration.ConstantTrue -import org.jacodb.taint.configuration.ContainsMark -import org.jacodb.taint.configuration.IsConstant -import org.jacodb.taint.configuration.IsType -import org.jacodb.taint.configuration.Not -import org.jacodb.taint.configuration.Or -import org.jacodb.taint.configuration.Position -import org.jacodb.taint.configuration.SourceFunctionMatches -import org.jacodb.taint.configuration.TaintMark -import org.jacodb.taint.configuration.This -import org.jacodb.taint.configuration.TypeMatches -import org.junit.jupiter.api.Test -import kotlin.test.assertFailsWith -import kotlin.test.assertFalse -import kotlin.test.assertTrue - -class ConditionEvaluatorTest { - - companion object : JcTraits - - private val cp = mockk() - - private val intType: JcPrimitiveType = PredefinedPrimitive(cp, PredefinedPrimitives.Int) - private val boolType: JcPrimitiveType = PredefinedPrimitive(cp, PredefinedPrimitives.Boolean) - private val stringType = mockk { - every { classpath } returns cp - } - - private val intArg: Position = Argument(0) - private val intValue = JcInt(42, intType) - - private val boolArg: Position = Argument(1) - private val boolValue = JcBool(true, boolType) - - private val stringArg: Position = Argument(2) - private val stringValue = JcStringConstant("test", stringType) - - private val thisPos: Position = This - private val thisValue = JcThis(type = mockk()) - - private val positionResolver: (position: Position) -> Maybe = { position -> - when (position) { - intArg -> intValue - boolArg -> boolValue - stringArg -> stringValue - thisPos -> thisValue - else -> null - }.toMaybe() - } - private val evaluator: ConditionVisitor = BasicConditionEvaluator(positionResolver) - - @Test - fun `True is true`() { - val condition = ConstantTrue - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `Not(True) is false`() { - val condition = Not(ConstantTrue) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `Not(Not(True)) is true`() { - val condition = Not(Not(ConstantTrue)) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `And(True) is true`() { - val condition = And(listOf(ConstantTrue, ConstantTrue, ConstantTrue)) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `And(Not(True)) is false`() { - val condition = And(listOf(ConstantTrue, ConstantTrue, Not(ConstantTrue))) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `Or(Not(True)) is false`() { - val condition = Or(listOf(Not(ConstantTrue), Not(ConstantTrue), Not(ConstantTrue))) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `Or(True) is true`() { - val condition = Or(listOf(Not(ConstantTrue), Not(ConstantTrue), ConstantTrue)) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `IsConstant(int) is true`() { - val condition = IsConstant(intArg) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `IsConstant(bool) is true`() { - val condition = IsConstant(boolArg) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `IsConstant(this) is false`() { - val condition = IsConstant(thisPos) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `IsConstant(unresolved) is false`() { - val condition = IsConstant(position = mockk()) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `IsType in unexpected`() { - val condition = mockk() - assertFailsWith { - evaluator.visit(condition) - } - } - - @Test - fun `AnnotationType in unexpected`() { - val condition = mockk() - assertFailsWith { - evaluator.visit(condition) - } - } - - @Test - fun `ConstantEq(intArg(42), 42) is true`() { - val condition = ConstantEq(intArg, ConstantIntValue(42)) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `ConstantEq(intArg(42), 999) is false`() { - val condition = ConstantEq(intArg, ConstantIntValue(999)) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `ConstantEq(boolArg(true), true) is true`() { - val condition = ConstantEq(boolArg, ConstantBooleanValue(true)) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `ConstantEq(boolArg(true), false) is false`() { - val condition = ConstantEq(boolArg, ConstantBooleanValue(false)) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `ConstantEq(stringArg('test'), 'test') is true`() { - val condition = ConstantEq(stringArg, ConstantStringValue("test")) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `ConstantEq(stringArg('test'), 'other') is false`() { - val condition = ConstantEq(stringArg, ConstantStringValue("other")) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `ConstantEq(unresolved, any) is false`() { - val condition = ConstantEq(position = mockk(), value = mockk()) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `ConstantLt(intArg(42), 999) is true`() { - val condition = ConstantLt(intArg, ConstantIntValue(999)) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `ConstantLt(intArg(42), 5) is false`() { - val condition = ConstantLt(intArg, ConstantIntValue(5)) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `ConstantLt(unresolved, any) is false`() { - val condition = ConstantLt(position = mockk(), value = mockk()) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `ConstantGt(intArg(42), 5) is true`() { - val condition = ConstantGt(intArg, ConstantIntValue(5)) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `ConstantGt(intArg(42), 999) is false`() { - val condition = ConstantGt(intArg, ConstantIntValue(999)) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `ConstantGt(unresolved, any) is false`() { - val condition = ConstantGt(position = mockk(), value = mockk()) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `ConstantMatches(intArg(42), '42') is true`() { - val condition = ConstantMatches(intArg, "42") - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `ConstantMatches(intArg(42), 'd+') is true`() { - val condition = ConstantMatches(intArg, "\\d+") - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `ConstantMatches(stringArg('test'), 'test') is true`() { - val condition = ConstantMatches(stringArg, "\"test\"") - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `ConstantMatches(stringArg('test'), 'w+') is true`() { - val condition = ConstantMatches(stringArg, "\"\\w+\"") - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `ConstantMatches(unresolved, any) is false`() { - val condition = ConstantMatches(position = mockk(), pattern = ".*") - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `SourceFunctionMatches is not implemented yet`() { - val condition = mockk() - assertFailsWith { - evaluator.visit(condition) - } - } - - @Test - fun `ContainsMark is not supported by basic evaluator`() { - val condition = mockk() - assertFailsWith { - evaluator.visit(condition) - } - } - - @Test - fun `TypeMatches(intArg, Int) is true`() { - val condition = TypeMatches(intArg, intType) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `TypeMatches(boolArg, Boolean) is true`() { - val condition = TypeMatches(boolArg, boolType) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `TypeMatches(stringArg, String) is true`() { - val condition = TypeMatches(stringArg, stringType) - assertTrue(evaluator.visit(condition)) - } - - @Test - fun `TypeMatches(unresolved, any) is false`() { - val condition = TypeMatches(position = mockk(), type = mockk()) - assertFalse(evaluator.visit(condition)) - } - - @Test - fun `FactAwareConditionEvaluator supports ContainsMark`() { - val fact = Tainted(intValue.toPath(), TaintMark("FOO")) - val factAwareEvaluator = FactAwareConditionEvaluator(fact, positionResolver) - assertTrue(factAwareEvaluator.visit(ContainsMark(intArg, TaintMark("FOO")))) - assertFalse(factAwareEvaluator.visit(ContainsMark(intArg, TaintMark("BAR")))) - assertFalse(factAwareEvaluator.visit(ContainsMark(stringArg, TaintMark("FOO")))) - assertFalse(factAwareEvaluator.visit(ContainsMark(stringArg, TaintMark("BAR")))) - assertFalse(factAwareEvaluator.visit(ContainsMark(position = mockk(), TaintMark("FOO")))) - } -} diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt deleted file mode 100644 index cbb3cb0a0..000000000 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.impl - -import kotlinx.coroutines.runBlocking -import org.jacodb.analysis.graph.JcApplicationGraphImpl -import org.jacodb.analysis.ifds.SingletonUnitResolver -import org.jacodb.analysis.npe.NpeManager -import org.jacodb.analysis.taint.TaintVulnerability -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.ext.constructors -import org.jacodb.api.jvm.ext.findClass -import org.jacodb.impl.features.InMemoryHierarchy -import org.jacodb.impl.features.Usages -import org.jacodb.impl.features.usagesExt -import org.jacodb.testing.WithDB -import org.jacodb.testing.WithRAMDB -import org.jacodb.testing.analysis.NpeExamples -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.MethodSource -import java.util.StringTokenizer -import java.util.stream.Stream -import kotlin.time.Duration.Companion.seconds - -private val logger = mu.KotlinLogging.logger {} - -abstract class IfdsNpeTest : BaseAnalysisTest() { - - companion object { - @JvmStatic - fun provideClassesForJuliet476(): Stream = - provideClassesForJuliet(476, listOf("null_check_after_deref")) - - @JvmStatic - fun provideClassesForJuliet690(): Stream = - provideClassesForJuliet(690) - } - - @Test - fun `fields resolving should work through interfaces`() = runBlocking { - val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) - val callers = graph.callers(cp.findClass().constructors[2]) - logger.debug { "callers: ${callers.toList().size}" } - } - - @Test - fun `analyze simple NPE`() { - testOneMethod("npeOnLength", listOf("%3 = x.length()")) - } - - @Test - fun `analyze no NPE`() { - testOneMethod("noNPE", emptyList()) - } - - @Test - fun `analyze NPE after fun with two exits`() { - testOneMethod( - "npeAfterTwoExits", - listOf("%4 = x.length()", "%5 = y.length()") - ) - } - - @Test - fun `no NPE after checked access`() { - testOneMethod("checkedAccess", emptyList()) - } - - @Disabled("Aliasing") - @Test - fun `no NPE after checked access with field`() { - testOneMethod("checkedAccessWithField", emptyList()) - } - - @Test - fun `consecutive NPEs handled properly`() { - testOneMethod( - "consecutiveNPEs", - listOf("a = x.length()", "c = x.length()") - ) - } - - @Test - fun `npe on virtual call when possible`() { - testOneMethod( - "possibleNPEOnVirtualCall", - listOf("%0 = x.length()") - ) - } - - @Test - fun `no npe on virtual call when impossible`() { - testOneMethod( - "noNPEOnVirtualCall", - emptyList() - ) - } - - @Test - fun `basic test for NPE on fields`() { - testOneMethod("simpleNPEOnField", listOf("len2 = second.length()")) - } - - @Disabled("Flowdroid architecture not supported for async ifds yet") - @Test - fun `simple points-to analysis`() { - testOneMethod("simplePoints2", listOf("%5 = %4.length()")) - } - - @Disabled("Flowdroid architecture not supported for async ifds yet") - @Test - fun `complex aliasing`() { - testOneMethod("complexAliasing", listOf("%6 = %5.length()")) - } - - @Disabled("Flowdroid architecture not supported for async ifds yet") - @Test - fun `context injection in points-to`() { - testOneMethod( - "contextInjection", - listOf("%6 = %5.length()", "%3 = %2.length()") - ) - } - - @Disabled("Flowdroid architecture not supported for async ifds yet") - @Test - fun `activation points maintain flow sensitivity`() { - testOneMethod("flowSensitive", listOf("%8 = %7.length()")) - } - - @Test - fun `overridden null assignment in callee don't affect next caller's instructions`() { - testOneMethod("overriddenNullInCallee", emptyList()) - } - - @Test - fun `recursive classes handled correctly`() { - testOneMethod( - "recursiveClass", - listOf("%10 = %9.toString()", "%15 = %14.toString()") - ) - } - - @Test - fun `NPE on uninitialized array element dereferencing`() { - testOneMethod("simpleArrayNPE", listOf("b = %4.length()")) - } - - @Test - fun `no NPE on array element dereferencing after initialization`() { - testOneMethod("noNPEAfterArrayInit", emptyList()) - } - - @Disabled("Flowdroid architecture not supported for async ifds yet") - @Test - fun `array aliasing`() { - testOneMethod("arrayAliasing", listOf("%5 = %4.length()")) - } - - @Disabled("Flowdroid architecture not supported for async ifds yet") - @Test - fun `mixed array and class aliasing`() { - testOneMethod("mixedArrayClassAliasing", listOf("%13 = %12.length()")) - } - - @Test - fun `dereferencing field of null object`() { - testOneMethod("npeOnFieldDeref", listOf("s = a.field")) - } - - @Test - fun `dereferencing copy of value saved before null assignment produce no npe`() { - testOneMethod("copyBeforeNullAssignment", emptyList()) - } - - @Test - fun `assigning null to copy doesn't affect original value`() { - testOneMethod("nullAssignmentToCopy", emptyList()) - } - - private fun findSinks(method: JcMethod): List> { - val unitResolver = SingletonUnitResolver - val manager = NpeManager(graph, unitResolver) - return manager.analyze(listOf(method), timeout = 30.seconds) - } - - @ParameterizedTest - @MethodSource("provideClassesForJuliet476") - fun `test on Juliet's CWE 476`(className: String) { - testSingleJulietClass(className, ::findSinks) - } - - @ParameterizedTest - @MethodSource("provideClassesForJuliet690") - fun `test on Juliet's CWE 690`(className: String) { - testSingleJulietClass(className, ::findSinks) - } - - @Test - fun `test on specific Juliet's testcase`() { - // val className = "juliet.testcases.CWE476_NULL_Pointer_Dereference.CWE476_NULL_Pointer_Dereference__Integer_01" - // val className = "juliet.testcases.CWE690_NULL_Deref_From_Return.CWE690_NULL_Deref_From_Return__Class_StringBuilder_01" - val className = - "juliet.testcases.CWE690_NULL_Deref_From_Return.CWE690_NULL_Deref_From_Return__Properties_getProperty_equals_01" - - testSingleJulietClass(className, ::findSinks) - } - - private inline fun testOneMethod( - methodName: String, - expectedLocations: Collection, - ) { - val method = cp.findClass().declaredMethods.single { it.name == methodName } - val sinks = findSinks(method) - - // TODO: think about better assertions here - Assertions.assertEquals(expectedLocations.size, sinks.size) - expectedLocations.forEach { expected -> - Assertions.assertTrue(sinks.map { it.sink.toString() }.any { it.contains(expected) }) - } - } -} - -class IfdsNpeSqlTest : IfdsNpeTest() { - companion object : WithDB(Usages, InMemoryHierarchy) -} - -class IfdsNpeRAMTest : IfdsNpeTest() { - companion object : WithRAMDB(Usages, InMemoryHierarchy) -} \ No newline at end of file diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt deleted file mode 100644 index 7128b4ba8..000000000 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.impl - -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json -import org.jacodb.analysis.ifds.ClassUnitResolver -import org.jacodb.analysis.ifds.SingletonUnitResolver -import org.jacodb.analysis.sarif.sarifReportFromVulnerabilities -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.taint.toSarif -import org.jacodb.api.jvm.ext.findClass -import org.jacodb.api.jvm.ext.methods -import org.jacodb.impl.features.InMemoryHierarchy -import org.jacodb.impl.features.Usages -import org.jacodb.testing.WithDB -import org.jacodb.testing.WithRAMDB -import org.jacodb.testing.analysis.SqlInjectionExamples -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.MethodSource -import java.util.stream.Stream -import kotlin.time.Duration.Companion.seconds - -private val logger = mu.KotlinLogging.logger {} - -abstract class IfdsSqlTest : BaseAnalysisTest() { - - companion object { - @JvmStatic - fun provideClassesForJuliet89(): Stream = provideClassesForJuliet(89, specificBansCwe89) - - private val specificBansCwe89: List = listOf( - // Not working yet (#156) - "s03", "s04" - ) - } - - private val myJson = Json { - prettyPrint = true - } - - @Test - fun `simple SQL injection`() { - val methodName = "bad" - val method = cp.findClass().declaredMethods.single { it.name == methodName } - val methods = listOf(method) - val unitResolver = SingletonUnitResolver - val manager = TaintManager(graph, unitResolver) - val sinks = manager.analyze(methods, timeout = 30.seconds) - assertTrue(sinks.isNotEmpty()) - val sink = sinks.first() - val graph = manager.vulnerabilityTraceGraph(sink) - val trace = graph.getAllTraces().first() - assertTrue(trace.isNotEmpty()) - } - - @ParameterizedTest - @MethodSource("provideClassesForJuliet89") - fun `test on Juliet's CWE 89`(className: String) { - testSingleJulietClass(className) { method -> - val unitResolver = SingletonUnitResolver - val manager = TaintManager(graph, unitResolver) - manager.analyze(listOf(method), timeout = 30.seconds) - } - } - - @Test - fun `test on specific Juliet instance`() { - val className = "juliet.testcases.CWE89_SQL_Injection.s01.CWE89_SQL_Injection__connect_tcp_execute_01" - testSingleJulietClass(className) { method -> - val unitResolver = SingletonUnitResolver - val manager = TaintManager(graph, unitResolver) - manager.analyze(listOf(method), timeout = 30.seconds) - } - } - - @Test - fun `test bidirectional runner and other stuff`() { - val className = "juliet.testcases.CWE89_SQL_Injection.s01.CWE89_SQL_Injection__Environment_executeBatch_51a" - val clazz = cp.findClass(className) - val badMethod = clazz.methods.single { it.name == "bad" } - val unitResolver = ClassUnitResolver(true) - val manager = TaintManager(graph, unitResolver, useBidiRunner = true) - val sinks = manager.analyze(listOf(badMethod), timeout = 30.seconds) - assertTrue(sinks.isNotEmpty()) - val sink = sinks.first() - val graph = manager.vulnerabilityTraceGraph(sink) - val trace = graph.getAllTraces().first() - assertTrue(trace.isNotEmpty()) - val sarif = sarifReportFromVulnerabilities(listOf(sink.toSarif(graph))) - val sarifJson = myJson.encodeToString(sarif) - logger.info { "SARIF:\n$sarifJson" } - } -} - -class IfdsSqlSqlTest : IfdsSqlTest() { - companion object : WithDB(Usages, InMemoryHierarchy) -} - -class IfdsSqlRAMTest : IfdsSqlTest() { - companion object : WithRAMDB(Usages, InMemoryHierarchy) -} diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsTaintTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsTaintTest.kt deleted file mode 100644 index 4531d690a..000000000 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsTaintTest.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.impl - -import org.jacodb.analysis.ifds.SingletonUnitResolver -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.taint.TaintVulnerability -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.ext.findClass -import org.jacodb.testing.analysis.TaintExamples -import org.junit.jupiter.api.Test -import kotlin.test.assertTrue -import kotlin.time.Duration.Companion.seconds - -private val logger = mu.KotlinLogging.logger {} - -class IfdsTaintTest : BaseAnalysisTest() { - - @Test - fun `analyze simple taint on bad method`() { - testOneMethod("bad") - } - - private fun findSinks(method: JcMethod): List> { - val unitResolver = SingletonUnitResolver - val manager = TaintManager(graph, unitResolver) - return manager.analyze(listOf(method), timeout = 3000.seconds) - } - - private inline fun testOneMethod(methodName: String) { - val method = cp.findClass().declaredMethods.single { it.name == methodName } - val sinks = findSinks(method) - logger.info { "Sinks: ${sinks.size}" } - for ((i, sink) in sinks.withIndex()) { - logger.info { "[${i + 1}/${sinks.size}]: ${sink.sink}" } - } - assertTrue(sinks.isNotEmpty()) - } -} diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUntrustedLoopBoundTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUntrustedLoopBoundTest.kt deleted file mode 100644 index 2c23c22e4..000000000 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUntrustedLoopBoundTest.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.impl - -import kotlinx.coroutines.runBlocking -import mu.KotlinLogging -import org.jacodb.analysis.ifds.SingletonUnitResolver -import org.jacodb.analysis.taint.TaintAnalysisOptions -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.util.JcTraits -import org.jacodb.api.jvm.JcClasspath -import org.jacodb.api.jvm.ext.findClass -import org.jacodb.impl.features.InMemoryHierarchy -import org.jacodb.impl.features.Usages -import org.jacodb.taint.configuration.TaintConfigurationFeature -import org.jacodb.testing.WithDB -import org.jacodb.testing.allClasspath -import org.jacodb.testing.analysis.UntrustedLoopBound -import org.junit.jupiter.api.Test -import kotlin.test.assertTrue -import kotlin.time.Duration.Companion.seconds - -private val logger = KotlinLogging.logger {} - -class Ifds2UpperBoundTest : BaseAnalysisTest() { - - companion object : WithDB(Usages, InMemoryHierarchy) - - override val cp: JcClasspath = runBlocking { - val defaultConfigResource = this.javaClass.getResourceAsStream("/config_untrusted_loop_bound.json") - if (defaultConfigResource != null) { - val configJson = defaultConfigResource.bufferedReader().readText() - val configurationFeature = TaintConfigurationFeature.fromJson(configJson) - db.classpath(allClasspath, listOf(configurationFeature) + classpathFeatures) - } else { - super.cp - } - }.also { - JcTraits.cp = it - } - - @Test - fun `analyze untrusted upper bound`() { - TaintAnalysisOptions.UNTRUSTED_LOOP_BOUND_SINK = true - testOneMethod("handle") - } - - private inline fun testOneMethod(methodName: String) { - val method = cp.findClass().declaredMethods.single { it.name == methodName } - val unitResolver = SingletonUnitResolver - val manager = TaintManager(graph, unitResolver) - val sinks = manager.analyze(listOf(method), timeout = 60.seconds) - logger.info { "Sinks: ${sinks.size}" } - for (sink in sinks) { - logger.info { sink } - } - assertTrue(sinks.isNotEmpty()) - } -} diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt deleted file mode 100644 index ca17c3a28..000000000 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.impl - -import org.jacodb.analysis.ifds.SingletonUnitResolver -import org.jacodb.analysis.unused.UnusedVariableManager -import org.jacodb.api.jvm.ext.findClass -import org.jacodb.api.jvm.ext.methods -import org.jacodb.impl.features.InMemoryHierarchy -import org.jacodb.impl.features.Usages -import org.jacodb.testing.WithDB -import org.jacodb.testing.WithRAMDB -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.MethodSource -import java.util.stream.Stream -import kotlin.time.Duration.Companion.seconds - -abstract class IfdsUnusedTest : BaseAnalysisTest() { - - companion object { - @JvmStatic - fun provideClassesForJuliet563(): Stream = provideClassesForJuliet( - 563, listOf( - // Unused variables are already optimized out by cfg - "unused_uninit_variable_", - "unused_init_variable_int", - "unused_init_variable_long", - "unused_init_variable_String_", - - // Unused variable is generated by cfg (!!) - "unused_value_StringBuilder_17", - - // Expected answers are strange, seems to be problem in tests - "_12", - - // The variable isn't expected to be detected as unused actually - "_81" - ) - ) - } - - @Disabled("#220") - @ParameterizedTest - @MethodSource("provideClassesForJuliet563") - fun `test on Juliet's CWE 563`(className: String) { - testSingleJulietClass(className) { method -> - val unitResolver = SingletonUnitResolver - val manager = UnusedVariableManager(graph, unitResolver) - manager.analyze(listOf(method), timeout = 30.seconds) - } - } - - @Test - fun `test on specific Juliet instance`() { - val className = - "juliet.testcases.CWE563_Unused_Variable.CWE563_Unused_Variable__unused_init_variable_StringBuilder_01" - val clazz = cp.findClass(className) - val badMethod = clazz.methods.single { it.name == "bad" } - val unitResolver = SingletonUnitResolver - val manager = UnusedVariableManager(graph, unitResolver) - val sinks = manager.analyze(listOf(badMethod), timeout = 30.seconds) - Assertions.assertTrue(sinks.isNotEmpty()) - } -} - - -class IfdsUnusedSqlTest : IfdsUnusedTest() { - - companion object : WithDB(Usages, InMemoryHierarchy) -} - -class IfdsUnusedRAMTest : IfdsUnusedTest() { - - companion object : WithRAMDB(Usages, InMemoryHierarchy) -} diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt deleted file mode 100644 index a5a1f50af..000000000 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.impl - -import kotlinx.coroutines.runBlocking -import org.jacodb.analysis.ifds.SingletonUnitResolver -import org.jacodb.analysis.npe.NpeManager -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.unused.UnusedVariableManager -import org.jacodb.analysis.util.JcTraits -import org.jacodb.api.jvm.JcClasspath -import org.jacodb.api.jvm.ext.findClass -import org.jacodb.taint.configuration.TaintConfigurationFeature -import org.jacodb.testing.WithGlobalDB -import org.jacodb.testing.allClasspath -import org.joda.time.DateTime -import org.junit.jupiter.api.Test -import kotlin.time.Duration.Companion.seconds - -private val logger = mu.KotlinLogging.logger {} - -class JodaDateTimeAnalysisTest : BaseAnalysisTest() { - - companion object : WithGlobalDB() - - override val cp: JcClasspath = runBlocking { - val configFileName = "config_small.json" - val configResource = this.javaClass.getResourceAsStream("/$configFileName") - if (configResource != null) { - val configJson = configResource.bufferedReader().readText() - val configurationFeature = TaintConfigurationFeature.fromJson(configJson) - db.classpath(allClasspath, listOf(configurationFeature) + classpathFeatures) - } else { - super.cp - } - }.also { - JcTraits.cp = it - } - - @Test - fun `test taint analysis`() { - val clazz = cp.findClass() - val methods = clazz.declaredMethods - val unitResolver = SingletonUnitResolver - val manager = TaintManager(graph, unitResolver) - val sinks = manager.analyze(methods, timeout = 60.seconds) - logger.info { "Vulnerabilities found: ${sinks.size}" } - } - - @Test - fun `test NPE analysis`() { - val clazz = cp.findClass() - val methods = clazz.declaredMethods - val unitResolver = SingletonUnitResolver - val manager = NpeManager(graph, unitResolver) - val sinks = manager.analyze(methods, timeout = 60.seconds) - logger.info { "Vulnerabilities found: ${sinks.size}" } - } - - @Test - fun `test unused variables analysis`() { - val clazz = cp.findClass() - val methods = clazz.declaredMethods - val unitResolver = SingletonUnitResolver - val manager = UnusedVariableManager(graph, unitResolver) - val sinks = manager.analyze(methods, timeout = 60.seconds) - logger.info { "Unused variables found: ${sinks.size}" } - } -} diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/NullabilityAssumptionAnalysisTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/NullabilityAssumptionAnalysisTest.kt deleted file mode 100644 index d854b2585..000000000 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/NullabilityAssumptionAnalysisTest.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.impl - -import org.jacodb.analysis.impl.custom.NullAssumptionAnalysis -import org.jacodb.api.jvm.JcClassOrInterface -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.cfg.JcAssignInst -import org.jacodb.api.jvm.cfg.JcInstanceCallExpr -import org.jacodb.api.jvm.cfg.JcLocal -import org.jacodb.api.jvm.ext.findClass -import org.jacodb.testing.BaseTest -import org.jacodb.testing.WithGlobalDB -import org.jacodb.testing.cfg.NullAssumptionAnalysisExample -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.Test - -class NullabilityAssumptionAnalysisTest : BaseTest() { - - companion object : WithGlobalDB() - - @Test - fun `null-assumption analysis should work`() { - val clazz = cp.findClass() - with(clazz.findMethod("test1").flowGraph()) { - val analysis = NullAssumptionAnalysis(this).also { - it.run() - } - val sout = (instructions[0] as JcAssignInst).lhv as JcLocal - val a = ((instructions[3] as JcAssignInst).rhv as JcInstanceCallExpr).instance - - assertTrue(analysis.isAssumedNonNullBefore(instructions[2], a)) - assertTrue(analysis.isAssumedNonNullBefore(instructions[0], sout)) - } - } - - @Test - fun `null-assumption analysis should work 2`() { - val clazz = cp.findClass() - with(clazz.findMethod("test2").flowGraph()) { - val analysis = NullAssumptionAnalysis(this).also { - it.run() - } - val sout = (instructions[0] as JcAssignInst).lhv as JcLocal - val a = ((instructions[3] as JcAssignInst).rhv as JcInstanceCallExpr).instance - val x = (instructions[5] as JcAssignInst).lhv as JcLocal - - assertTrue(analysis.isAssumedNonNullBefore(instructions[2], a)) - assertTrue(analysis.isAssumedNonNullBefore(instructions[0], sout)) - analysis.isAssumedNonNullBefore(instructions[5], x) - } - } - - private fun JcClassOrInterface.findMethod(name: String): JcMethod = declaredMethods.first { it.name == name } - -} diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt deleted file mode 100644 index f890d8e9f..000000000 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.analysis.impl - -import io.mockk.every -import io.mockk.mockk -import kotlinx.coroutines.runBlocking -import org.jacodb.analysis.taint.ForwardTaintFlowFunctions -import org.jacodb.analysis.taint.TaintZeroFact -import org.jacodb.analysis.taint.Tainted -import org.jacodb.analysis.util.JcTraits -import org.jacodb.api.jvm.JcClassType -import org.jacodb.api.jvm.JcClasspath -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.analysis.JcApplicationGraph -import org.jacodb.api.jvm.cfg.JcArgument -import org.jacodb.api.jvm.cfg.JcAssignInst -import org.jacodb.api.jvm.cfg.JcCallExpr -import org.jacodb.api.jvm.cfg.JcCallInst -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.api.jvm.cfg.JcLocal -import org.jacodb.api.jvm.cfg.JcLocalVar -import org.jacodb.api.jvm.cfg.JcReturnInst -import org.jacodb.api.jvm.ext.cfg.callExpr -import org.jacodb.api.jvm.ext.findTypeOrNull -import org.jacodb.api.jvm.ext.packageName -import org.jacodb.impl.features.InMemoryHierarchy -import org.jacodb.impl.features.Usages -import org.jacodb.taint.configuration.TaintConfigurationFeature -import org.jacodb.taint.configuration.TaintMark -import org.jacodb.testing.BaseTest -import org.jacodb.testing.WithDB -import org.jacodb.testing.WithRAMDB -import org.jacodb.testing.allClasspath -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test - -open class TaintFlowFunctionsTest : BaseTest() { - - companion object : WithDB(Usages, InMemoryHierarchy), JcTraits - - override val cp: JcClasspath = runBlocking { - val configFileName = "config_test.json" - val configResource = this.javaClass.getResourceAsStream("/$configFileName") - if (configResource != null) { - val configJson = configResource.bufferedReader().readText() - val configurationFeature = TaintConfigurationFeature.fromJson(configJson) - db.classpath(allClasspath, listOf(configurationFeature) + classpathFeatures) - } else { - super.cp - } - }.also { - JcTraits.cp = it - } - - private val graph: JcApplicationGraph = mockk { - every { cp } returns this@TaintFlowFunctionsTest.cp - every { callees(any()) } answers { - sequenceOf(arg(0).callExpr!!.callee) - } - every { methodOf(any()) } answers { - arg(0).location.method - } - } - - private val stringType = cp.findTypeOrNull() as JcClassType - - private val testMethod = mockk { - every { name } returns "test" - every { enclosingClass } returns mockk(relaxed = true) { - every { packageName } returns "com.example" - every { simpleName } returns "Example" - every { name } returns "com.example.Example" - every { superClass } returns null - every { interfaces } returns emptyList() - } - every { isConstructor } returns false - every { returnType } returns mockk(relaxed = true) - every { parameters } returns listOf( - mockk(relaxed = true) { - every { index } returns 0 - every { type } returns mockk { - every { typeName } returns "java.lang.String" - } - } - ) - } - - @Test - fun `test obtain start facts`() { - val flowSpace = ForwardTaintFlowFunctions(graph) - val facts = flowSpace.obtainPossibleStartFacts(testMethod).toList() - val arg0 = getArgument(testMethod.parameters[0])!! - val arg0Taint = Tainted(arg0.toPath(), TaintMark("EXAMPLE")) - Assertions.assertEquals(listOf(TaintZeroFact, arg0Taint), facts) - } - - @Test - fun `test sequential flow function assign mark`() { - // "x := y", where 'y' is tainted, should result in both 'x' and 'y' to be tainted - val x: JcLocal = JcLocalVar(1, "x", stringType) - val y: JcLocal = JcLocalVar(2, "y", stringType) - val inst = JcAssignInst(location = mockk(), lhv = x, rhv = y) - val flowSpace = ForwardTaintFlowFunctions(graph) - val f = flowSpace.obtainSequentFlowFunction(inst, next = mockk()) - val yTaint = Tainted(y.toPath(), TaintMark("TAINT")) - val xTaint = Tainted(x.toPath(), TaintMark("TAINT")) - val facts = f.compute(yTaint).toList() - Assertions.assertEquals(listOf(yTaint, xTaint), facts) - } - - @Test - fun `test call flow function assign mark`() { - // "x := test(...)", where 'test' is a source, should result in 'x' to be tainted - val x: JcLocal = JcLocalVar(1, "x", stringType) - val callStatement = JcAssignInst(location = mockk(), lhv = x, rhv = mockk { - every { method.method } returns testMethod - }) - val flowSpace = ForwardTaintFlowFunctions(graph) - val f = flowSpace.obtainCallToReturnSiteFlowFunction(callStatement, returnSite = mockk()) - val xTaint = Tainted(x.toPath(), TaintMark("EXAMPLE")) - val facts = f.compute(TaintZeroFact).toList() - Assertions.assertEquals(listOf(TaintZeroFact, xTaint), facts) - } - - @Test - fun `test call flow function remove mark`() { - // "test(x)", where 'x' is tainted, should result in 'x' NOT to be tainted - val x: JcLocal = JcLocalVar(1, "x", stringType) - val callStatement = JcCallInst(location = mockk(), callExpr = mockk { - every { method.method } returns testMethod - every { args } returns listOf(x) - }) - val flowSpace = ForwardTaintFlowFunctions(graph) - val f = flowSpace.obtainCallToReturnSiteFlowFunction(callStatement, returnSite = mockk()) - val xTaint = Tainted(x.toPath(), TaintMark("REMOVE")) - val facts = f.compute(xTaint).toList() - Assertions.assertTrue(facts.isEmpty()) - } - - @Test - fun `test call flow function copy mark`() { - // "y := test(x)" should result in 'y' to be tainted only when 'x' is tainted - val x: JcLocal = JcLocalVar(1, "x", stringType) - val y: JcLocal = JcLocalVar(2, "y", stringType) - val callStatement = JcAssignInst(location = mockk(), lhv = y, rhv = mockk { - every { method.method } returns testMethod - every { args } returns listOf(x) - }) - val flowSpace = ForwardTaintFlowFunctions(graph) - val f = flowSpace.obtainCallToReturnSiteFlowFunction(callStatement, returnSite = mockk()) - val xTaint = Tainted(x.toPath(), TaintMark("COPY")) - val yTaint = Tainted(y.toPath(), TaintMark("COPY")) - val facts = f.compute(xTaint).toList() - Assertions.assertEquals(listOf(xTaint, yTaint), facts) // copy from x to y - val other: JcLocal = JcLocalVar(10, "other", stringType) - val otherTaint = Tainted(other.toPath(), TaintMark("OTHER")) - val facts2 = f.compute(otherTaint).toList() - Assertions.assertEquals(listOf(otherTaint), facts2) // pass-through - } - - @Test - fun `test call to start flow function`() { - // "test(x)", where 'x' is tainted, should result in 'x' (formal argument of 'test') to be tainted - val x: JcLocal = JcLocalVar(1, "x", stringType) - val callStatement = JcCallInst(location = mockk(), callExpr = mockk { - every { method.method } returns testMethod - every { args } returns listOf(x) - }) - val flowSpace = ForwardTaintFlowFunctions(graph) - val f = flowSpace.obtainCallToStartFlowFunction(callStatement, calleeStart = mockk { - every { location } returns mockk { - every { method } returns testMethod - } - }) - val xTaint = Tainted(x.toPath(), TaintMark("TAINT")) - val arg0: JcArgument = getArgument(testMethod.parameters[0])!! - val arg0Taint = Tainted(arg0.toPath(), TaintMark("TAINT")) - val facts = f.compute(xTaint).toList() - Assertions.assertEquals(listOf(arg0Taint), facts) - val other: JcLocal = JcLocalVar(10, "other", stringType) - val otherTaint = Tainted(other.toPath(), TaintMark("TAINT")) - val facts2 = f.compute(otherTaint).toList() - Assertions.assertTrue(facts2.isEmpty()) - } - - @Test - fun `test exit flow function`() { - // "x := test()" + "return y", where 'y' is tainted, should result in 'x' to be tainted - val x: JcLocal = JcLocalVar(1, "x", stringType) - val callStatement = JcAssignInst(location = mockk(), lhv = x, rhv = mockk { - every { method.method } returns testMethod - }) - val y: JcLocal = JcLocalVar(1, "y", stringType) - val exitStatement = JcReturnInst(location = mockk { - every { method } returns testMethod - }, returnValue = y) - val flowSpace = ForwardTaintFlowFunctions(graph) - val f = flowSpace.obtainExitToReturnSiteFlowFunction(callStatement, returnSite = mockk(), exitStatement) - val yTaint = Tainted(y.toPath(), TaintMark("TAINT")) - val xTaint = Tainted(x.toPath(), TaintMark("TAINT")) - val facts = f.compute(yTaint).toList() - Assertions.assertEquals(listOf(xTaint), facts) - } -} - -class TaintFlowFunctionsRAMTest : TaintFlowFunctionsTest() { - - companion object : WithRAMDB(Usages, InMemoryHierarchy) -} diff --git a/jacodb-analysis/src/test/resources/additional.json b/jacodb-analysis/src/test/resources/additional.json deleted file mode 100644 index 4c883436e..000000000 --- a/jacodb-analysis/src/test/resources/additional.json +++ /dev/null @@ -1,607 +0,0 @@ -[ - { - "_": "EntryPointSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameMatches", - "pattern": ".*" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": ".*" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": ".*" - }, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": false, - "functionLabel": null, - "modifier": -1, - "exclude": [] - }, - "condition": { - "_": "AnnotationType", - "position": { - "_": "Argument", - "number": 0 - }, - "type": { - "_": "ClassMatcher", - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "org.springframework.web.bind.annotation" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "RequestParam" - } - } - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Argument", - "number": 0 - }, - "mark": { - "name": "XSS" - } - } - ] - }, - { - "_": "EntryPointSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameMatches", - "pattern": ".*" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": ".*" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": ".*" - }, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": false, - "functionLabel": null, - "modifier": -1, - "exclude": [] - }, - "condition": { - "_": "AnnotationType", - "position": { - "_": "Argument", - "number": 1 - }, - "type": { - "_": "ClassMatcher", - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "org.springframework.web.bind.annotation" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "RequestParam" - } - } - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Argument", - "number": 1 - }, - "mark": { - "name": "XSS" - } - } - ] - }, - { - "_": "EntryPointSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameMatches", - "pattern": ".*" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": ".*" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": ".*" - }, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": false, - "functionLabel": null, - "modifier": -1, - "exclude": [] - }, - "condition": { - "_": "AnnotationType", - "position": { - "_": "Argument", - "number": 2 - }, - "type": { - "_": "ClassMatcher", - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "org.springframework.web.bind.annotation" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "RequestParam" - } - } - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Argument", - "number": 2 - }, - "mark": { - "name": "XSS" - } - } - ] - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.net" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "URLDecoder" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "decode" - }, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyAllMarks", - "from": { - "_": "Argument", - "number": 0 - }, - "to": { - "_": "Result" - } - } - ] - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.sql" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "Connection" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "prepareCall|prepareStatement" - }, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyAllMarks", - "from": { - "_": "Argument", - "number": 0 - }, - "to": { - "_": "Result" - } - } - ] - }, - { - "_": "MethodSink", - "ruleNote": "SQL Injection", - "cwe": [ - 89 - ], - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.sql" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": "PreparedStatement" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "execute|executeQuery|executeUpdate|executeLargeUpdate" - }, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [] - }, - "condition": { - "_": "Or", - "args": [ - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "NETWORK" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "ARGS" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "LDAP" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "FORM" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "WEBSERVICE" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "PROPERTY" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "ENVIRONMENT" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "ICC" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "STREAM" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "FILE_SYSTEM" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "JSON" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "STDIN" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "DATABASE" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "CHANNEL" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "WEB" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "CONSOLE" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "XML" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "XSS" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "GUI_FORM" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "NAMING" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "REGISTRY" - } - } - ] - } - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.util" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "Map" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "get" - }, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyAllMarks", - "from": { - "_": "This" - }, - "to": { - "_": "Result" - } - } - ] - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.util" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "Map" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "put|replace" - }, - "applyToOverrides": true, - "exclude": [], - "functionLabel": null, - "modifier": -1, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - } - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyAllMarks", - "from": { - "_": "Argument", - "number": 1 - }, - "to": { - "_": "This" - } - } - ] - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "Base64" - }, - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "org.apache.commons.codec.binary" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "decodeBase64" - }, - "applyToOverrides": true, - "exclude": [], - "functionLabel": null, - "modifier": -1, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - } - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyAllMarks", - "from": { - "_": "Argument", - "number": 0 - }, - "to": { - "_": "Result" - } - } - ] - } -] diff --git a/jacodb-analysis/src/test/resources/config_small.json b/jacodb-analysis/src/test/resources/config_small.json deleted file mode 100644 index ddbf34757..000000000 --- a/jacodb-analysis/src/test/resources/config_small.json +++ /dev/null @@ -1,789 +0,0 @@ -[ - { - "_": "MethodSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.lang" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "System" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "getenv" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Result" - }, - "mark": { - "name": "ENVIRONMENT" - } - } - ] - }, - { - "_": "MethodSink", - "ruleNote": "SQL Injection", - "cwe": [ - 89 - ], - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.sql" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": "Statement" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "execute|executeQuery|executeUpdate|executeLargeUpdate" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "Or", - "args": [ - { - "_": "ContainsMark", - "position": { - "_": "Argument", - "number": 0 - }, - "mark": { - "name": "UNTRUSTED" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "Argument", - "number": 0 - }, - "mark": { - "name": "INJECTION" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "Argument", - "number": 0 - }, - "mark": { - "name": "ENVIRONMENT" - } - } - ] - } - }, - { - "_": "MethodSink", - "ruleNote": "SQL Injection", - "cwe": [ - 89 - ], - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.sql" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": "Statement" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "executeBatch|executeLargeBatch" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "Or", - "args": [ - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "UNTRUSTED" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "INJECTION" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "ENVIRONMENT" - } - } - ] - } - }, - { - "_": "MethodSink", - "ruleNote": "SQL Injection", - "cwe": [ - 89 - ], - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.sql" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": "PreparedStatement" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "execute|executeQuery|executeUpdate|executeLargeUpdate" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "Or", - "args": [ - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "UNTRUSTED" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "INJECTION" - } - }, - { - "_": "ContainsMark", - "position": { - "_": "This" - }, - "mark": { - "name": "ENVIRONMENT" - } - } - ] - } - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.lang" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "String" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "split" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyAllMarks", - "from": { - "_": "This" - }, - "to": { - "_": "ResultAnyElement" - } - } - ] - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.lang" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "String" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "concat" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyAllMarks", - "from": { - "_": "Argument", - "number": 0 - }, - "to": { - "_": "Result" - } - }, - { - "_": "CopyAllMarks", - "from": { - "_": "This" - }, - "to": { - "_": "Result" - } - } - ] - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.lang" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "StringBuilder" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "append" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyAllMarks", - "from": { - "_": "Argument", - "number": 0 - }, - "to": { - "_": "This" - } - }, - { - "_": "CopyAllMarks", - "from": { - "_": "Argument", - "number": 0 - }, - "to": { - "_": "Result" - } - }, - { - "_": "CopyAllMarks", - "from": { - "_": "This" - }, - "to": { - "_": "Result" - } - } - ] - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.lang" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "StringBuilder" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "toString" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyAllMarks", - "from": { - "_": "This" - }, - "to": { - "_": "Result" - } - } - ] - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.sql" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "Statement" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "addBatch" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyAllMarks", - "from": { - "_": "Argument", - "number": 0 - }, - "to": { - "_": "This" - } - } - ] - }, - { - "_": "MethodSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.sql" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "ResultSet" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "get.*" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Result" - }, - "mark": { - "name": "UNTRUSTED" - } - } - ] - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.sql" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "Connection" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "prepareStatement" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyAllMarks", - "from": { - "_": "Argument", - "number": 0 - }, - "to": { - "_": "Result" - } - } - ] - }, - { - "_": "MethodSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.io" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "BufferedReader" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "readLine" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Result" - }, - "mark": { - "name": "UNTRUSTED" - } - } - ] - }, - { - "_": "MethodSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.util" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "Properties" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "getProperty" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Result" - }, - "mark": { - "name": "NULLNESS" - } - } - ] - }, - { - "_": "MethodSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "java.lang" - }, - "classNameMatcher": { - "_": "NameIsEqualTo", - "name": "System" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "getProperty" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Result" - }, - "mark": { - "name": "NULLNESS" - } - } - ] - }, - { - "_": "MethodSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameMatches", - "pattern": ".*" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": ".*" - } - }, - "functionName": { - "_": "NameIsEqualTo", - "name": "source" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Result" - }, - "mark": { - "name": "DEBUG" - } - } - ] - }, - { - "_": "MethodSink", - "ruleNote": "DEBUG", - "cwe": [], - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameMatches", - "pattern": ".*" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": ".*" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "sink" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ContainsMark", - "position": { - "_": "Argument", - "number": 0 - }, - "mark": { - "name": "DEBUG" - } - } - } -] diff --git a/jacodb-analysis/src/test/resources/config_test.json b/jacodb-analysis/src/test/resources/config_test.json deleted file mode 100644 index 86260231e..000000000 --- a/jacodb-analysis/src/test/resources/config_test.json +++ /dev/null @@ -1,174 +0,0 @@ -[ - { - "_": "EntryPointSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "com.example" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": ".*" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "test" - }, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": false, - "functionLabel": null, - "modifier": -1, - "exclude": [] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Argument", - "number": 0 - }, - "mark": { - "name": "EXAMPLE" - } - } - ] - }, - { - "_": "MethodSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "com.example" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": ".*" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "test" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Result" - }, - "mark": { - "name": "EXAMPLE" - } - } - ] - }, - { - "_": "Cleaner", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "com.example" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": ".*" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "test" - }, - "applyToOverrides": true, - "exclude": [], - "functionLabel": null, - "modifier": -1, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - } - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "RemoveMark", - "mark": { - "name": "REMOVE" - }, - "position": { - "_": "Argument", - "number": 0 - } - } - ] - }, - { - "_": "PassThrough", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameIsEqualTo", - "name": "com.example" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": ".*" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "test" - }, - "applyToOverrides": true, - "exclude": [], - "functionLabel": null, - "modifier": -1, - "parametersMatchers": [], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - } - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "CopyMark", - "mark": { - "name": "COPY" - }, - "from": { - "_": "Argument", - "number": 0 - }, - "to": { - "_": "Result" - } - } - ] - } -] diff --git a/jacodb-analysis/src/test/resources/config_untrusted_loop_bound.json b/jacodb-analysis/src/test/resources/config_untrusted_loop_bound.json deleted file mode 100644 index f2f31b240..000000000 --- a/jacodb-analysis/src/test/resources/config_untrusted_loop_bound.json +++ /dev/null @@ -1,45 +0,0 @@ -[ - { - "_": "MethodSource", - "methodInfo": { - "cls": { - "packageMatcher": { - "_": "NameMatches", - "pattern": ".*" - }, - "classNameMatcher": { - "_": "NameMatches", - "pattern": ".*Message" - } - }, - "functionName": { - "_": "NameMatches", - "pattern": "readInt" - }, - "parametersMatchers": [ - ], - "returnTypeMatcher": { - "_": "AnyTypeMatches" - }, - "applyToOverrides": true, - "functionLabel": null, - "modifier": -1, - "exclude": [ - ] - }, - "condition": { - "_": "ConstantTrue" - }, - "actionsAfter": [ - { - "_": "AssignMark", - "position": { - "_": "Result" - }, - "mark": { - "name": "UNTRUSTED" - } - } - ] - } -] diff --git a/jacodb-analysis/src/test/resources/pointerbench.jar b/jacodb-analysis/src/test/resources/pointerbench.jar deleted file mode 100644 index 7595762c0..000000000 Binary files a/jacodb-analysis/src/test/resources/pointerbench.jar and /dev/null differ diff --git a/jacodb-analysis/src/test/resources/simplelogger.properties b/jacodb-analysis/src/test/resources/simplelogger.properties deleted file mode 100644 index de8ce921f..000000000 --- a/jacodb-analysis/src/test/resources/simplelogger.properties +++ /dev/null @@ -1,34 +0,0 @@ -# SLF4J's SimpleLogger configuration file -# Simple implementation of Logger that sends all enabled log messages, for all defined loggers, to System.err. - -# Default logging detail level for all instances of SimpleLogger. -# Must be one of ("trace", "debug", "info", "warn", or "error"). -# If not specified, defaults to "info". -org.slf4j.simpleLogger.defaultLogLevel=info - -# Logging detail level for a SimpleLogger instance named "xxxxx". -# Must be one of ("trace", "debug", "info", "warn", or "error"). -# If not specified, the default logging detail level is used. -org.slf4j.simpleLogger.log.org.jacodb.analysis.ifds=debug - -# Set to true if you want the current date and time to be included in output messages. -# Default is false, and will output the number of milliseconds elapsed since startup. -org.slf4j.simpleLogger.showDateTime=true - -# The date and time format to be used in the output messages. -# The pattern describing the date and time format is the same that is used in java.text.SimpleDateFormat. -# If the format is not specified or is invalid, the default format is used. -# The default format is yyyy-MM-dd HH:mm:ss:SSS Z. -org.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss - -# Set to true if you want to output the current thread name. -# Defaults to true. -org.slf4j.simpleLogger.showThreadName=false - -# Set to true if you want the Logger instance name to be included in output messages. -# Defaults to true. -org.slf4j.simpleLogger.showLogName=true - -# Set to true if you want the last component of the name to be included in output messages. -# Defaults to false. -org.slf4j.simpleLogger.showShortLogName=true diff --git a/jacodb-cli/build.gradle.kts b/jacodb-cli/build.gradle.kts deleted file mode 100644 index f308337c3..000000000 --- a/jacodb-cli/build.gradle.kts +++ /dev/null @@ -1,15 +0,0 @@ -plugins { - kotlin("plugin.serialization") -} - -dependencies { - api(project(":jacodb-api-jvm")) - api(project(":jacodb-core")) - api(project(":jacodb-analysis")) - - implementation(Libs.kotlin_logging) - implementation(Libs.kotlinx_cli) - implementation(Libs.kotlinx_serialization_json) - - testImplementation(testFixtures(project(":jacodb-core"))) -} diff --git a/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt b/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt deleted file mode 100644 index 7591cbc26..000000000 --- a/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.cli - -import kotlinx.cli.ArgParser -import kotlinx.cli.ArgType -import kotlinx.cli.default -import kotlinx.cli.required -import kotlinx.coroutines.runBlocking -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.Serializable -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.encodeToStream -import org.jacodb.analysis.graph.newApplicationGraphForAnalysis -import org.jacodb.analysis.ifds.SingletonUnitResolver -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.npe.NpeManager -import org.jacodb.analysis.sarif.VulnerabilityInstance -import org.jacodb.analysis.sarif.sarifReportFromVulnerabilities -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.taint.toSarif -import org.jacodb.analysis.unused.UnusedVariableManager -import org.jacodb.analysis.unused.toSarif -import org.jacodb.analysis.util.JcTraits -import org.jacodb.api.jvm.JcClassOrInterface -import org.jacodb.api.jvm.JcClassProcessingTask -import org.jacodb.api.jvm.JcMethod -import org.jacodb.api.jvm.analysis.JcApplicationGraph -import org.jacodb.api.jvm.cfg.JcInst -import org.jacodb.impl.features.InMemoryHierarchy -import org.jacodb.impl.features.Usages -import org.jacodb.impl.jacodb -import java.io.File -import java.util.concurrent.ConcurrentHashMap -import kotlin.time.Duration.Companion.seconds - -private val logger = mu.KotlinLogging.logger {} - -class AnalysisMain { - fun run(args: List) = main(args.toTypedArray()) -} - -typealias AnalysesOptions = Map - -@Serializable -data class AnalysisConfig(val analyses: Map) - -fun launchAnalysesByConfig( - config: AnalysisConfig, - graph: JcApplicationGraph, - methods: List, -): List>> = with(JcTraits) { - return config.analyses.mapNotNull { (analysis, options) -> - val unitResolver = options["UnitResolver"]?.let { - UnitResolver.getByName(it) - } ?: SingletonUnitResolver - - when (analysis) { - "NPE" -> { - val manager = NpeManager(graph, unitResolver) - manager.analyze(methods, timeout = 60.seconds).map { it.toSarif(manager.vulnerabilityTraceGraph(it)) } - } - - "Unused" -> { - val manager = UnusedVariableManager(graph, unitResolver) - manager.analyze(methods, timeout = 60.seconds).map { it.toSarif() } - } - - "SQL" -> { - val manager = TaintManager(graph, unitResolver) - manager.analyze(methods, timeout = 60.seconds).map { it.toSarif(manager.vulnerabilityTraceGraph(it)) } - } - - else -> { - logger.error { "Unknown analysis type: $analysis" } - return@mapNotNull null - } - } - } -} - -@OptIn(ExperimentalSerializationApi::class) -fun main(args: Array) { - val parser = ArgParser("taint-analysis") - val configFilePath by parser.option( - ArgType.String, - fullName = "analysisConf", - shortName = "a", - description = "File with analysis configuration in JSON format" - ).required() - val dbLocation by parser.option( - ArgType.String, - fullName = "dbLocation", - shortName = "l", - description = "Location of SQLite database for storing bytecode data" - ) - val startClasses by parser.option( - ArgType.String, - fullName = "start", - shortName = "s", - description = "classes from which to start the analysis" - ).required() - val outputPath by parser.option( - ArgType.String, - fullName = "output", - shortName = "o", - description = "File where analysis report (in SARIF format) will be written. File will be created if not exists. Existing file will be overwritten." - ).default("report.sarif") - val classpath by parser.option( - ArgType.String, - fullName = "classpath", - shortName = "cp", - description = "Classpath for analysis. Used by JacoDB." - ).default(System.getProperty("java.class.path")) - - parser.parse(args) - - val outputFile = File(outputPath) - - if (outputFile.exists() && outputFile.isDirectory) { - throw IllegalArgumentException("Provided path for output file is directory, please provide correct path") - } else if (outputFile.exists()) { - logger.info { "Output file $outputFile already exists, results will be overwritten" } - } - - val configFile = File(configFilePath) - if (!configFile.isFile) { - throw IllegalArgumentException("Can't find provided config file $configFilePath") - } - val config = Json.decodeFromString(configFile.readText()) - - val classpathAsFiles = classpath.split(File.pathSeparatorChar).sorted().map { File(it) } - - val cp = runBlocking { - val jacodb = jacodb { - loadByteCode(classpathAsFiles) - dbLocation?.let { - persistent(it) - } - installFeatures(InMemoryHierarchy, Usages) - } - jacodb.classpath(classpathAsFiles) - } - JcTraits.cp = cp - - val startClassesAsList = startClasses.split(";") - val startJcClasses = ConcurrentHashMap.newKeySet() - cp.executeAsync(object : JcClassProcessingTask { - override fun process(clazz: JcClassOrInterface) { - if (startClassesAsList.any { clazz.name.startsWith(it) }) { - startJcClasses.add(clazz) - } - } - }).get() - val startJcMethods = startJcClasses.flatMap { it.declaredMethods }.filter { !it.isPrivate } - - val graph = runBlocking { - cp.newApplicationGraphForAnalysis() - } - - val vulnerabilities = launchAnalysesByConfig(config, graph, startJcMethods).flatten() - val report = sarifReportFromVulnerabilities(vulnerabilities) - val prettyJson = Json { - prettyPrint = true - } - - outputFile.outputStream().use { fileOutputStream -> - prettyJson.encodeToStream(report, fileOutputStream) - } -} diff --git a/jacodb-cli/src/test/kotlin/org/jacodb/cli/CliTest.kt b/jacodb-cli/src/test/kotlin/org/jacodb/cli/CliTest.kt deleted file mode 100644 index 3e9976978..000000000 --- a/jacodb-cli/src/test/kotlin/org/jacodb/cli/CliTest.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.cli - -import org.jacodb.testing.analysis.NpeExamples -import org.junit.jupiter.api.Test - -class CliTest { - @Test - fun `test basic analysis cli api`() { - val args = listOf( - "-a", CliTest::class.java.getResource("/config.json")?.file ?: error("Can't find file with config"), - "-s", NpeExamples::class.java.name - ) - AnalysisMain().run(args) - } -} \ No newline at end of file diff --git a/jacodb-cli/src/test/resources/config.json b/jacodb-cli/src/test/resources/config.json deleted file mode 100644 index 21a1020ab..000000000 --- a/jacodb-cli/src/test/resources/config.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "analyses": { - "NPE": {}, - "Unused": { - "UnitResolver": "class" - }, - "SQL": {} - } -} \ No newline at end of file diff --git a/jacodb-ets/build.gradle.kts b/jacodb-ets/build.gradle.kts index 2d18f61d5..82280243b 100644 --- a/jacodb-ets/build.gradle.kts +++ b/jacodb-ets/build.gradle.kts @@ -14,8 +14,6 @@ dependencies { implementation(Libs.jdot) testImplementation(kotlin("test")) - testImplementation(project(":jacodb-analysis")) - testImplementation(testFixtures(project(":jacodb-core"))) testImplementation(Libs.mockk) } diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/LoadEtsFile.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/LoadEtsFile.kt index 4baf176a8..cb6a057cf 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/LoadEtsFile.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/LoadEtsFile.kt @@ -23,13 +23,10 @@ import java.io.FileNotFoundException import java.nio.file.Path import kotlin.io.path.Path import kotlin.io.path.absolute -import kotlin.io.path.createTempDirectory -import kotlin.io.path.div import kotlin.io.path.exists import kotlin.io.path.inputStream import kotlin.io.path.nameWithoutExtension import kotlin.io.path.pathString -import kotlin.io.path.relativeTo import kotlin.time.Duration.Companion.seconds private const val ENV_VAR_ARK_ANALYZER_DIR = "ARKANALYZER_DIR" diff --git a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsIfds.kt b/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsIfds.kt deleted file mode 100644 index 158659ea0..000000000 --- a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsIfds.kt +++ /dev/null @@ -1,433 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.ets.test - -import org.jacodb.analysis.ifds.SingletonUnit -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.taint.ForwardTaintFlowFunctions -import org.jacodb.analysis.taint.TaintAnalysisOptions -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.util.EtsTraits -import org.jacodb.ets.base.EtsStmt -import org.jacodb.ets.graph.EtsApplicationGraphImpl -import org.jacodb.ets.model.EtsFile -import org.jacodb.ets.model.EtsMethod -import org.jacodb.ets.model.EtsScene -import org.jacodb.ets.test.utils.loadEtsFileFromResource -import org.jacodb.taint.configuration.Argument -import org.jacodb.taint.configuration.AssignMark -import org.jacodb.taint.configuration.ConstantTrue -import org.jacodb.taint.configuration.ContainsMark -import org.jacodb.taint.configuration.CopyAllMarks -import org.jacodb.taint.configuration.RemoveMark -import org.jacodb.taint.configuration.Result -import org.jacodb.taint.configuration.TaintConfigurationItem -import org.jacodb.taint.configuration.TaintMark -import org.jacodb.taint.configuration.TaintMethodSink -import org.jacodb.taint.configuration.TaintMethodSource -import org.jacodb.taint.configuration.TaintPassThrough -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.condition.EnabledIf -import kotlin.io.path.exists -import kotlin.io.path.toPath -import kotlin.time.Duration.Companion.seconds - -private val logger = mu.KotlinLogging.logger {} - -@Disabled("Have several issues with EtsIR") -class EtsIfds { - - companion object : EtsTraits { - private const val BASE_PATH = "/etsir/samples" - - private fun loadSample(programName: String): EtsFile { - return loadEtsFileFromResource("$BASE_PATH/${programName}.ts.json") - } - } - - private fun projectAvailable(): Boolean { - val resource = object {}::class.java.getResource("/samples/source/project1")?.toURI() - return resource != null && resource.toPath().exists() - } - - @Test - fun `test taint analysis on MethodCollision`() { - val file = loadSample("MethodCollision") - val project = EtsScene(listOf(file)) - val graph = EtsApplicationGraphImpl(project) - val unitResolver = UnitResolver { SingletonUnit } - val getConfigForMethod: ForwardTaintFlowFunctions.(EtsMethod) -> List? = - { method -> - val rules = buildList { - if (method.name == "isSame" && method.signature.enclosingClass.name == "Foo") add( - TaintMethodSource( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - AssignMark(mark = TaintMark("TAINT"), position = Result), - ), - ) - ) - if (method.name == "log") add( - TaintMethodSink( - method = method, - ruleNote = "CUSTOM SINK", // FIXME - cwe = listOf(), // FIXME - condition = ContainsMark(position = Argument(0), mark = TaintMark("TAINT")) - ) - ) - } - rules.ifEmpty { null } - } - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = getConfigForMethod, - ) - - val methods = project.classes.flatMap { it.methods }.filter { it.name == "main" } - logger.info { "Methods: ${methods.size}" } - for (method in methods) { - logger.info { " ${method.name}" } - } - val sinks = manager.analyze(methods, timeout = 60.seconds) - logger.info { "Sinks: $sinks" } - Assertions.assertTrue(sinks.isNotEmpty()) - } - - @Test - fun `test taint analysis on TypeMismatch`() { - val file = loadSample("TypeMismatch") - val project = EtsScene(listOf(file)) - val graph = EtsApplicationGraphImpl(project) - val unitResolver = UnitResolver { SingletonUnit } - val getConfigForMethod: ForwardTaintFlowFunctions.(EtsMethod) -> List? = - { method -> - val rules = buildList { - if (method.name == "add") add( - TaintMethodSource( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - AssignMark(mark = TaintMark("TAINT"), position = Result), - ) - ) - ) - if (method.name == "log") add( - TaintMethodSink( - method = method, - ruleNote = "CUSTOM SINK", // FIXME - cwe = listOf(), // FIXME - condition = ContainsMark(position = Argument(1), mark = TaintMark("TAINT")) - ) - ) - } - rules.ifEmpty { null } - } - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = getConfigForMethod, - ) - - val methods = project.classes.flatMap { it.methods } - logger.info { "Methods: ${methods.size}" } - for (method in methods) { - logger.info { " ${method.name}" } - } - val sinks = manager.analyze(methods, timeout = 60.seconds) - logger.info { "Sinks: $sinks" } - Assertions.assertTrue(sinks.isNotEmpty()) - } - - @Disabled("TODO: Sink should be detected in the 'good' method") - @Test - fun `test taint analysis on DataFlowSecurity`() { - val file = loadSample("DataFlowSecurity") - val project = EtsScene(listOf(file)) - val graph = EtsApplicationGraphImpl(project) - val unitResolver = UnitResolver { SingletonUnit } - val getConfigForMethod: ForwardTaintFlowFunctions.(EtsMethod) -> List? = - { method -> - val rules = buildList { - if (method.name == "samples/source") add( - TaintMethodSource( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - AssignMark(mark = TaintMark("TAINT"), position = Result), - ), - ) - ) - if (method.name == "sink") add( - TaintMethodSink( - method = method, - ruleNote = "SINK", // FIXME - cwe = listOf(), // FIXME - condition = ContainsMark(position = Argument(0), mark = TaintMark("TAINT")) - ) - ) - if (method.name == "pass") add( - TaintPassThrough( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - CopyAllMarks(from = Argument(0), to = Result) - ), - ) - ) - if (method.name == "validate") add( - TaintPassThrough( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - RemoveMark(mark = TaintMark("TAINT"), position = Argument(0)) - ), - ) - ) - } - rules.ifEmpty { null } - } - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = getConfigForMethod, - ) - - val goodMethod = project.classes.flatMap { it.methods }.single { it.name == "good" } - logger.info { "good() method: $goodMethod" } - val goodSinks = manager.analyze(listOf(goodMethod), timeout = 60.seconds) - logger.info { "Sinks in good(): $goodSinks" } - Assertions.assertTrue(goodSinks.isEmpty()) - - val badMethod = project.classes.flatMap { it.methods }.single { it.name == "bad" } - logger.info { "bad() method: $badMethod" } - val badSinks = manager.analyze(listOf(badMethod), timeout = 60.seconds) - logger.info { "Sinks in bad(): $badSinks" } - Assertions.assertTrue(badSinks.isNotEmpty()) - } - - @Test - fun `test taint analysis on case1 - untrusted loop bound scenario`() { - val file = loadSample("cases/case1") - val project = EtsScene(listOf(file)) - val graph = EtsApplicationGraphImpl(project) - val unitResolver = UnitResolver { SingletonUnit } - val getConfigForMethod: ForwardTaintFlowFunctions.(EtsMethod) -> List? = - { method -> - val rules = buildList { - if (method.name == "readInt") add( - TaintMethodSource( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - AssignMark(mark = TaintMark("UNTRUSTED"), position = Result), - ), - ) - ) - } - rules.ifEmpty { null } - } - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = getConfigForMethod, - ) - TaintAnalysisOptions.UNTRUSTED_LOOP_BOUND_SINK = true - - val methods = project.classes.flatMap { it.methods } - logger.info { "Methods: ${methods.size}" } - for (method in methods) { - logger.info { " ${method.name}" } - } - val sinks = manager.analyze(methods, timeout = 60.seconds) - logger.info { "Sinks: $sinks" } - Assertions.assertTrue(sinks.isNotEmpty()) - } - - @Test - fun `test taint analysis on case2 - untrusted array buffer size scenario`() { - val file = loadSample("cases/case2") - val project = EtsScene(listOf(file)) - val graph = EtsApplicationGraphImpl(project) - val unitResolver = UnitResolver { SingletonUnit } - val getConfigForMethod: ForwardTaintFlowFunctions.(EtsMethod) -> List? = - { method -> - val rules = buildList { - if (method.name == "readInt") add( - TaintMethodSource( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - AssignMark(mark = TaintMark("UNTRUSTED"), position = Result), - ), - ) - ) - } - rules.ifEmpty { null } - } - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = getConfigForMethod, - ) - TaintAnalysisOptions.UNTRUSTED_ARRAY_SIZE_SINK = true - - val methods = project.classes.flatMap { it.methods } - logger.info { "Methods: ${methods.size}" } - for (method in methods) { - logger.info { " ${method.name}" } - } - val sinks = manager.analyze(methods, timeout = 60.seconds) - logger.info { "Sinks: $sinks" } - Assertions.assertTrue(sinks.isNotEmpty()) - } - - // TODO(): support AnyArgument Position type for more flexible configs - @Test - fun `test taint analysis on case3 - send plain information with sensitive data`() { - val file = loadSample("cases/case3") - val project = EtsScene(listOf(file)) - val graph = EtsApplicationGraphImpl(project) - val unitResolver = UnitResolver { SingletonUnit } - val getConfigForMethod: ForwardTaintFlowFunctions.(EtsMethod) -> List? = - { method -> - val rules = buildList { - if (method.name == "getPassword") add( - TaintMethodSource( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - AssignMark(mark = TaintMark("TAINT"), position = Result), - ), - ) - ) - if (method.name == "publishEvent") add( - TaintMethodSink( - method = method, ruleNote = "SINK", // FIXME - cwe = listOf(), // FIXME - condition = ContainsMark(position = Argument(1), mark = TaintMark("TAINT")) - ) - ) - } - rules.ifEmpty { null } - } - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = getConfigForMethod, - ) - - val methods = project.classes.flatMap { it.methods } - logger.info { "Methods: ${methods.size}" } - for (method in methods) { - logger.info { " ${method.name}" } - } - val sinks = manager.analyze(methods, timeout = 60.seconds) - logger.info { "Sinks: $sinks" } - Assertions.assertTrue(sinks.isNotEmpty()) - } - - @EnabledIf("projectAvailable") - @Test - fun `test taint analysis on AccountManager`() { - val file = loadEtsFileFromResource("/etsir/project1/entry/src/main/ets/base/account/AccountManager.ts.json") - val project = EtsScene(listOf(file)) - val graph = EtsApplicationGraphImpl(project) - val unitResolver = UnitResolver { SingletonUnit } - val getConfigForMethod: ForwardTaintFlowFunctions.(EtsMethod) -> List? = - { method -> - val rules = buildList { - // adhoc taint second argument (cursor: string) - if (method.name == "taintSink") add( - TaintMethodSink( - method = method, - cwe = listOf(), - ruleNote = "SINK", - condition = ContainsMark(position = Argument(0), mark = TaintMark("TAINT")), - ) - ) -// // encodeURI* -// if (method.name.startsWith("encodeURI")) add( -// TaintMethodSource( -// method = method, -// condition = ContainsMark(position = Argument(0), mark = TaintMark("UNSAFE")), -// actionsAfter = listOf( -// RemoveMark(position = Result, mark = TaintMark("UNSAFE")), -// ), -// ) -// ) -// // RequestOption.setUrl -// if (method.name == "setUrl") add( -// TaintMethodSource( -// method = method, -// condition = ConstantTrue, -// actionsAfter = listOf( -// CopyMark( -// mark = TaintMark("UNSAFE"), -// from = Argument(0), -// to = Result -// ), -// ), -// ) -// ) -// // HttpManager.requestSync -// if (method.name == "requestSync") add( -// TaintMethodSink( -// method = method, -// ruleNote = "Unsafe request", // FIXME -// cwe = listOf(), // FIXME -// condition = ContainsMark(position = Argument(0), mark = TaintMark("UNSAFE")) -// ) -// ) - // SyncUtil.requestGet - if (method.name == "requestGet") add( - TaintMethodSource( - method = method, - condition = ConstantTrue, - actionsAfter = listOf(AssignMark(position = Result, mark = TaintMark("TAINT"))) - ) - ) - } - rules.ifEmpty { null } - } - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = getConfigForMethod, - ) - - val methodNames = setOf( - "getDeviceIdListWithCursor", - "requestGet", - "taintRun", - "taintSink" - ) - - val methods = project.classes.flatMap { it.methods }.filter { it.name in methodNames } - logger.info { "Methods: ${methods.size}" } - for (method in methods) { - logger.info { " ${method.name}" } - } - val sinks = manager.analyze(methods, timeout = 60.seconds) - logger.info { "Sinks: $sinks" } - Assertions.assertTrue(sinks.isNotEmpty()) - } - -} diff --git a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsProjectAnalysis.kt b/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsProjectAnalysis.kt deleted file mode 100644 index e999da8ce..000000000 --- a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsProjectAnalysis.kt +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.ets.test - -import org.jacodb.ets.test.utils.getConfigForMethod -import org.jacodb.ets.test.utils.loadEtsFileFromResource -import org.jacodb.ets.test.utils.loadRules -import org.jacodb.analysis.ifds.SingletonUnit -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.taint.TaintVulnerability -import org.jacodb.analysis.util.EtsTraits -import org.jacodb.analysis.util.getPathEdges -import org.jacodb.ets.base.EtsStmt -import org.jacodb.ets.graph.EtsApplicationGraphImpl -import org.jacodb.ets.model.EtsFile -import org.jacodb.ets.model.EtsMethod -import org.jacodb.ets.model.EtsScene -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.condition.EnabledIf -import java.nio.file.Files -import java.nio.file.Paths -import kotlin.io.path.exists -import kotlin.time.Duration -import kotlin.time.Duration.Companion.milliseconds -import kotlin.time.Duration.Companion.seconds - -private val logger = mu.KotlinLogging.logger {} - -class EtsProjectAnalysis { - private var tsLinesSuccess = 0L - private var tsLinesFailed = 0L - private var analysisTime: Duration = Duration.ZERO - private var totalPathEdges = 0 - private var totalSinks: MutableList> = mutableListOf() - - companion object : EtsTraits { - private const val SOURCE_PROJECT_PATH = "/project1" - private const val PROJECT_PATH = "/etsir/project1" - private const val START_PATH = "/entry/src/main/ets" - private const val BASE_PATH = PROJECT_PATH + START_PATH - private const val SOURCE_BASE_PATH = SOURCE_PROJECT_PATH + START_PATH - - private fun loadFromProject(filename: String): EtsFile { - return loadEtsFileFromResource("$BASE_PATH/$filename.json") - } - - private fun countFileLines(path: String): Long { - val stream = object {}::class.java.getResourceAsStream(path) - ?: error("Resource not found: $path") - stream.bufferedReader().use { reader -> - return reader.lines().count() - } - } - - val rules = loadRules("config1.json") - } - - private fun projectAvailable(): Boolean { - val resource = object {}::class.java.getResource(PROJECT_PATH)?.toURI() - return resource != null && Paths.get(resource).exists() - } - - @EnabledIf("projectAvailable") - @Test - fun processAllFiles() { - val baseDirUrl = object {}::class.java.getResource(BASE_PATH) - val baseDir = Paths.get(baseDirUrl?.toURI() ?: error("Resource not found")) - Files.walk(baseDir) - .filter { it.toString().endsWith(".json") } - .map { baseDir.relativize(it).toString().replace("\\", "/").substringBeforeLast('.') } - .forEach { filename -> - handleFile(filename) - } - makeReport() - } - - private fun makeReport() { - logger.info { "Analysis Report On $PROJECT_PATH" } - logger.info { "====================" } - logger.info { "Total files processed: ${tsLinesSuccess + tsLinesFailed}" } - logger.info { "Successfully processed lines: $tsLinesSuccess" } - logger.info { "Failed lines: $tsLinesFailed" } - logger.info { "Total analysis time: $analysisTime" } - logger.info { "Total path edges: $totalPathEdges" } - logger.info { "Found sinks: ${totalSinks.size}" } - - if (totalSinks.isNotEmpty()) { - totalSinks.forEachIndexed { idx, sink -> - logger.info { - """Detailed Sink Information: - | - |Sink ID: $idx - |Statement: ${sink.sink.statement} - |Fact: ${sink.sink.fact} - |Condition: ${sink.rule?.condition} - | - """.trimMargin() - } - } - } else { - logger.info { "No sinks found." } - } - logger.info { "====================" } - logger.info { "End of report" } - } - - private fun handleFile(filename: String) { - val fileLines = countFileLines("$SOURCE_BASE_PATH/$filename") - try { - logger.info { "Processing '$filename'" } - val file = loadFromProject(filename) - val project = EtsScene(listOf(file)) - val startTime = System.currentTimeMillis() - runAnalysis(project) - val endTime = System.currentTimeMillis() - analysisTime += (endTime - startTime).milliseconds - tsLinesSuccess += fileLines - } catch (e: Exception) { - logger.warn { "Failed to process '$filename': $e" } - logger.warn { e.stackTraceToString() } - tsLinesFailed += fileLines - } - } - - private fun runAnalysis(project: EtsScene) { - val graph = EtsApplicationGraphImpl(project) - val unitResolver = UnitResolver { SingletonUnit } - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = { method -> getConfigForMethod(method, rules) }, - ) - val methods = project.classes.flatMap { it.methods } - val sinks = manager.analyze(methods, timeout = 10.seconds) - totalPathEdges += manager.runnerForUnit.values.sumOf { it.getPathEdges().size } - totalSinks += sinks - } -} diff --git a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsSceneTest.kt b/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsSceneTest.kt deleted file mode 100644 index 9c68b0737..000000000 --- a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsSceneTest.kt +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.ets.test - -import org.jacodb.ets.base.EtsArrayType -import org.jacodb.ets.base.EtsAssignStmt -import org.jacodb.ets.base.EtsCallStmt -import org.jacodb.ets.base.EtsClassType -import org.jacodb.ets.base.EtsInstLocation -import org.jacodb.ets.base.EtsInstanceCallExpr -import org.jacodb.ets.base.EtsLocal -import org.jacodb.ets.base.EtsReturnStmt -import org.jacodb.ets.base.EtsStringType -import org.jacodb.ets.base.EtsThis -import org.jacodb.ets.base.EtsVoidType -import org.jacodb.ets.graph.EtsApplicationGraphImpl -import org.jacodb.ets.graph.EtsCfg -import org.jacodb.ets.model.EtsClassImpl -import org.jacodb.ets.model.EtsClassSignature -import org.jacodb.ets.model.EtsFieldImpl -import org.jacodb.ets.model.EtsFieldSignature -import org.jacodb.ets.model.EtsFieldSubSignature -import org.jacodb.ets.model.EtsFile -import org.jacodb.ets.model.EtsFileSignature -import org.jacodb.ets.model.EtsMethodImpl -import org.jacodb.ets.model.EtsMethodSignature -import org.jacodb.ets.model.EtsScene -import kotlin.test.Test -import kotlin.test.assertEquals - -class EtsSceneTest { - - @Test - fun `test create EtsScene with multiple files`() { - val fileCatSignature = EtsFileSignature( - projectName = "TestProject", - fileName = "cat.ts", - ) - val classCatSignature = EtsClassSignature( - name = "Cat", - file = fileCatSignature, - namespace = null, - ) - val fieldName = EtsFieldImpl( - signature = EtsFieldSignature( - enclosingClass = classCatSignature, - sub = EtsFieldSubSignature( - name = "name", - type = EtsStringType, - ) - ) - ) - val methodMeow = EtsMethodImpl( - signature = EtsMethodSignature( - enclosingClass = classCatSignature, - name = "meow", - parameters = emptyList(), - returnType = EtsVoidType, - ) - ) - val ctorCat = EtsMethodImpl( - signature = EtsMethodSignature( - enclosingClass = classCatSignature, - name = "constructor", - parameters = emptyList(), - returnType = EtsVoidType, - ), - ) - val classCat = EtsClassImpl( - signature = classCatSignature, - fields = listOf(fieldName), - methods = listOf(methodMeow), - ctor = ctorCat, - ) - val fileCat = EtsFile( - signature = fileCatSignature, - classes = listOf(classCat), - namespaces = emptyList(), - ) - - val fileBoxSignature = EtsFileSignature( - projectName = "TestProject", - fileName = "box.ts", - ) - val classBoxSignature = EtsClassSignature( - name = "Box", - file = fileBoxSignature, - namespace = null, - ) - val fieldCats = EtsFieldImpl( - signature = EtsFieldSignature( - enclosingClass = classBoxSignature, - sub = EtsFieldSubSignature( - name = "cats", - type = EtsArrayType(EtsClassType(classCatSignature), 1), - ) - ) - ) - val methodTouch = EtsMethodImpl( - signature = EtsMethodSignature( - enclosingClass = classBoxSignature, - name = "touch", - parameters = emptyList(), - returnType = EtsVoidType, - ) - ).also { - var index = 0 - val stmts = listOf( - EtsAssignStmt( - location = EtsInstLocation(it, index++), - lhv = EtsLocal("this", EtsClassType(classBoxSignature)), - rhv = EtsThis(EtsClassType(classBoxSignature)), - ), - EtsCallStmt( - location = EtsInstLocation(it, index++), - expr = EtsInstanceCallExpr( - instance = EtsLocal("this", EtsClassType(classBoxSignature)), - method = methodMeow.signature, - args = emptyList(), - ) - ), - EtsReturnStmt( - location = EtsInstLocation(it, index++), - returnValue = null, - ) - ) - check(index == stmts.size) - val successors = mapOf( - stmts[0] to listOf(stmts[1]), - stmts[1] to listOf(stmts[2]), - ) - it._cfg = EtsCfg( - stmts = stmts, - successorMap = successors, - ) - } - val ctorBox = EtsMethodImpl( - signature = EtsMethodSignature( - enclosingClass = classBoxSignature, - name = "constructor", - parameters = emptyList(), - returnType = EtsVoidType, - ), - ) - val classBox = EtsClassImpl( - signature = classBoxSignature, - fields = listOf(fieldCats), - methods = listOf(methodTouch), - ctor = ctorBox, - ) - val fileBox = EtsFile( - signature = fileBoxSignature, - classes = listOf(classBox), - namespaces = emptyList(), - ) - - val project = EtsScene(files = listOf(fileCat, fileBox)) - val graph = EtsApplicationGraphImpl(project) - - val callStmt = project.classes - .asSequence() - .flatMap { it.methods } - .filter { it.name == "touch" } - .flatMap { it.cfg.stmts } - .filterIsInstance() - .first() - assertEquals(methodMeow, graph.callees(callStmt).first()) - } -} diff --git a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsTaintAnalysisTest.kt b/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsTaintAnalysisTest.kt deleted file mode 100644 index 2826c4207..000000000 --- a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsTaintAnalysisTest.kt +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.ets.test - -import org.jacodb.analysis.ifds.SingletonUnit -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.taint.ForwardTaintFlowFunctions -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.util.EtsTraits -import org.jacodb.ets.base.EtsStmt -import org.jacodb.ets.graph.EtsApplicationGraphImpl -import org.jacodb.ets.model.EtsFile -import org.jacodb.ets.model.EtsMethod -import org.jacodb.ets.model.EtsScene -import org.jacodb.ets.test.utils.loadEtsFileFromResource -import org.jacodb.taint.configuration.Argument -import org.jacodb.taint.configuration.AssignMark -import org.jacodb.taint.configuration.ConstantTrue -import org.jacodb.taint.configuration.ContainsMark -import org.jacodb.taint.configuration.CopyAllMarks -import org.jacodb.taint.configuration.RemoveMark -import org.jacodb.taint.configuration.Result -import org.jacodb.taint.configuration.TaintConfigurationItem -import org.jacodb.taint.configuration.TaintMark -import org.jacodb.taint.configuration.TaintMethodSink -import org.jacodb.taint.configuration.TaintMethodSource -import org.jacodb.taint.configuration.TaintPassThrough -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test -import kotlin.time.Duration.Companion.seconds - -private val logger = mu.KotlinLogging.logger {} - -class EtsTaintAnalysisTest { - - companion object : EtsTraits { - private const val BASE_PATH = "/samples/etsir/ast" - - private const val DECOMPILED_PATH = "/decompiled" - - private fun loadFromProject(name: String): EtsFile { - return loadEtsFileFromResource("$BASE_PATH/$name.ts.json") - } - - private fun loadDecompiled(name: String): EtsFile { - return loadEtsFileFromResource("$DECOMPILED_PATH/$name.abc.json") - } - - val getConfigForMethod: ForwardTaintFlowFunctions.(EtsMethod) -> List? = - { method -> - val rules = buildList { - if (method.name == "source") add( - TaintMethodSource( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - AssignMark(mark = TaintMark("TAINT"), position = Result), - ), - ) - ) - if (method.name == "sink") add( - TaintMethodSink( - method = method, - ruleNote = "SINK", // FIXME - cwe = listOf(), // FIXME - condition = ContainsMark(position = Argument(0), mark = TaintMark("TAINT")) - ) - ) - if (method.name == "pass") add( - TaintPassThrough( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - CopyAllMarks(from = Argument(0), to = Result) - ), - ) - ) - if (method.name == "validate") add( - TaintPassThrough( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - RemoveMark(mark = TaintMark("TAINT"), position = Argument(0)) - ), - ) - ) - } - rules.ifEmpty { null } - } - } - - fun runTaintAnalysis(project: EtsScene) { - val graph = EtsApplicationGraphImpl(project) - val unitResolver = UnitResolver { SingletonUnit } - - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = getConfigForMethod, - ) - - val methods = project.classes.flatMap { it.methods }.filter { it.name == "bad" } - logger.info { "Methods: ${methods.size}" } - for (method in methods) { - logger.info { " ${method.name}" } - } - val sinks = manager.analyze(methods, timeout = 60.seconds) - logger.info { "Sinks: $sinks" } - assertTrue(sinks.isNotEmpty()) - } - - @Test - fun `test taint analysis`() { - val file = loadFromProject("TaintAnalysis") - val project = EtsScene(files = listOf(file)) - runTaintAnalysis(project) - } - - @Disabled("Need to update the EtsIR-ABC json file") - @Test - fun `test taint analysis on decompiled file`() { - val file = loadDecompiled("TaintAnalysis") - val project = EtsScene(files = listOf(file)) - runTaintAnalysis(project) - } -} diff --git a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/utils/Entrypoints.kt b/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/utils/Entrypoints.kt index d82bb1b61..21da10fd0 100644 --- a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/utils/Entrypoints.kt +++ b/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/utils/Entrypoints.kt @@ -23,7 +23,6 @@ import org.jacodb.ets.utils.dumpDot import org.jacodb.ets.utils.render import org.jacodb.ets.utils.resolveSibling import org.jacodb.ets.utils.toText -import kotlin.io.path.ExperimentalPathApi import kotlin.io.path.Path import kotlin.io.path.div import kotlin.io.path.name @@ -79,7 +78,6 @@ object DumpEtsFileToDot { /** * Visualize classes and methods in [EtsFileDto] and [EtsFile] from directory. */ -@OptIn(ExperimentalPathApi::class) object DumpEtsFilesToDot { // private const val ETSIR = "/projects/applications_app_samples/etsir/ast/ArkTSDistributedCalc" // private val DOT_DIR = Path("generated/projects/applications_app_samples/Calc/dot") diff --git a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/utils/TaintConfig.kt b/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/utils/TaintConfig.kt deleted file mode 100644 index ac18fd3d6..000000000 --- a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/utils/TaintConfig.kt +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.ets.test.utils - -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.json.Json -import kotlinx.serialization.modules.SerializersModule -import org.jacodb.api.common.CommonMethod -import org.jacodb.taint.configuration.NameExactMatcher -import org.jacodb.taint.configuration.NamePatternMatcher -import org.jacodb.taint.configuration.SerializedTaintCleaner -import org.jacodb.taint.configuration.SerializedTaintConfigurationItem -import org.jacodb.taint.configuration.SerializedTaintEntryPointSource -import org.jacodb.taint.configuration.SerializedTaintMethodSink -import org.jacodb.taint.configuration.SerializedTaintMethodSource -import org.jacodb.taint.configuration.SerializedTaintPassThrough -import org.jacodb.taint.configuration.TaintCleaner -import org.jacodb.taint.configuration.TaintConfigurationItem -import org.jacodb.taint.configuration.TaintEntryPointSource -import org.jacodb.taint.configuration.TaintMethodSink -import org.jacodb.taint.configuration.TaintMethodSource -import org.jacodb.taint.configuration.TaintPassThrough -import org.jacodb.taint.configuration.actionModule -import org.jacodb.taint.configuration.conditionModule - -private val json = Json { - classDiscriminator = "_" - serializersModule = SerializersModule { - include(conditionModule) - include(actionModule) - } -} - -fun loadRules(configFileName: String): List { - val configResource = object {}::class.java.getResourceAsStream("/$configFileName") - ?: error("Could not load config from '$configFileName'") - val configJson = configResource.bufferedReader().readText() - val rules: List = json.decodeFromString(configJson) - // println("Loaded ${rules.size} rules from '$configFileName'") - // for (rule in rules) { - // println(rule) - // } - return rules -} - -fun getConfigForMethod( - method: CommonMethod, - rules: List, -): List? { - val res = buildList { - for (item in rules) { - val matcher = item.methodInfo.functionName - if (matcher is NameExactMatcher) { - if (method.name == matcher.name) add(item.toItem(method)) - } else if (matcher is NamePatternMatcher) { - if (method.name.matches(matcher.pattern.toRegex())) add(item.toItem(method)) - } - } - } - return res.ifEmpty { null } -} - -fun SerializedTaintConfigurationItem.toItem(method: CommonMethod): TaintConfigurationItem { - return when (this) { - is SerializedTaintEntryPointSource -> TaintEntryPointSource( - method = method, - condition = condition, - actionsAfter = actionsAfter - ) - - is SerializedTaintMethodSource -> TaintMethodSource( - method = method, - condition = condition, - actionsAfter = actionsAfter - ) - - is SerializedTaintMethodSink -> TaintMethodSink( - method = method, - ruleNote = ruleNote, - cwe = cwe, - condition = condition - ) - - is SerializedTaintPassThrough -> TaintPassThrough( - method = method, - condition = condition, - actionsAfter = actionsAfter - ) - - is SerializedTaintCleaner -> TaintCleaner( - method = method, - condition = condition, - actionsAfter = actionsAfter - ) - } -} diff --git a/jacodb-examples/build.gradle.kts b/jacodb-examples/build.gradle.kts index 1d630faf3..ec2a4a81e 100644 --- a/jacodb-examples/build.gradle.kts +++ b/jacodb-examples/build.gradle.kts @@ -1,7 +1,6 @@ dependencies { api(project(":jacodb-api-jvm")) api(project(":jacodb-core")) - api(project(":jacodb-analysis")) implementation(Libs.slf4j_simple) implementation(Libs.soot_utbot_fork) diff --git a/jacodb-panda-static/build.gradle.kts b/jacodb-panda-static/build.gradle.kts deleted file mode 100644 index 65a2830e3..000000000 --- a/jacodb-panda-static/build.gradle.kts +++ /dev/null @@ -1,26 +0,0 @@ -plugins { - kotlin("plugin.serialization") -} - -repositories { - mavenCentral() -} - -dependencies { - api(project(":jacodb-core")) - api(project(":jacodb-api-common")) - - implementation(Libs.kotlin_logging) - implementation(Libs.slf4j_simple) - implementation(Libs.kotlinx_serialization_json) - implementation(Libs.jdot) - - testImplementation(kotlin("test")) - testImplementation(project(":jacodb-analysis")) - testImplementation(testFixtures(project(":jacodb-core"))) - testImplementation(Libs.mockk) -} - -tasks.test { - useJUnitPlatform() -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/Graph.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/Graph.kt deleted file mode 100644 index 51c406e5b..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/Graph.kt +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.cfg - -import org.jacodb.api.common.analysis.ApplicationGraph -import org.jacodb.api.common.cfg.BytecodeGraph -import org.jacodb.api.common.cfg.Graph -import org.jacodb.panda.staticvm.* -import org.jacodb.panda.staticvm.classpath.PandaMethod -import org.jacodb.panda.staticvm.classpath.PandaProject -import org.jacodb.panda.staticvm.ir.PandaBasicBlockIr -import org.jacodb.panda.staticvm.utils.OneDirectionGraph - -interface PandaBytecodeGraph : BytecodeGraph - -/** - * Control flow graph for a single [PandaMethod]. - */ -class PandaGraph private constructor( - private val instList: PandaInstList, - private val graph: OneDirectionGraph, - private val throwGraph: OneDirectionGraph, -) : PandaBytecodeGraph, Graph { - - override val entries: List = listOfNotNull(instList.firstOrNull()) - - override val exits: List = setOfNotNull(instList.lastOrNull().takeIf { it !is PandaGotoInst }) - .plus(instList.filterIsInstance()) - .toList() - - override val instructions: List = instList.instructions - - fun index(inst: PandaInst): Int { - if (inst in instructions) { - return inst.location.index - } - return -1 - } - - fun ref(inst: PandaInst): PandaInstRef = PandaInstRef(index(inst)) - fun inst(ref: PandaInstRef): PandaInst = instructions[ref.index] - - fun previous(inst: PandaInst): PandaInst = instructions[ref(inst).index - 1] - fun next(inst: PandaInst): PandaInst = instructions[ref(inst).index + 1] - - override fun successors(node: PandaInst): Set = graph.successors(node) - override fun predecessors(node: PandaInst): Set = graph.predecessors(node) - - override fun throwers(node: PandaInst): Set = throwGraph.predecessors(node) - override fun catchers(node: PandaInst): Set = throwGraph.successors(node) - - companion object { - fun empty(): PandaGraph { - return PandaGraph( - PandaInstList(emptyList()), - OneDirectionGraph(emptySet()) { emptySet() }, - OneDirectionGraph(emptySet()) { emptySet() } - ) - } - - fun of(method: PandaMethod, blocks: List): PandaGraph { - val instListBuilder = InstListBuilder(method, blocks) - val instList = instListBuilder.instList - val graph = OneDirectionGraph(instList) { inst -> - when (inst) { - is PandaBranchingInst -> inst.successors.map { instList[it.index] } - is PandaTerminatingInst -> emptyList() - else -> listOfNotNull(instList.getOrNull(instList.indexOf(inst) + 1)) - } - } - val throwGraph = OneDirectionGraph(instList) { thrower -> - instListBuilder.throwEdges - .filter { (from, _) -> instList[from.index] == thrower } - .map { instList[it.second.index] } - } - // instListBuilder.throwEdges.applyFold(graph) { (from, to) -> withEdge(instList[from.index], instList[to.index]) } - return PandaGraph(PandaInstList(instList), graph, throwGraph) - } - } -} - -class PandaApplicationGraph( - val cp: PandaProject, -) : ApplicationGraph { - private val callersMap = cp.methods - .flatMap { it.flowGraph().instructions } - .flatMap { inst -> callees(inst).map { it to inst } } - .groupBy(Pair::first, Pair::second) - - override fun predecessors(node: PandaInst): Sequence { - val graph = node.location.method.flowGraph() - val predecessors = graph.predecessors(node) - if (node is PandaCatchInst) { - val throwers = graph.throwers(node) - return predecessors.asSequence() + throwers.asSequence() - } else { - return predecessors.asSequence() - } - } - - override fun successors(node: PandaInst): Sequence { - val graph = node.location.method.flowGraph() - val successors = graph.successors(node) - if (node is PandaThrowInst) { - val catchers = graph.catchers(node) - return successors.asSequence() + catchers.asSequence() - } else { - return successors.asSequence() - } - } - - override fun callees(node: PandaInst): Sequence = when (node) { - is PandaAssignInst -> when (val expr = node.rhv) { - is PandaStaticCallExpr -> sequenceOf(expr.method) - is PandaVirtualCallExpr -> sequenceOf(expr.method) - else -> emptySequence() - } - - else -> emptySequence() - } - - override fun callers(method: PandaMethod): Sequence { - return callersMap[method]?.asSequence() ?: emptySequence() - } - - override fun entryPoints(method: PandaMethod): Sequence { - return method.flowGraph().entries.asSequence() - } - - override fun exitPoints(method: PandaMethod): Sequence { - return method.flowGraph().exits.asSequence() - } - - override fun methodOf(node: PandaInst): PandaMethod { - return node.location.method - } -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/GraphExt.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/GraphExt.kt deleted file mode 100644 index 4dc460436..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/GraphExt.kt +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.cfg - -import info.leadinglight.jdot.Edge -import info.leadinglight.jdot.Graph -import info.leadinglight.jdot.Node -import info.leadinglight.jdot.enums.Color -import info.leadinglight.jdot.enums.Shape -import info.leadinglight.jdot.enums.Style -import info.leadinglight.jdot.impl.Util -import org.jacodb.impl.cfg.graphs.GraphDominators -import java.io.File -import java.nio.file.Files -import java.nio.file.Path - -fun PandaGraph.view(dotCmd: String, viewerCmd: String, viewCatchConnections: Boolean = false) { - Util.sh(arrayOf(viewerCmd, "file://${toFile(dotCmd, viewCatchConnections)}")) -} - -fun PandaGraph.toFile(dotCmd: String, viewCatchConnections: Boolean = false, file: File? = null): Path { - Graph.setDefaultCmd(dotCmd) - - val graph = Graph("pandaGraph") - - val nodes = mutableMapOf() - for ((index, inst) in instructions.withIndex()) { - val node = Node("$index") - .setShape(Shape.box) - .setLabel(inst.toString().replace("\"", "\\\"")) - .setFontSize(12.0) - nodes[inst] = node - graph.addNode(node) - } - - graph.setBgColor(Color.X11.transparent) - graph.setFontSize(12.0) - graph.setFontName("Fira Mono") - - for ((inst, node) in nodes) { - when (inst) { - is PandaGotoInst -> for (successor in successors(inst)) { - graph.addEdge(Edge(node.name, nodes[successor]!!.name)) - } - - is PandaIfInst -> { - graph.addEdge( - Edge(node.name, nodes[inst(inst.trueBranch)]!!.name) - .also { - it.setLabel("true") - } - ) - graph.addEdge( - Edge(node.name, nodes[inst(inst.falseBranch)]!!.name) - .also { - it.setLabel("false") - } - ) - } - - // is PandaSwitchInst -> { - // for ((key, branch) in inst.branches) { - // graph.addEdge( - // Edge(node.name, nodes[inst(branch)]!!.name) - // .also { - // it.setLabel("$key") - // } - // ) - // } - // graph.addEdge( - // Edge(node.name, nodes[inst(inst.default)]!!.name) - // .also { - // it.setLabel("else") - // } - // ) - // } - - else -> for (successor in successors(inst)) { - graph.addEdge(Edge(node.name, nodes[successor]!!.name)) - } - } - if (viewCatchConnections) { - for (catcher in catchers(inst)) { - graph.addEdge(Edge(node.name, nodes[catcher]!!.name).also { - // it.setLabel("catch ${catcher.throwable.type}") - it.setLabel("catch") - it.setStyle(Style.Edge.dashed) - }) - } - } - } - - val outFile = graph.dot2file("svg") - val newFile = "${outFile.removeSuffix(".out")}.svg" - val resultingFile = file?.toPath() ?: File(newFile).toPath() - Files.move(File(outFile).toPath(), resultingFile) - return resultingFile -} - -fun PandaGraph.findDominators(): GraphDominators { - return GraphDominators(this).also { - it.find() - } -} - -// fun PandaBlockGraph.findDominators(): GraphDominators { -// return GraphDominators(this).also { -// it.find() -// } -// } diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/InstListBuilder.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/InstListBuilder.kt deleted file mode 100644 index 52873dd62..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/InstListBuilder.kt +++ /dev/null @@ -1,857 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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. - */ - -@file:Suppress("MemberVisibilityCanBePrivate") - -package org.jacodb.panda.staticvm.cfg - -import org.jacodb.panda.staticvm.classpath.PandaArrayType -import org.jacodb.panda.staticvm.classpath.PandaMethod -import org.jacodb.panda.staticvm.classpath.PandaPrimitiveType -import org.jacodb.panda.staticvm.classpath.PandaPrimitives -import org.jacodb.panda.staticvm.classpath.PandaType -import org.jacodb.panda.staticvm.ir.PandaAShlInstIr -import org.jacodb.panda.staticvm.ir.PandaAShrInstIr -import org.jacodb.panda.staticvm.ir.PandaAddInstIr -import org.jacodb.panda.staticvm.ir.PandaAndInstIr -import org.jacodb.panda.staticvm.ir.PandaBasicBlockIr -import org.jacodb.panda.staticvm.ir.PandaBitcastInstIr -import org.jacodb.panda.staticvm.ir.PandaBoundsCheckInstIr -import org.jacodb.panda.staticvm.ir.PandaBuiltinInstIr -import org.jacodb.panda.staticvm.ir.PandaCallDynamicInstIr -import org.jacodb.panda.staticvm.ir.PandaCallLaunchStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaCallLaunchVirtualInstIr -import org.jacodb.panda.staticvm.ir.PandaCallResolvedStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaCallResolvedVirtualInstIr -import org.jacodb.panda.staticvm.ir.PandaCallStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaCallVirtualInstIr -import org.jacodb.panda.staticvm.ir.PandaCastInstIr -import org.jacodb.panda.staticvm.ir.PandaCatchPhiInstIr -import org.jacodb.panda.staticvm.ir.PandaCheckCastInstIr -import org.jacodb.panda.staticvm.ir.PandaCmpInstIr -import org.jacodb.panda.staticvm.ir.PandaCompareInstIr -import org.jacodb.panda.staticvm.ir.PandaConstantInstIr -import org.jacodb.panda.staticvm.ir.PandaDivInstIr -import org.jacodb.panda.staticvm.ir.PandaFillConstArrayInstIr -import org.jacodb.panda.staticvm.ir.PandaFunctionImmediateInstIr -import org.jacodb.panda.staticvm.ir.PandaHclassCheckInstIr -import org.jacodb.panda.staticvm.ir.PandaIfImmInstIr -import org.jacodb.panda.staticvm.ir.PandaInitClassInstIr -import org.jacodb.panda.staticvm.ir.PandaInstIr -import org.jacodb.panda.staticvm.ir.PandaInstIrVisitor -import org.jacodb.panda.staticvm.ir.PandaIntrinsicInstIr -import org.jacodb.panda.staticvm.ir.PandaIsInstanceInstIr -import org.jacodb.panda.staticvm.ir.PandaLenArrayInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadAndInitClassInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadArrayInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadClassInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadFromConstantPoolInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadImmediateInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadObjFromConstInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadObjectDynamicInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadObjectInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadResolvedObjectFieldInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadResolvedObjectFieldStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadRuntimeClassInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadStringInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadTypeInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadUndefinedInstIr -import org.jacodb.panda.staticvm.ir.PandaModInstIr -import org.jacodb.panda.staticvm.ir.PandaMulInstIr -import org.jacodb.panda.staticvm.ir.PandaNegInstIr -import org.jacodb.panda.staticvm.ir.PandaNegativeCheckInstIr -import org.jacodb.panda.staticvm.ir.PandaNewArrayInstIr -import org.jacodb.panda.staticvm.ir.PandaNewObjectInstIr -import org.jacodb.panda.staticvm.ir.PandaNotInstIr -import org.jacodb.panda.staticvm.ir.PandaNullCheckInstIr -import org.jacodb.panda.staticvm.ir.PandaNullPtrInstIr -import org.jacodb.panda.staticvm.ir.PandaOrInstIr -import org.jacodb.panda.staticvm.ir.PandaParameterInstIr -import org.jacodb.panda.staticvm.ir.PandaPhiInstIr -import org.jacodb.panda.staticvm.ir.PandaRefTypeCheckInstIr -import org.jacodb.panda.staticvm.ir.PandaResolveStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaResolveVirtualInstIr -import org.jacodb.panda.staticvm.ir.PandaReturnInstIr -import org.jacodb.panda.staticvm.ir.PandaReturnVoidInstIr -import org.jacodb.panda.staticvm.ir.PandaSafePointInstIr -import org.jacodb.panda.staticvm.ir.PandaSaveStateDeoptimizeInstIr -import org.jacodb.panda.staticvm.ir.PandaSaveStateInstIr -import org.jacodb.panda.staticvm.ir.PandaShlInstIr -import org.jacodb.panda.staticvm.ir.PandaShrInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreArrayInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreObjectDynamicInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreObjectInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreResolvedObjectFieldInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreResolvedObjectFieldStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaSubInstIr -import org.jacodb.panda.staticvm.ir.PandaTerminatingInstIr -import org.jacodb.panda.staticvm.ir.PandaThrowInstIr -import org.jacodb.panda.staticvm.ir.PandaTryInstIr -import org.jacodb.panda.staticvm.ir.PandaXorInstIr -import org.jacodb.panda.staticvm.ir.PandaZeroCheckInstIr -import org.jacodb.panda.staticvm.utils.OneDirectionGraph -import org.jacodb.panda.staticvm.utils.SCCs -import org.jacodb.panda.staticvm.utils.inTopsortOrder -import org.jacodb.panda.staticvm.utils.runDP -import java.nio.ByteBuffer -import java.nio.ByteOrder -import kotlin.reflect.typeOf - -fun interface InstBuilder { - fun build(): PandaInst -} - -fun interface ThrowInstBuilder : InstBuilder { - override fun build(): PandaThrowInst -} - -data class IrInstLocation(val block: Int, val index: Int) - -class InstListBuilder( - val method: PandaMethod, - val blocks: List, -) { - val project = method.enclosingClass.project - - private val localVars = buildLocalVariables(method, blocks) - private val locationMap = hashMapOf() - private val blockIdMap = blocks.mapIndexed { index, block -> block.id to index }.toMap() - - private fun getBlock(id: Int): PandaBasicBlockIr = blocks[requireNotNull(blockIdMap[id])] - - private fun linearRef(location: IrInstLocation): PandaInstRef { - val loc = locationMap[location] - ?: error("No location $location for method: $method") - return PandaInstRef(loc) - } - - fun local(name: String): PandaLocalVar = localVars[name] - ?: error("No local $name for method: $method") - - fun result(inst: PandaInstIr): PandaLocalVar = local(inst.id) - - private val instBuilders: MutableList = mutableListOf() - - private inline fun push(noinline build: (PandaInstLocation) -> T) { - val index = instBuilders.size - when (typeOf()) { - typeOf() -> { - @Suppress("UNCHECKED_CAST", "NAME_SHADOWING") - val build = build as (PandaInstLocation) -> PandaThrowInst - instBuilders += ThrowInstBuilder { build(PandaInstLocation(method, index)) } - } - - else -> { - instBuilders += InstBuilder { build(PandaInstLocation(method, index)) } - } - } - } - - internal fun pushAssign(lhv: PandaValue, rhv: PandaExpr) { - push { location -> - PandaAssignInst(location, lhv, rhv) - } - } - - internal fun pushParameter(lhv: PandaValue, index: Int) { - push { location -> - PandaParameterInst(location, lhv, index) - } - } - - internal fun pushReturn(value: PandaValue?) { - push { location -> - PandaReturnInst( - location = location, - returnValue = value - ) - } - } - - internal fun pushIf( - conditionExpr: PandaConditionExpr, - trueBranch: IrInstLocation, - falseBranch: IrInstLocation, - ) { - push { location -> - PandaIfInst( - location = location, - condition = conditionExpr, - trueBranch = linearRef(trueBranch), - falseBranch = linearRef(falseBranch) - ) - } - } - - internal fun pushGoto(target: IrInstLocation) { - push { location -> - PandaGotoInst( - location = location, - target = linearRef(target) - ) - } - } - - internal fun pushDoNothing() { - push { location -> - PandaDoNothingInst(location) - } - } - - internal fun pushCatchPhi( - lhv: PandaValue, - inputs: List, - throwers: List, - ) { - push { location -> - val throwerIndices = throwers.map { idMap[it] }.requireNoNulls() - - val (throwInputs, throwPredecessors) = (inputs zip throwerIndices).filter { (_, thrower) -> - instBuilders[thrower] is ThrowInstBuilder - }.unzip() - val predecessors = throwPredecessors.map { PandaInstRef(it) } - PandaPhiInst( - location = location, - lhv = lhv, - phiInputs = throwInputs.zip(predecessors, PandaPhiInst::PhiInput) - ) - } - } - - internal fun pushPhi( - lhv: PandaValue, - inputs: List, - blocks: List, - ) { - push { location -> - val predecessors = blocks.map { - linearRef(IrInstLocation(it, maxOf(0, getBlock(it).insts.lastIndex))) - } - PandaAssignInst( - location, lhv, PandaPhiExpr(lhv.type, inputs, predecessors) - ) - /*PandaPhiInst( - location = location, - lhv = lhv, - phiInputs = inputs.zip(predecessors, PandaPhiInst::PhiInput) - )*/ - } - } - - internal fun pushCatch(lhv: PandaValue, throwerIds: List) = push { location -> - PandaCatchInst(location, lhv, TODO()) - } - - internal fun pushThrow(error: PandaValue, catchers: List) { - push { location -> - PandaThrowInst( - location = location, - error = error, - catchers = catchers.map { linearRef(IrInstLocation(it, 0)) } - ) - } - } - - private val idMap: MutableMap = hashMapOf() - - private val throwEdgeBuilders: MutableList> = mutableListOf() - - private val throwersToCatchBlocks = OneDirectionGraph(blocks) { block -> - block.insts.flatMap { it.catchers }.map(this::getBlock) - } - - private fun throwersLocations(block: PandaBasicBlockIr) = - block.insts.mapIndexedNotNull { index, inst -> - if (inst.catchers.isNotEmpty()) IrInstLocation(block.id, index) else null - } - - init { - val visitor = InstListBuilderVisitor() - blocks.sortedBy { it.predecessors.size }.forEach { block -> - if (block.isCatchBegin) { - visitor.location = IrInstLocation(block.id, 0) - locationMap[visitor.location] = instBuilders.size - val exceptionCatcher = block.insts - .filterIsInstance() - .find { it.throwers.isEmpty() } - exceptionCatcher?.let { - push { location -> - PandaCatchInst( - location, - result(it), - throwersToCatchBlocks - .predecessors(block) - .flatMap { throwersLocations(it) } - .map(this::linearRef) - ) - } - } - } - - if (block.isTryBegin) { - visitor.location = IrInstLocation(block.id, 0) - locationMap[visitor.location] = instBuilders.size - push { location -> - PandaTryPseudoInst(location, block.successors.drop(1).map { linearRef(IrInstLocation(it, 0)) }) - } - } - - block.insts.forEachIndexed { instIndex, inst -> - visitor.location = IrInstLocation(block.id, instIndex) - locationMap.putIfAbsent(visitor.location, instBuilders.size) - idMap[inst.id] = instBuilders.size - - inst.accept(visitor) - - if (inst is PandaThrowInstIr) { - throwEdgeBuilders.addAll(inst.catchers.map { visitor.location to IrInstLocation(it, 0) }) - } - } - - val endOfBlock = IrInstLocation(block.id, block.insts.size) - visitor.location = endOfBlock - locationMap[endOfBlock] = instBuilders.size - if (block.isTryBegin || block.isTryEnd) { - pushGoto(IrInstLocation(block.successors.first(), 0)) - } else { - block.successors.singleOrNull()?.let { - if (block.insts.lastOrNull() !is PandaTerminatingInstIr) { - pushGoto(IrInstLocation(it, 0)) - } - } ?: if (block.insts.isEmpty()) { - pushDoNothing() - } else Unit - } - } - } - - val instList: List = instBuilders.map { it.build() } - - val throwEdges: List> = throwEdgeBuilders.map { (from, to) -> - linearRef(from) to linearRef(to) - } -} - -internal fun buildLocalVariables( - pandaMethod: PandaMethod, - blocks: List, -): Map { - val project = pandaMethod.enclosingClass.project - - val localVarsIndex = hashMapOf() - - val handledType = blocks.flatMap { it.handlers }.associate { - val t = if (it.type == "finally") null else it.type - it.id to t?.let { n -> project.findTypeOrNull(n) } - } - - val varNodes = blocks.flatMap { block -> - val outputVarBuilder = OutputVarBuilder(pandaMethod, block, handledType[block.id]) - block.insts.mapNotNull { it.accept(outputVarBuilder) } - }.associateBy { it.name } - - val graph = OneDirectionGraph(varNodes.values) { node -> - when (node) { - is LeafVarNode -> emptySet() - is DependentVarNode -> node.bounds.mapTo(hashSetOf()) { requireNotNull(varNodes[it]) } - is LoadArrayNode -> setOf(requireNotNull(varNodes[node.array])) - } - } - - val sccs = graph.SCCs() - check(sccs.inTopsortOrder() != null) - - graph.SCCs().runDP { vars, inputTypes -> - vars.map { lv -> - when (lv) { - is LeafVarNode -> lv.type - - is DependentVarNode -> project.commonType(inputTypes.values.flatten()) - ?: error("No common type for ${inputTypes.values}") - - is LoadArrayNode -> { - val arrayTypes = inputTypes.values.flatten() - require(arrayTypes.all { it is PandaArrayType || it == project.objectClass.type }) { - println() - } - val elementTypes = arrayTypes.filterIsInstance().map { it.elementType } - requireNotNull(project.commonType(elementTypes)) - } - }.also { - if (lv is ThisNode) { - localVarsIndex[lv.name] = PandaThis(lv.name, it) - } else { - localVarsIndex[lv.name] = PandaLocalVarImpl(lv.name, it) - } - } - } - } - - return localVarsIndex -} - -context(InstListBuilder) -class InstListBuilderVisitor : PandaInstIrVisitor { - lateinit var location: IrInstLocation - - private inline fun convert(value: ULong, getter: ByteBuffer.() -> T) = ByteBuffer - .allocate(16) - .order(ByteOrder.LITTLE_ENDIAN) - .putLong(value.toLong()) - .rewind() - .let { it as ByteBuffer } - .let(getter) - - private fun getConstant(value: ULong, type: PandaPrimitiveType) = when (type) { - PandaPrimitiveType.VOID -> throw IllegalArgumentException("cannot create void constant") - PandaPrimitiveType.NULL -> PandaNull - PandaPrimitiveType.BOOL -> PandaBoolean(value != 0UL) - PandaPrimitiveType.BYTE -> PandaByte(value.toByte()) - PandaPrimitiveType.UBYTE -> PandaUByte(value.toUByte()) - PandaPrimitiveType.SHORT -> PandaShort(value.toShort()) - PandaPrimitiveType.USHORT -> PandaUShort(value.toUShort()) - PandaPrimitiveType.INT -> PandaInt(value.toInt()) - PandaPrimitiveType.UINT -> PandaUInt(value.toUInt()) - PandaPrimitiveType.LONG -> PandaLong(value.toLong()) - PandaPrimitiveType.ULONG -> PandaULong(value) - PandaPrimitiveType.FLOAT -> PandaFloat(convert(value, ByteBuffer::getFloat)) - PandaPrimitiveType.DOUBLE -> PandaDouble(convert(value, ByteBuffer::getDouble)) - } - - private fun getConditionType(operator: String) = when (operator) { - "LE" -> ::PandaLeExpr - "LT" -> ::PandaLtExpr - "GE" -> ::PandaGeExpr - "GT" -> ::PandaGtExpr - "EQ" -> ::PandaEqExpr - "NE" -> ::PandaNeExpr - else -> throw AssertionError("Unknown operator: $operator") - } - - private fun skip() {} - - private fun pushUnary( - inst: PandaInstIr, - exprConstructor: (PandaType, PandaValue) -> PandaUnaryExpr, - ) { - val type = project.findType(inst.type) - val value = local(inst.inputs[0]) - val expr = exprConstructor(type, value) - pushAssign(result(inst), expr) - } - - private fun pushBinary( - inst: PandaInstIr, - exprConstructor: (PandaType, PandaValue, PandaValue) -> PandaBinaryExpr, - ) { - val type = project.findType(inst.type) - val (lhv, rhv) = inst.inputs.map { local(it) } - val expr = exprConstructor(type, lhv, rhv) - pushAssign(result(inst), expr) - } - - override fun visitPandaConstantInstIr(inst: PandaConstantInstIr) { - val constant = getConstant(inst.value, PandaPrimitives.find(inst.type)) - pushAssign(result(inst), constant) - } - - override fun visitPandaSafePointInstIr(inst: PandaSafePointInstIr) { - skip() - } - - override fun visitPandaSaveStateInstIr(inst: PandaSaveStateInstIr) { - skip() - } - - override fun visitPandaNewObjectInstIr(inst: PandaNewObjectInstIr) { - val type = project.findClass(inst.objectClass).type - val newExpr = PandaNewExpr(type) - pushAssign(result(inst), newExpr) - } - - override fun visitPandaNewArrayInstIr(inst: PandaNewArrayInstIr) { - val type = project.getElementType(inst.arrayType) - val length = local(inst.inputs[1]) - val newArrayExpr = PandaNewArrayExpr(type, length) - pushAssign(result(inst), newArrayExpr) - } - - override fun visitPandaCallStaticInstIr(inst: PandaCallStaticInstIr) { - val callee = project.findMethod(inst.method) - val args = inst.inputs.take(callee.parameterTypes.size).map { local(it) } - val callExpr = PandaStaticCallExpr(callee, args) - pushAssign(result(inst), callExpr) - } - - override fun visitPandaCallLaunchStaticInstIr(inst: PandaCallLaunchStaticInstIr) { - val callee = project.findMethod(inst.method) - val args = inst.inputs.take(callee.parameterTypes.size).map { local(it) } - val callExpr = PandaStaticCallExpr(callee, args) - pushAssign(result(inst), callExpr) - } - - override fun visitPandaNullCheckInstIr(inst: PandaNullCheckInstIr) { - pushAssign(result(inst), local(inst.inputs.first())) - } - - override fun visitPandaZeroCheckInstIr(inst: PandaZeroCheckInstIr) { - pushAssign(result(inst), local(inst.inputs.first())) - } - - override fun visitPandaLoadStringInstIr(inst: PandaLoadStringInstIr) { - pushAssign(result(inst), PandaString(inst.string, project.stringClass.type)) - } - - override fun visitPandaCallVirtualInstIr(inst: PandaCallVirtualInstIr) { - val callee = project.findMethod(inst.method) - val instance = local(inst.inputs[0]) - val args = inst.inputs.drop(1).take(callee.parameterTypes.size - 1).map { local(it) } - val callExpr = PandaVirtualCallExpr(callee, instance, args) - pushAssign(result(inst), callExpr) - } - - override fun visitPandaCallLaunchVirtualInstIr(inst: PandaCallLaunchVirtualInstIr) { - val callee = project.findMethod(inst.method) - val instance = local(inst.inputs[0]) - val args = inst.inputs.drop(1).take(callee.parameterTypes.size - 1).map { local(it) } - val callExpr = PandaVirtualCallExpr(callee, instance, args) - pushAssign(result(inst), callExpr) - } - - override fun visitPandaLoadAndInitClassInstIr(inst: PandaLoadAndInitClassInstIr) { - skip() - } - - override fun visitPandaLoadClassInstIr(inst: PandaLoadClassInstIr) { - skip() - } - - override fun visitPandaInitClassInstIr(inst: PandaInitClassInstIr) { - skip() - } - - override fun visitPandaReturnVoidInstIr(inst: PandaReturnVoidInstIr) { - pushReturn(null) - } - - override fun visitPandaReturnInstIr(inst: PandaReturnInstIr) { - pushReturn(local(inst.inputs[0])) - } - - override fun visitPandaParameterInstIr(inst: PandaParameterInstIr) { - pushParameter(result(inst), inst.index) - } - - override fun visitPandaLoadStaticInstIr(inst: PandaLoadStaticInstIr) { - val enclosingClass = project.findClass(inst.enclosingClass) - val field = enclosingClass.findField(inst.field) - pushAssign(result(inst), PandaFieldRef(null, field)) - } - - override fun visitPandaLoadObjectInstIr(inst: PandaLoadObjectInstIr) { - val enclosingClass = project.findClass(inst.enclosingClass) - val field = enclosingClass.findField(inst.field) - pushAssign(result(inst), PandaFieldRef(local(inst.inputs[0]), field)) - } - - override fun visitPandaStoreStaticInstIr(inst: PandaStoreStaticInstIr) { - val enclosingClass = project.findClass(inst.enclosingClass) - val field = enclosingClass.findField(inst.field) - val fieldRef = PandaFieldRef(null, field) - val value = local(inst.inputs[1]) - pushAssign(fieldRef, value) - } - - override fun visitPandaStoreObjectInstIr(inst: PandaStoreObjectInstIr) { - val (instance, value) = inst.inputs.map { local(it) } - val enclosingClass = project.findClass(inst.enclosingClass) - val field = enclosingClass.findField(inst.field) - val fieldRef = PandaFieldRef(instance, field) - pushAssign(fieldRef, value) - } - - override fun visitPandaLoadArrayInstIr(inst: PandaLoadArrayInstIr) { - val (array, index) = inst.inputs.map { local(it) } - val arrayType = array.type - val type = if (arrayType is PandaArrayType) arrayType.elementType else project.objectClass.type - val arrayAccess = PandaArrayAccess(array, index, type) - pushAssign(result(inst), arrayAccess) - } - - override fun visitPandaStoreArrayInstIr(inst: PandaStoreArrayInstIr) { - val (array, index, value) = inst.inputs.map { local(it) } - val arrayType = array.type - val type = if (arrayType is PandaArrayType) arrayType.elementType else project.objectClass.type - val arrayAccess = PandaArrayAccess(array, index, type) - pushAssign(arrayAccess, value) - } - - override fun visitPandaCastInstIr(inst: PandaCastInstIr) { - val type = project.findType(inst.type) - val value = local(inst.inputs[0]) - val castExpr = PandaCastExpr(type, value) - pushAssign(result(inst), castExpr) - } - - override fun visitPandaIsInstanceInstIr(inst: PandaIsInstanceInstIr) { - val type = project.findType(inst.type) - val value = local(inst.inputs[0]) - val candidateType = project.findClassOrInterface(inst.candidateType).type - val isInstanceExpr = PandaIsInstanceExpr(type, value, candidateType) - pushAssign(result(inst), isInstanceExpr) - } - - override fun visitPandaCheckCastInstIr(inst: PandaCheckCastInstIr) { - val type = project.findClassOrInterface(inst.candidateType).type - val value = local(inst.inputs[0]) - val castExpr = PandaCastExpr(type, value) - pushAssign(result(inst), castExpr) - } - - override fun visitPandaBitcastInstIr(inst: PandaBitcastInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaIfImmInstIr(inst: PandaIfImmInstIr) { - val type = project.findType(inst.type) - val lhv = local(inst.inputs[0]) - val rhv = getConstant(inst.immediate, PandaPrimitives.find(inst.operandsType)) - val conditionExpr = getConditionType(inst.operator).invoke(type, lhv, rhv) - val (trueBranch, falseBranch) = blocks - .single { it.id == location.block } - .successors - .map { IrInstLocation(it, 0) } - pushIf(conditionExpr, trueBranch, falseBranch) - } - - override fun visitPandaCompareInstIr(inst: PandaCompareInstIr) { - val (lhv, rhv) = inst.inputs.map { local(it) } - val type = project.findType(inst.type) - val conditionExpr = getConditionType(inst.operator).invoke(type, lhv, rhv) - pushAssign(result(inst), conditionExpr) - } - - override fun visitPandaPhiInstIr(inst: PandaPhiInstIr) { - if (inst.users.isNotEmpty()) { - val inputs = inst.inputs.map { local(it) } - val blocks = inst.inputBlocks - pushPhi(result(inst), inputs, blocks) - } - } - - override fun visitPandaAddInstIr(inst: PandaAddInstIr) { - pushBinary(inst, ::PandaAddExpr) - } - - override fun visitPandaSubInstIr(inst: PandaSubInstIr) { - pushBinary(inst, ::PandaSubExpr) - } - - override fun visitPandaMulInstIr(inst: PandaMulInstIr) { - pushBinary(inst, ::PandaMulExpr) - } - - override fun visitPandaDivInstIr(inst: PandaDivInstIr) { - pushBinary(inst, ::PandaDivExpr) - } - - override fun visitPandaModInstIr(inst: PandaModInstIr) { - pushBinary(inst, ::PandaModExpr) - } - - override fun visitPandaAndInstIr(inst: PandaAndInstIr) { - pushBinary(inst, ::PandaAndExpr) - } - - override fun visitPandaOrInstIr(inst: PandaOrInstIr) { - pushBinary(inst, ::PandaOrExpr) - } - - override fun visitPandaXorInstIr(inst: PandaXorInstIr) { - pushBinary(inst, ::PandaXorExpr) - } - - override fun visitPandaShlInstIr(inst: PandaShlInstIr) { - pushBinary(inst, ::PandaShlExpr) - } - - override fun visitPandaShrInstIr(inst: PandaShrInstIr) { - pushBinary(inst, ::PandaShrExpr) - } - - override fun visitPandaAShlInstIr(inst: PandaAShlInstIr) { - pushBinary(inst, ::PandaAshlExpr) - } - - override fun visitPandaAShrInstIr(inst: PandaAShrInstIr) { - pushBinary(inst, ::PandaAshrExpr) - } - - override fun visitPandaCmpInstIr(inst: PandaCmpInstIr) { - pushBinary(inst, ::PandaCmpExpr) - } - - override fun visitPandaThrowInstIr(inst: PandaThrowInstIr) { - val error = local(inst.inputs[0]) - val catchers = inst.catchers - pushThrow(error, catchers) - } - - override fun visitPandaNegativeCheckInstIr(inst: PandaNegativeCheckInstIr) { - skip() - } - - override fun visitPandaSaveStateDeoptimizeInstIr(inst: PandaSaveStateDeoptimizeInstIr) { - skip() - } - - override fun visitPandaNegInstIr(inst: PandaNegInstIr) { - pushUnary(inst, ::PandaNegExpr) - } - - override fun visitPandaNotInstIr(inst: PandaNotInstIr) { - pushUnary(inst, ::PandaNotExpr) - } - - override fun visitPandaLenArrayInstIr(inst: PandaLenArrayInstIr) { - pushUnary(inst, ::PandaLenArrayExpr) - } - - override fun visitPandaBoundsCheckInstIr(inst: PandaBoundsCheckInstIr) { - skip() - } - - override fun visitPandaNullPtrInstIr(inst: PandaNullPtrInstIr) { - val nullPtr = PandaNull - pushAssign(result(inst), nullPtr) - } - - override fun visitPandaLoadUndefinedInstIr(inst: PandaLoadUndefinedInstIr) { - val undefined = PandaUndefined(project.findType("std.core.UndefinedType")) - pushAssign(result(inst), undefined) - } - - override fun visitPandaRefTypeCheckInstIr(inst: PandaRefTypeCheckInstIr) { - skip() - } - - override fun visitPandaTryInstIr(inst: PandaTryInstIr) { - skip() - } - - override fun visitPandaCatchPhiInstIr(inst: PandaCatchPhiInstIr) { - val inputs = inst.inputs.map { local(it) } - val throwers = inst.throwers - if (inst.inputs.isNotEmpty()) - pushCatchPhi(result(inst), inputs, throwers) - } - - override fun visitPandaIntrinsicInstIr(inst: PandaIntrinsicInstIr) { - val method = project.resolveIntrinsic(inst.intrinsicId) - val args = inst.inputs.dropLast(1).map { local(it) } - val callExpr = if (method != null) { - PandaStaticCallExpr(method, args) - } else { - PandaIntrinsicCallExpr(inst.intrinsicId, result(inst).type, args) - } - pushAssign(result(inst), callExpr) - } - - override fun visitPandaLoadFromConstantPoolInstIr(inst: PandaLoadFromConstantPoolInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaResolveStaticInstIr(inst: PandaResolveStaticInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaResolveVirtualInstIr(inst: PandaResolveVirtualInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaCallDynamicInstIr(inst: PandaCallDynamicInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaCallResolvedVirtualInstIr(inst: PandaCallResolvedVirtualInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaCallResolvedStaticInstIr(inst: PandaCallResolvedStaticInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaFillConstArrayInstIr(inst: PandaFillConstArrayInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaBuiltinInstIr(inst: PandaBuiltinInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaLoadResolvedObjectFieldInstIr(inst: PandaLoadResolvedObjectFieldInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaLoadResolvedObjectFieldStaticInstIr(inst: PandaLoadResolvedObjectFieldStaticInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaStoreResolvedObjectFieldInstIr(inst: PandaStoreResolvedObjectFieldInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaStoreResolvedObjectFieldStaticInstIr(inst: PandaStoreResolvedObjectFieldStaticInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaLoadObjectDynamicInstIr(inst: PandaLoadObjectDynamicInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaStoreObjectDynamicInstIr(inst: PandaStoreObjectDynamicInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaFunctionImmediateInstIr(inst: PandaFunctionImmediateInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaHclassCheckInstIr(inst: PandaHclassCheckInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaLoadObjFromConstInstIr(inst: PandaLoadObjFromConstInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaLoadImmediateInstIr(inst: PandaLoadImmediateInstIr) { - TODO("Not yet implemented") - } - - override fun visitPandaLoadRuntimeClassInstIr(inst: PandaLoadRuntimeClassInstIr) { - skip() - } - - override fun visitPandaLoadTypeInstIr(inst: PandaLoadTypeInstIr) { - val value = project.findType(inst.loadedType) - val type = project.typeClass.type - val typeConstant = PandaTypeConstant(value, type) - pushAssign(result(inst), typeConstant) - } -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/OutputVarBuilder.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/OutputVarBuilder.kt deleted file mode 100644 index ecdcbe187..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/OutputVarBuilder.kt +++ /dev/null @@ -1,392 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.cfg - -import org.jacodb.panda.staticvm.classpath.PandaMethod -import org.jacodb.panda.staticvm.classpath.PandaPrimitiveType -import org.jacodb.panda.staticvm.classpath.PandaType -import org.jacodb.panda.staticvm.ir.PandaAShlInstIr -import org.jacodb.panda.staticvm.ir.PandaAShrInstIr -import org.jacodb.panda.staticvm.ir.PandaAddInstIr -import org.jacodb.panda.staticvm.ir.PandaAndInstIr -import org.jacodb.panda.staticvm.ir.PandaBasicBlockIr -import org.jacodb.panda.staticvm.ir.PandaBitcastInstIr -import org.jacodb.panda.staticvm.ir.PandaBoundsCheckInstIr -import org.jacodb.panda.staticvm.ir.PandaBuiltinInstIr -import org.jacodb.panda.staticvm.ir.PandaCallDynamicInstIr -import org.jacodb.panda.staticvm.ir.PandaCallLaunchStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaCallLaunchVirtualInstIr -import org.jacodb.panda.staticvm.ir.PandaCallResolvedStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaCallResolvedVirtualInstIr -import org.jacodb.panda.staticvm.ir.PandaCallStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaCallVirtualInstIr -import org.jacodb.panda.staticvm.ir.PandaCastInstIr -import org.jacodb.panda.staticvm.ir.PandaCatchPhiInstIr -import org.jacodb.panda.staticvm.ir.PandaCheckCastInstIr -import org.jacodb.panda.staticvm.ir.PandaCmpInstIr -import org.jacodb.panda.staticvm.ir.PandaCompareInstIr -import org.jacodb.panda.staticvm.ir.PandaConstantInstIr -import org.jacodb.panda.staticvm.ir.PandaDivInstIr -import org.jacodb.panda.staticvm.ir.PandaFillConstArrayInstIr -import org.jacodb.panda.staticvm.ir.PandaFunctionImmediateInstIr -import org.jacodb.panda.staticvm.ir.PandaHclassCheckInstIr -import org.jacodb.panda.staticvm.ir.PandaIfImmInstIr -import org.jacodb.panda.staticvm.ir.PandaInitClassInstIr -import org.jacodb.panda.staticvm.ir.PandaInstIr -import org.jacodb.panda.staticvm.ir.PandaInstIrVisitor -import org.jacodb.panda.staticvm.ir.PandaIntrinsicInstIr -import org.jacodb.panda.staticvm.ir.PandaIsInstanceInstIr -import org.jacodb.panda.staticvm.ir.PandaLenArrayInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadAndInitClassInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadArrayInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadClassInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadFromConstantPoolInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadImmediateInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadObjFromConstInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadObjectDynamicInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadObjectInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadResolvedObjectFieldInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadResolvedObjectFieldStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadRuntimeClassInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadStringInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadTypeInstIr -import org.jacodb.panda.staticvm.ir.PandaLoadUndefinedInstIr -import org.jacodb.panda.staticvm.ir.PandaModInstIr -import org.jacodb.panda.staticvm.ir.PandaMulInstIr -import org.jacodb.panda.staticvm.ir.PandaNegInstIr -import org.jacodb.panda.staticvm.ir.PandaNegativeCheckInstIr -import org.jacodb.panda.staticvm.ir.PandaNewArrayInstIr -import org.jacodb.panda.staticvm.ir.PandaNewObjectInstIr -import org.jacodb.panda.staticvm.ir.PandaNotInstIr -import org.jacodb.panda.staticvm.ir.PandaNullCheckInstIr -import org.jacodb.panda.staticvm.ir.PandaNullPtrInstIr -import org.jacodb.panda.staticvm.ir.PandaOrInstIr -import org.jacodb.panda.staticvm.ir.PandaParameterInstIr -import org.jacodb.panda.staticvm.ir.PandaPhiInstIr -import org.jacodb.panda.staticvm.ir.PandaRefTypeCheckInstIr -import org.jacodb.panda.staticvm.ir.PandaResolveStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaResolveVirtualInstIr -import org.jacodb.panda.staticvm.ir.PandaReturnInstIr -import org.jacodb.panda.staticvm.ir.PandaReturnVoidInstIr -import org.jacodb.panda.staticvm.ir.PandaSafePointInstIr -import org.jacodb.panda.staticvm.ir.PandaSaveStateDeoptimizeInstIr -import org.jacodb.panda.staticvm.ir.PandaSaveStateInstIr -import org.jacodb.panda.staticvm.ir.PandaShlInstIr -import org.jacodb.panda.staticvm.ir.PandaShrInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreArrayInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreObjectDynamicInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreObjectInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreResolvedObjectFieldInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreResolvedObjectFieldStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaStoreStaticInstIr -import org.jacodb.panda.staticvm.ir.PandaSubInstIr -import org.jacodb.panda.staticvm.ir.PandaThrowInstIr -import org.jacodb.panda.staticvm.ir.PandaTryInstIr -import org.jacodb.panda.staticvm.ir.PandaXorInstIr -import org.jacodb.panda.staticvm.ir.PandaZeroCheckInstIr - -sealed interface LocalVarNode { - val name: String -} - -open class LeafVarNode(override val name: String, val type: PandaType) : LocalVarNode - -class DependentVarNode(override val name: String, val bounds: List) : LocalVarNode - -class LoadArrayNode(override val name: String, val array: String) : LocalVarNode - -class ThisNode(name: String, type: PandaType) : LeafVarNode(name, type) - -class OutputVarBuilder( - private val method: PandaMethod, - private val block: PandaBasicBlockIr, - private val handledType: PandaType? = null, -) : PandaInstIrVisitor { - private val project = method.enclosingClass.project - - private fun default(inst: PandaInstIr): LeafVarNode { - val type = project.findType(inst.type) - return LeafVarNode(inst.id, type) - } - - // TODO: default(inst) - override fun visitPandaConstantInstIr(inst: PandaConstantInstIr): LocalVarNode { - val type = project.findType(inst.type) - return LeafVarNode(inst.id, type) - } - - override fun visitPandaSafePointInstIr(inst: PandaSafePointInstIr): LocalVarNode? = null - - override fun visitPandaSaveStateInstIr(inst: PandaSaveStateInstIr): LocalVarNode? = null - - override fun visitPandaNewObjectInstIr(inst: PandaNewObjectInstIr): LocalVarNode { - val classType = project.findClass(inst.objectClass).type - return LeafVarNode(inst.id, classType) - } - - override fun visitPandaNewArrayInstIr(inst: PandaNewArrayInstIr): LocalVarNode { - val arrayType = project.findType(inst.arrayType) - return LeafVarNode(inst.id, arrayType) - } - - override fun visitPandaCallStaticInstIr(inst: PandaCallStaticInstIr): LocalVarNode { - val returnType = project.findMethod(inst.method).returnType - return LeafVarNode(inst.id, returnType) - } - - override fun visitPandaCallLaunchStaticInstIr(inst: PandaCallLaunchStaticInstIr): LocalVarNode { - val returnType = project.findMethod(inst.method).returnType - return LeafVarNode(inst.id, returnType) - } - - override fun visitPandaNullCheckInstIr(inst: PandaNullCheckInstIr): LocalVarNode { - val bounds = inst.inputs.dropLast(1) - return DependentVarNode(inst.id, bounds) - } - - // TODO: default(inst) - override fun visitPandaZeroCheckInstIr(inst: PandaZeroCheckInstIr): LocalVarNode { - val type = project.findType(inst.type) - return LeafVarNode(inst.id, type) - } - - override fun visitPandaLoadStringInstIr(inst: PandaLoadStringInstIr): LocalVarNode { - val stringType = project.stringClass.type - return LeafVarNode(inst.id, stringType) - } - - override fun visitPandaLoadTypeInstIr(inst: PandaLoadTypeInstIr): LocalVarNode { - val typeType = project.typeClass.type - return LeafVarNode(inst.id, typeType) - } - - override fun visitPandaLoadRuntimeClassInstIr(inst: PandaLoadRuntimeClassInstIr): LocalVarNode? = null - - override fun visitPandaCallVirtualInstIr(inst: PandaCallVirtualInstIr): LocalVarNode { - val returnType = project.findMethod(inst.method).returnType - return LeafVarNode(inst.id, returnType) - } - - override fun visitPandaCallLaunchVirtualInstIr(inst: PandaCallLaunchVirtualInstIr): LocalVarNode { - val returnType = project.findMethod(inst.method).returnType - return LeafVarNode(inst.id, returnType) - } - - override fun visitPandaLoadAndInitClassInstIr(inst: PandaLoadAndInitClassInstIr): LocalVarNode? = null - - override fun visitPandaLoadClassInstIr(inst: PandaLoadClassInstIr): LocalVarNode? = null - - override fun visitPandaInitClassInstIr(inst: PandaInitClassInstIr): LocalVarNode? = null - - override fun visitPandaReturnVoidInstIr(inst: PandaReturnVoidInstIr): LocalVarNode? = null - - override fun visitPandaReturnInstIr(inst: PandaReturnInstIr): LocalVarNode? = null - - override fun visitPandaParameterInstIr(inst: PandaParameterInstIr): LocalVarNode = - if (inst.index == 0 && !method.flags.isStatic) { - ThisNode(inst.id, method.parameterTypes[inst.index]) - } else { - LeafVarNode(inst.id, method.parameterTypes[inst.index]) - } - - override fun visitPandaLoadStaticInstIr(inst: PandaLoadStaticInstIr): LocalVarNode { - val enclosingClass = project.findClass(inst.enclosingClass) - val field = enclosingClass.findField(inst.field) - return LeafVarNode(inst.id, field.type) - } - - override fun visitPandaLoadObjectInstIr(inst: PandaLoadObjectInstIr): LocalVarNode { - val enclosingClass = project.findClass(inst.enclosingClass) - val field = enclosingClass.findField(inst.field) - return LeafVarNode(inst.id, field.type) - } - - override fun visitPandaStoreStaticInstIr(inst: PandaStoreStaticInstIr): LocalVarNode? = null - - override fun visitPandaStoreObjectInstIr(inst: PandaStoreObjectInstIr): LocalVarNode? = null - - override fun visitPandaLoadArrayInstIr(inst: PandaLoadArrayInstIr): LocalVarNode { - val array = inst.inputs.first() - return LoadArrayNode(inst.id, array) - } - - override fun visitPandaStoreArrayInstIr(inst: PandaStoreArrayInstIr): LocalVarNode? = null - - override fun visitPandaCastInstIr(inst: PandaCastInstIr): LocalVarNode = default(inst) - - override fun visitPandaIsInstanceInstIr(inst: PandaIsInstanceInstIr): LocalVarNode = - LeafVarNode(inst.id, PandaPrimitiveType.BOOL) - - override fun visitPandaCheckCastInstIr(inst: PandaCheckCastInstIr): LocalVarNode { - val candidateType = project.findType(inst.candidateType) - return LeafVarNode(inst.id, candidateType) - } - - override fun visitPandaBitcastInstIr(inst: PandaBitcastInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaIfImmInstIr(inst: PandaIfImmInstIr): LocalVarNode? = null - - override fun visitPandaCompareInstIr(inst: PandaCompareInstIr): LocalVarNode = default(inst) - - override fun visitPandaPhiInstIr(inst: PandaPhiInstIr): LocalVarNode? = - DependentVarNode(inst.id, inst.inputs).takeIf { inst.users.isNotEmpty() } - - override fun visitPandaAddInstIr(inst: PandaAddInstIr): LocalVarNode = default(inst) - - override fun visitPandaSubInstIr(inst: PandaSubInstIr): LocalVarNode = default(inst) - - override fun visitPandaMulInstIr(inst: PandaMulInstIr): LocalVarNode = default(inst) - - override fun visitPandaDivInstIr(inst: PandaDivInstIr): LocalVarNode = default(inst) - - override fun visitPandaModInstIr(inst: PandaModInstIr): LocalVarNode = default(inst) - - override fun visitPandaAndInstIr(inst: PandaAndInstIr): LocalVarNode = default(inst) - - override fun visitPandaOrInstIr(inst: PandaOrInstIr): LocalVarNode = default(inst) - - override fun visitPandaXorInstIr(inst: PandaXorInstIr): LocalVarNode = default(inst) - - override fun visitPandaShlInstIr(inst: PandaShlInstIr): LocalVarNode = default(inst) - - override fun visitPandaShrInstIr(inst: PandaShrInstIr): LocalVarNode = default(inst) - - override fun visitPandaAShlInstIr(inst: PandaAShlInstIr): LocalVarNode = default(inst) - - override fun visitPandaAShrInstIr(inst: PandaAShrInstIr): LocalVarNode = default(inst) - - override fun visitPandaCmpInstIr(inst: PandaCmpInstIr): LocalVarNode = default(inst) - - override fun visitPandaThrowInstIr(inst: PandaThrowInstIr): LocalVarNode? = null - - override fun visitPandaNegativeCheckInstIr(inst: PandaNegativeCheckInstIr): LocalVarNode = default(inst) - - override fun visitPandaSaveStateDeoptimizeInstIr(inst: PandaSaveStateDeoptimizeInstIr): LocalVarNode? = null - - override fun visitPandaNegInstIr(inst: PandaNegInstIr): LocalVarNode = default(inst) - - override fun visitPandaNotInstIr(inst: PandaNotInstIr): LocalVarNode = default(inst) - - override fun visitPandaLenArrayInstIr(inst: PandaLenArrayInstIr): LocalVarNode = default(inst) - - override fun visitPandaBoundsCheckInstIr(inst: PandaBoundsCheckInstIr): LocalVarNode = default(inst) - - override fun visitPandaNullPtrInstIr(inst: PandaNullPtrInstIr): LocalVarNode { - val objectType = project.objectClass.type - return LeafVarNode(inst.id, objectType) - } - - override fun visitPandaLoadUndefinedInstIr(inst: PandaLoadUndefinedInstIr): LocalVarNode { - val undefinedType = project.undefinedClass.type - return LeafVarNode(inst.id, undefinedType) - } - - override fun visitPandaRefTypeCheckInstIr(inst: PandaRefTypeCheckInstIr): LocalVarNode { - val bounds = inst.inputs.take(1) - return DependentVarNode(inst.id, bounds) - } - - override fun visitPandaTryInstIr(inst: PandaTryInstIr): LocalVarNode? = null - - override fun visitPandaCatchPhiInstIr(inst: PandaCatchPhiInstIr): LocalVarNode? = - if (inst.inputs.isNotEmpty()) { - DependentVarNode(inst.id, inst.inputs).takeIf { inst.users.isNotEmpty() } - } else { - val throwableType = handledType ?: project.objectClass.type - LeafVarNode(inst.id, throwableType) - } - - override fun visitPandaIntrinsicInstIr(inst: PandaIntrinsicInstIr): LocalVarNode { - val type = project.resolveIntrinsic(inst.intrinsicId)?.returnType ?: project.objectClass.type - return LeafVarNode(inst.id, type) - } - - override fun visitPandaLoadFromConstantPoolInstIr(inst: PandaLoadFromConstantPoolInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaResolveStaticInstIr(inst: PandaResolveStaticInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaResolveVirtualInstIr(inst: PandaResolveVirtualInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaCallDynamicInstIr(inst: PandaCallDynamicInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaCallResolvedVirtualInstIr(inst: PandaCallResolvedVirtualInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaCallResolvedStaticInstIr(inst: PandaCallResolvedStaticInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaFillConstArrayInstIr(inst: PandaFillConstArrayInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaBuiltinInstIr(inst: PandaBuiltinInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaLoadResolvedObjectFieldInstIr(inst: PandaLoadResolvedObjectFieldInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaLoadResolvedObjectFieldStaticInstIr(inst: PandaLoadResolvedObjectFieldStaticInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaStoreResolvedObjectFieldInstIr(inst: PandaStoreResolvedObjectFieldInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaStoreResolvedObjectFieldStaticInstIr(inst: PandaStoreResolvedObjectFieldStaticInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaLoadObjectDynamicInstIr(inst: PandaLoadObjectDynamicInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaStoreObjectDynamicInstIr(inst: PandaStoreObjectDynamicInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaFunctionImmediateInstIr(inst: PandaFunctionImmediateInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaHclassCheckInstIr(inst: PandaHclassCheckInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaLoadObjFromConstInstIr(inst: PandaLoadObjFromConstInstIr): LocalVarNode? { - TODO("Not yet implemented") - } - - override fun visitPandaLoadImmediateInstIr(inst: PandaLoadImmediateInstIr): LocalVarNode? { - TODO("Not yet implemented") - } -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaExpr.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaExpr.kt deleted file mode 100644 index 53af09867..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaExpr.kt +++ /dev/null @@ -1,503 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.cfg - -import org.jacodb.api.common.cfg.CommonArgument -import org.jacodb.api.common.cfg.CommonArrayAccess -import org.jacodb.api.common.cfg.CommonCallExpr -import org.jacodb.api.common.cfg.CommonExpr -import org.jacodb.api.common.cfg.CommonFieldRef -import org.jacodb.api.common.cfg.CommonInstanceCallExpr -import org.jacodb.api.common.cfg.CommonThis -import org.jacodb.api.common.cfg.CommonValue -import org.jacodb.panda.staticvm.classpath.PandaClassType -import org.jacodb.panda.staticvm.classpath.PandaField -import org.jacodb.panda.staticvm.classpath.PandaMethod -import org.jacodb.panda.staticvm.classpath.PandaPrimitiveType -import org.jacodb.panda.staticvm.classpath.PandaType - -sealed interface PandaExpr : CommonExpr { - val type: PandaType - - override val typeName: String - get() = type.typeName - - val operands: List -} - -sealed interface PandaValue : PandaExpr, CommonValue - -interface PandaSimpleValue : PandaValue { - override val operands: List - get() = emptyList() -} - -class PandaArgument( - val index: Int, - val name: String, - override val type: PandaType, -) : PandaSimpleValue, CommonArgument { - override fun toString(): String = "$name(${type.typeName})" -} - -sealed interface PandaLocalVar : PandaSimpleValue { - val name: String - override val type: PandaType -} - -class PandaLocalVarImpl( - override val name: String, - override val type: PandaType, -) : PandaLocalVar { - override fun toString(): String = name -} - -class PandaThis( - override val name: String, - override val type: PandaType, -) : PandaLocalVar, CommonThis { - override fun toString(): String = name -} - -class PandaFieldRef( - override val instance: PandaValue?, - val field: PandaField, -) : PandaValue, CommonFieldRef { - - override val type: PandaType - get() = this.field.type - - override val operands: List - get() = listOfNotNull(instance) - - override fun toString(): String = "${instance ?: field.enclosingClass.name}.${field.name}" -} - -class PandaArrayAccess( - override val array: PandaValue, - override val index: PandaValue, - override val type: PandaType, -) : PandaValue, CommonArrayAccess { - override val operands: List - get() = listOf(array, index) - - override fun toString(): String = "$array[$index]" -} - -sealed interface PandaConstant : PandaSimpleValue - -object PandaNull : PandaConstant { - override val type: PandaType - get() = PandaPrimitiveType.NULL - - override fun toString(): String = "null" -} - -data class PandaUndefined(override val type: PandaType) : PandaConstant { - override fun toString(): String = "undefined" -} - -data class PandaBoolean( - val value: Boolean, -) : PandaConstant { - override val type: PandaPrimitiveType - get() = PandaPrimitiveType.BYTE - - override fun toString(): String = "$value" -} - -data class PandaByte( - val value: Byte, -) : PandaConstant { - override val type: PandaType - get() = PandaPrimitiveType.BYTE - - override fun toString(): String = "$value" -} - -data class PandaShort( - val value: Short, -) : PandaConstant { - override val type: PandaType - get() = PandaPrimitiveType.SHORT - - override fun toString(): String = "$value" -} - -data class PandaInt( - val value: Int, -) : PandaConstant { - override val type: PandaType - get() = PandaPrimitiveType.INT - - override fun toString(): String = "$value" -} - -data class PandaLong( - val value: Long, -) : PandaConstant { - override val type: PandaType - get() = PandaPrimitiveType.LONG - - override fun toString(): String = "$value" -} - -data class PandaUByte( - val value: UByte, -) : PandaConstant { - override val type: PandaType - get() = PandaPrimitiveType.UBYTE - - override fun toString(): String = "$value" -} - -data class PandaUShort( - val value: UShort, -) : PandaConstant { - override val type: PandaType - get() = PandaPrimitiveType.USHORT - - override fun toString(): String = "$value" -} - -data class PandaUInt( - val value: UInt, -) : PandaConstant { - override val type: PandaType - get() = PandaPrimitiveType.UINT - - override fun toString(): String = "$value" -} - -data class PandaULong( - val value: ULong, -) : PandaConstant { - override val type: PandaType - get() = PandaPrimitiveType.ULONG - - override fun toString(): String = "$value" -} - -data class PandaFloat( - val value: Float, -) : PandaConstant { - override val type: PandaType - get() = PandaPrimitiveType.FLOAT - - override fun toString(): String = "$value" -} - -data class PandaDouble( - val value: Double, -) : PandaConstant { - override val type: PandaType - get() = PandaPrimitiveType.DOUBLE - - override fun toString(): String = "$value" -} - -data class PandaString( - val value: String, - override val type: PandaClassType, // TODO: StringType (std.core.String) -) : PandaConstant { - override fun toString(): String = "\"$value\"" -} - -data class PandaTypeConstant( - val value: PandaType, - override val type: PandaType, // TODO: ClassType -) : PandaConstant { - override fun toString(): String = "${value}.class" -} - -data class PandaNewExpr( - override val type: PandaType, -) : PandaExpr { - override val operands: List - get() = emptyList() - - override fun toString(): String = "new ${type.typeName}" -} - -interface PandaUnaryExpr : PandaExpr { - val arg: PandaValue - - override val operands: List - get() = listOf(arg) -} - -data class PandaNegExpr( - override val type: PandaType, - override val arg: PandaValue, -) : PandaUnaryExpr { - override fun toString(): String = "-$arg" -} - -data class PandaNotExpr( - override val type: PandaType, - override val arg: PandaValue, -) : PandaUnaryExpr { - override fun toString(): String = "!$arg" -} - -data class PandaLenArrayExpr( - override val type: PandaType, - override val arg: PandaValue, -) : PandaUnaryExpr { - override fun toString(): String = "length($arg)" -} - -data class PandaCastExpr( - override val type: PandaType, - override val arg: PandaValue, -) : PandaUnaryExpr { - override fun toString(): String = "($type) $arg" -} - -data class PandaIsInstanceExpr( - override val type: PandaType, - override val arg: PandaValue, - val candidateType: PandaType, -) : PandaUnaryExpr { - override fun toString(): String = "$arg is $candidateType" -} - -sealed interface PandaBinaryExpr : PandaExpr { - val lhv: PandaValue - val rhv: PandaValue - - override val operands: List - get() = listOf(lhv, rhv) -} - -data class PandaAddExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv + $rhv" -} - -data class PandaSubExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv - $rhv" -} - -data class PandaMulExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv * $rhv" -} - -data class PandaDivExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv / $rhv" -} - -data class PandaModExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv % $rhv" -} - -data class PandaAndExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv & $rhv" -} - -data class PandaOrExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv | $rhv" -} - -data class PandaXorExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv ^ $rhv" -} - -data class PandaShlExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv << $rhv" -} - -data class PandaShrExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv >> $rhv" -} - -data class PandaAshlExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv a<< $rhv" -} - -data class PandaAshrExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv a>> $rhv" -} - -data class PandaCmpExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaBinaryExpr { - override fun toString(): String = "$lhv cmp $rhv" -} - -interface PandaConditionExpr : PandaBinaryExpr - -data class PandaLeExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaConditionExpr { - override fun toString(): String = "$lhv <= $rhv" -} - -data class PandaLtExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaConditionExpr { - override fun toString(): String = "$lhv < $rhv" -} - -data class PandaGeExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaConditionExpr { - override fun toString(): String = "$lhv >= $rhv" -} - -data class PandaGtExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaConditionExpr { - override fun toString(): String = "$lhv > $rhv" -} - -data class PandaEqExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaConditionExpr { - override fun toString(): String = "$lhv == $rhv" -} - -data class PandaNeExpr( - override val type: PandaType, - override val lhv: PandaValue, - override val rhv: PandaValue, -) : PandaConditionExpr { - override fun toString(): String = "$lhv != $rhv" -} - -sealed interface PandaCallExpr : PandaExpr, CommonCallExpr { - val method: PandaMethod - override val args: List - override val operands: List - get() = args -} - -data class PandaStaticCallExpr( - override val method: PandaMethod, - override val operands: List, -) : PandaCallExpr { - override val type: PandaType = method.returnType - - override val args: List - get() = operands - - override fun toString(): String = "${method.enclosingClass.name}::${method.name}(${operands.joinToString(", ")})" -} - -data class PandaIntrinsicCallExpr( - val intrinsic: String, - override val type: PandaType, - override val operands: List, -) : PandaExpr, CommonCallExpr { - override val args: List - get() = operands - - override fun toString(): String = "intrinsic<${intrinsic}>(${operands.joinToString(", ")})" -} - -data class PandaVirtualCallExpr( - override val method: PandaMethod, - override val instance: PandaValue, - override val operands: List, -) : PandaCallExpr, CommonInstanceCallExpr { - override val type: PandaType = method.returnType - - override val args: List - get() = operands - - override fun toString(): String = "${instance}.${method.name}(${operands.joinToString(", ")})" -} - -data class PandaPhiExpr( - override val type: PandaType, - val inputs: List, - val predecessors: List, -) : PandaExpr { - override val operands: List - get() = inputs - - override fun toString(): String = "Phi(${inputs.joinToString(", ")})" -} - -data class PandaNewArrayExpr( - override val type: PandaType, - val length: PandaValue, -) : PandaExpr { - override val operands: List - get() = listOf(length) - - override fun toString(): String = "new $type[$length]" -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaGraphToDot.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaGraphToDot.kt deleted file mode 100644 index 7e5476a74..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaGraphToDot.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.cfg - -fun PandaGraph.toDot(): String = buildString { - appendLine("digraph {") - appendLine(" rankdir=LR;") - appendLine(" compound=true;") - - instructions.forEachIndexed { index, inst -> - appendLine("\"inst_$index\" [shape=box, label=\"index=$index\\l${inst.toString().replace("\"", "\\\"")}\\l\"]") - } - - instructions.forEach { from -> - successors(from).forEach { to -> - appendLine("\"inst_${index(from)}\" -> \"inst_${index(to)}\"") - } - if (from is PandaTryPseudoInst) { - from.catchers.forEach { to -> - appendLine("\"inst_${index(from)}\" -> \"inst_${to.index}\" [label=\"catch\", style=\"dashed\"]") - } - } - } - - appendLine("}") -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaInst.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaInst.kt deleted file mode 100644 index 58542523e..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaInst.kt +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.cfg - -import org.jacodb.api.common.cfg.CommonAssignInst -import org.jacodb.api.common.cfg.CommonGotoInst -import org.jacodb.api.common.cfg.CommonIfInst -import org.jacodb.api.common.cfg.CommonInst -import org.jacodb.api.common.cfg.CommonInstLocation -import org.jacodb.api.common.cfg.CommonReturnInst -import org.jacodb.panda.staticvm.classpath.PandaMethod - -data class PandaInstLocation( - override val method: PandaMethod, - val index: Int, -) : CommonInstLocation { - // TODO: expand like JcInstLocation - - // override val lineNumber: Int - // get() = 0 // TODO("Not yet implemented") - - override fun toString(): String = "${method.name}:$index" -} - -data class PandaInstRef( - val index: Int, -) { - override fun toString(): String = index.toString() -} - -sealed interface PandaInst : CommonInst { - override val location: PandaInstLocation - - override val method: PandaMethod - get() = location.method - - // TODO: remove 'operands' - val operands: List -} - -class PandaDoNothingInst( - override val location: PandaInstLocation, -) : PandaInst { - override val operands: List - get() = emptyList() - - override fun toString(): String = "NOP" -} - -class PandaParameterInst( - override val location: PandaInstLocation, - val lhv: PandaValue, - val index: Int, -) : PandaInst { - override val operands: List - get() = emptyList() - - override fun toString(): String = "$lhv = arg$index" -} - -class PandaAssignInst( - override val location: PandaInstLocation, - override val lhv: PandaValue, - override val rhv: PandaExpr, -) : PandaInst, CommonAssignInst { - override val operands: List - get() = listOf(lhv, rhv) - - override fun toString(): String = "$lhv = $rhv" -} - -sealed interface PandaBranchingInst : PandaInst { - val successors: List -} - -class PandaIfInst( - override val location: PandaInstLocation, - val condition: PandaConditionExpr, - val trueBranch: PandaInstRef, - val falseBranch: PandaInstRef, -) : PandaBranchingInst, CommonIfInst { - override val operands: List - get() = listOf(condition) - - override val successors: List - get() = listOf(trueBranch, falseBranch) - - override fun toString(): String = "if ($condition) goto ${trueBranch.index} else goto ${falseBranch.index}" -} - -class PandaGotoInst( - override val location: PandaInstLocation, - val target: PandaInstRef, -) : PandaBranchingInst, CommonGotoInst { - override val operands: List - get() = emptyList() - - override val successors: List - get() = listOf(target) - - override fun toString(): String = "goto ${target.index}" -} - -sealed interface PandaTerminatingInst : PandaInst - -class PandaReturnInst( - override val location: PandaInstLocation, - override val returnValue: PandaValue?, -) : PandaTerminatingInst, CommonReturnInst { - override val operands: List - get() = emptyList() - - override fun toString(): String = - if (returnValue != null) { - "return $returnValue" - } else { - "return" - } -} - -class PandaThrowInst( - override val location: PandaInstLocation, - val error: PandaValue, - val catchers: List, -) : PandaTerminatingInst { - override val operands: List - get() = listOf(error) - - override fun toString(): String = "throw $error" -} - -class PandaPhiInst( - override val location: PandaInstLocation, - val lhv: PandaValue, - val phiInputs: List, -) : PandaInst { - data class PhiInput(val value: PandaValue, val cfgBranch: PandaInstRef) - - val inputs: List - get() = phiInputs.map { it.value } - - override val operands: List - get() = inputs - - override fun toString() = "$lhv = Phi(${ - phiInputs.joinToString { "${it.value} <- ${it.cfgBranch}" } - })" -} - -class PandaCatchInst( - override val location: PandaInstLocation, - val throwable: PandaValue, - val throwers: List, -) : PandaInst { - override val operands: List - get() = emptyList() - - override fun toString(): String = "catch($throwable: ${throwable.typeName})" -} - -class PandaTryPseudoInst( - override val location: PandaInstLocation, - val catchers: List, -) : PandaInst { - override val operands: List - get() = emptyList() - - override fun toString(): String = "try" -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaInstList.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaInstList.kt deleted file mode 100644 index c67ea5061..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/cfg/PandaInstList.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.cfg - -import org.jacodb.api.common.cfg.InstList -import org.jacodb.api.common.cfg.MutableInstList - -class PandaInstList(override val instructions: List) : InstList { - override val size: Int - get() = instructions.size - override val indices: IntRange - get() = instructions.indices - override val lastIndex: Int - get() = instructions.lastIndex - - override fun get(index: Int): PandaInst = instructions[index] - - override fun getOrNull(index: Int): PandaInst? = instructions.getOrNull(index) - - override fun toMutableList(): MutableInstList = PandaMutableInstList(instructions.toMutableList()) - - override fun iterator(): Iterator = instructions.iterator() - - override fun toString(): String = instructions.joinToString(separator = "\n") { "${it.location.index}: $it" } -} - -data class PandaMutableInstList(override val instructions: MutableList) : MutableInstList { - override fun insertBefore(inst: PandaInst, vararg newInstructions: PandaInst) = - insertBefore(inst, newInstructions.toList()) - - override fun insertBefore(inst: PandaInst, newInstructions: Collection): Unit = - instructions.run { addAll(indexOf(inst), newInstructions) } - - override fun insertAfter(inst: PandaInst, vararg newInstructions: PandaInst) = - insertAfter(inst, newInstructions.toList()) - - override fun insertAfter(inst: PandaInst, newInstructions: Collection): Unit = - instructions.run { addAll(indexOf(inst) + 1, newInstructions) } - - override fun remove(inst: PandaInst): Boolean = instructions.remove(inst) - - override fun removeAll(inst: Collection): Boolean = instructions.removeAll(inst) - - override val size: Int - get() = instructions.size - override val indices: IntRange - get() = instructions.indices - override val lastIndex: Int - get() = instructions.lastIndex - - override fun get(index: Int): PandaInst = instructions[index] - - override fun getOrNull(index: Int): PandaInst? = instructions.getOrNull(index) - - override fun toMutableList(): MutableInstList = this - - override fun iterator(): Iterator = instructions.iterator() - -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/AccessFlags.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/AccessFlags.kt deleted file mode 100644 index 3c9a11eb4..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/AccessFlags.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.classpath - -data class AccessFlags(val flags: Int) { - val isPublic: Boolean - get() = flags and 0x0001 > 0 - val isPrivate: Boolean - get() = flags and 0x0002 > 0 - val isProtected: Boolean - get() = flags and 0x0004 > 0 - val isPackagePrivate: Boolean - get() = false - val isStatic: Boolean - get() = flags and 0x0008 > 0 - val isFinal: Boolean - get() = flags and 0x0010 > 0 - val isInterface: Boolean - get() = flags and 0x0200 > 0 - val isAbstract: Boolean - get() = flags and 0x0400 > 0 - val isSynthetic: Boolean - get() = flags and 0x1000 > 0 -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/ClassNodes.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/ClassNodes.kt deleted file mode 100644 index 27cc5fa93..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/ClassNodes.kt +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.classpath - -import org.jacodb.api.common.CommonMethod -import org.jacodb.api.common.CommonMethodParameter -import org.jacodb.panda.staticvm.cfg.PandaGraph - -class PandaField( - val enclosingClass: PandaClassOrInterface, - val name: String, - val type: PandaType, - val flags: AccessFlags, -) { - val signature: String - get() = "${enclosingClass.name}.$name" -} - -class PandaMethod( - val signature: String, - override val name: String, - val enclosingClass: PandaClassOrInterface, - override val returnType: PandaType, - val parameterTypes: List, - val flags: AccessFlags, -) : CommonMethod { - - data class Parameter( - override val type: PandaType, - val index: Int, - // val method: PandaMethod, - ) : CommonMethodParameter { - val name: String? - get() = null - } - - override val parameters: List - get() = parameterTypes.mapIndexed { index, typeName -> - // Parameter(typeName, index, this) - Parameter(typeName, index) - } - - override fun flowGraph(): PandaGraph { - return enclosingClass.project.flowGraph(this) - } - - // TODO: equals - - override fun toString(): String { - return "${enclosingClass.name}::$name(${parameterTypes.joinToString { it.typeName }})" - } -} - -sealed interface PandaClassOrInterface { - val project: PandaProject - - val name: String - - val simpleName: String - get() = name.substringAfterLast('.') - - val directSuperClass: PandaClass? - val directSuperInterfaces: Set - - val declaredFields: HashMap - val declaredMethods: HashMap - - val flags: AccessFlags - - fun findFieldOrNull(name: String): PandaField? = - declaredFields[name] ?: directSuperClass?.findFieldOrNull(name) - - fun findMethodOrNull(name: String): PandaMethod? = - declaredMethods[name] ?: directSuperClass?.findMethodOrNull(name) - - fun findField(name: String) = requireNotNull(findFieldOrNull(name)) - fun findMethod(name: String) = requireNotNull(findMethodOrNull(name)) - - fun findMethodBySimpleNameOrNull(name: String): PandaMethod? = declaredMethods.values.find { it.name == name } - ?: directSuperClass?.findMethodBySimpleNameOrNull(name) - - fun findMethodBySimpleName(name: String) = requireNotNull(findMethodBySimpleNameOrNull(name)) - - val fields: List - get() = (directSuperClass?.fields ?: emptyList()) + declaredFields.values - - val methods: List - get() = (directSuperClass?.methods ?: emptyList()) + declaredMethods.values - - val type: PandaObjectType -} - -class PandaClass( - override val project: PandaProject, - override val name: String, - override val directSuperClass: PandaClass?, - override val directSuperInterfaces: Set, - override val flags: AccessFlags, - override val declaredFields: HashMap = hashMapOf(), - override val declaredMethods: HashMap = hashMapOf(), -) : PandaClassOrInterface { - override val type: PandaClassType - get() = PandaClassType(project, this) - - override fun toString(): String = name -} - -class PandaInterface( - override val project: PandaProject, - override val name: String, - override val directSuperInterfaces: Set, - override val flags: AccessFlags, - override val declaredFields: HashMap = hashMapOf(), - override val declaredMethods: HashMap = hashMapOf(), -) : PandaClassOrInterface { - override val directSuperClass: PandaClass? - get() = null - - override val type: PandaInterfaceType - get() = PandaInterfaceType(project, this) - - override fun toString(): String = name -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/Intrinsics.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/Intrinsics.kt deleted file mode 100644 index e0bcb4f54..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/Intrinsics.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.classpath - -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.decodeFromStream - -object Intrinsics { - @Serializable - data class IntrinsicMethod( - val intrinsicId: String, - val className: String?, - val methodName: String?, - ) - - private val intrinsicsMapping: Map = run { - val resource = this::class.java.getResourceAsStream("/intrinsics.json") - ?: error("Intrinsics mapping not found") - - @OptIn(ExperimentalSerializationApi::class) - val intrinsics: List = Json.decodeFromStream(resource) - - intrinsics.associateBy { it.intrinsicId } - } - - fun resolve(id: String): Pair? = intrinsicsMapping[id]?.let { - if (it.className != null && it.methodName != null) { - Pair(it.className, it.methodName) - } else { - null - } - } -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/PandaPrimitives.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/PandaPrimitives.kt deleted file mode 100644 index 08b6c7e91..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/PandaPrimitives.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.classpath - -enum class PandaPrimitiveType( - // override val project: PandaProject, - override val typeName: String, -) : PandaSingleType { - VOID("void"), - NULL("null"), - BOOL("u1"), - BYTE("i8"), - UBYTE("u8"), - SHORT("i16"), - USHORT("u16"), - INT("i32"), - UINT("u32"), - LONG("i64"), - ULONG("u64"), - FLOAT("f32"), - DOUBLE("f64"); - - override fun toString(): String = typeName - - override val nullable: Boolean? - get() = false -} - -object PandaPrimitives { - fun findPrimitiveOrNull(name: String): PandaPrimitiveType? = - enumValues().find { it.typeName == name } - - fun find(name: String) = requireNotNull(findPrimitiveOrNull(name)) { - "Not found primitive $name" - } -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/PandaProject.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/PandaProject.kt deleted file mode 100644 index c2d1e1893..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/PandaProject.kt +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.classpath - -import org.jacodb.api.common.CommonProject -import org.jacodb.panda.staticvm.cfg.PandaGraph -import org.jacodb.panda.staticvm.ir.EtsStdlib -import org.jacodb.panda.staticvm.ir.PandaBasicBlockIr -import org.jacodb.panda.staticvm.ir.PandaProgramIr - -class PandaProject : CommonProject { - - private val autoInitializedClasses = mutableListOf() - - private fun newBlankClass( - name: String, - parent: PandaClass?, - interfaces: Collection = emptySet(), - accessFlags: AccessFlags = AccessFlags(1), - ) = PandaClass( - project = this, - name = name, - directSuperClass = parent, - directSuperInterfaces = interfaces.toSet(), - flags = accessFlags, - ).also { autoInitializedClasses.add(it) } - - val objectClass = newBlankClass("std.core.Object", null) - val stringClass = newBlankClass("std.core.String", objectClass) - val undefinedClass = newBlankClass("std.core.Undefined", objectClass) - val typeClass = newBlankClass("std.core.Type", objectClass) - val voidClass = newBlankClass("std.core.Void", objectClass) - - private val classesIndex = hashMapOf>() - private val classesPool = hashSetOf() - - private val interfacesIndex = hashMapOf() - private val interfacesPool = hashSetOf() - - private val methodIndex = hashMapOf() - - init { - autoInitializedClasses.forEach { this.addClass(it) } - } - - private data class TreeEntry( - val depth: Int, - val parent: TreeEntry?, - val data: T, - ) - - fun addClass(node: PandaClass): Boolean { - if (classesIndex.containsKey(node.name)) - return false - - require(interfacesPool.containsAll(node.directSuperInterfaces)) - val parentNode = node.directSuperClass?.let { requireNotNull(classesIndex[it.name]) } - ?: classesIndex[objectClass.name] - - classesIndex[node.name] = TreeEntry(parentNode?.depth?.inc() ?: 0, parentNode, node) - classesPool.add(node) - return true - } - - fun addInterface(node: PandaInterface): Boolean { - require(interfacesPool.containsAll(node.directSuperInterfaces)) - interfacesPool.add(node) - return interfacesIndex.putIfAbsent(node.name, node) == null - } - - fun addField(field: PandaField): Boolean { - require(field.enclosingClass in classesPool) - return field.enclosingClass.declaredFields.putIfAbsent(field.name, field) == null - } - - fun addMethod(method: PandaMethod): Boolean { - require(method.enclosingClass in classesPool || method.enclosingClass in interfacesPool) - method.parameterTypes.forEach { - requireNotNull(findTypeOrNull(it.typeName)) { - "Not found type ${it.typeName}" - } - } - if (method.signature in methodIndex) return false - methodIndex[method.signature] = method - method.enclosingClass.declaredMethods[method.signature] = method - return true - } - - fun addFlowGraph(method: PandaMethod, basicBlocksInfo: List): Boolean { - require(method.enclosingClass in classesPool || method.enclosingClass in interfacesPool) - // TODO: use lazy putIfAbsent - return flowGraphs.putIfAbsent(method, PandaGraph.of(method, basicBlocksInfo)) == null - } - - fun findClassOrNull(name: String): PandaClass? = classesIndex[name]?.data - fun findInterfaceOrNull(name: String): PandaInterface? = interfacesIndex[name] - fun findClassOrInterfaceOrNull(name: String): PandaClassOrInterface? = - classesIndex[name]?.data ?: interfacesIndex[name] - - fun findMethod(name: String): PandaMethod = requireNotNull(methodIndex[name]) { - "Not found method $name" - } - - companion object { - fun fromProgramIr(program: PandaProgramIr, withStdLib: Boolean = false): PandaProject { - val project = PandaProject() - if (withStdLib) { - project.addProgramIr(EtsStdlib.program) - } - project.addProgramIr(program) - return project - } - } - - fun addProgramIr(program: PandaProgramIr) { - program.addInterfacesHierarchyToPandaClasspath(this) - program.addClassesHierarchyToPandaClasspath(this) - program.addFieldsToPandaClasspath(this) - program.addMethodsToPandaClasspath(this) - program.addFlowGraphsToPandaClasspath(this) - } - - fun findTypeOrNull(name: String): PandaType? = - if (name.endsWith("[]")) { - findTypeOrNull(name.removeSuffix("[]"))?.array - } else { - PandaPrimitives.findPrimitiveOrNull(name) ?: findClassOrInterfaceOrNull(name)?.type - } - - fun findType(name: String) = requireNotNull(findTypeOrNull(name)) { - "Not found type $name" - } - - fun findClass(name: String) = requireNotNull(findClassOrNull(name)) { - "Not found class $name" - } - - fun findClassOrInterface(name: String) = requireNotNull(findClassOrInterfaceOrNull(name)) { - "Not found class or interface $name" - } - - fun getElementType(name: String): PandaType = - if (name.endsWith("[]")) { - findType(name.removeSuffix("[]")) - } else { - throw IllegalArgumentException("Expected array type") - } - - private val flowGraphs: MutableMap = hashMapOf() - - val classes: List - get() = classesIndex.values.map { it.data } - - val methods: List - get() = methodIndex.values.toList() - - // TODO: why PUT empty graph? why not just use 'flowGraphs[method] ?: PandaGraph.empty()' - fun flowGraph(method: PandaMethod): PandaGraph = flowGraphs.getOrPut(method) { PandaGraph.empty() } - - private fun ancestors(node: TreeEntry): List = - (node.parent?.let { ancestors(it) } ?: emptyList()).plus(node.data.type) - - fun commonClassType(types: Collection): PandaClassType? { - if (types.isEmpty()) return objectClass.type - val nodes = types.map { - requireNotNull(classesIndex[it.typeName]) { - "Not found class ${it.typeName}" - } - } - val paths = nodes.map { ancestors(it) } - return paths.reduce { p1, p2 -> - p1.zip(p2) { t1, t2 -> t1.takeIf { t1 == t2 } }.filterNotNull() - }.lastOrNull() - } - - fun commonType(types: Collection): PandaType? { - if (types.any { it is PandaArrayType }) { - return types.takeIf { it.all { it is PandaArrayType } } - ?.filterIsInstance() - ?.map { it.elementType } - ?.let(this::commonType) - ?.array - ?: objectClass.type - } - if (types.any { it is PandaPrimitiveType }) { - return types.takeIf { it.all { it is PandaPrimitiveType } } - ?.filterIsInstance() - ?.max() - } - return commonClassType(types.filterIsInstance()) - } - - fun resolveIntrinsic(id: String) = Intrinsics.resolve(id)?.let { (className, methodName) -> - findClassOrInterface(className).findMethodBySimpleName(methodName) - } -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/Types.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/Types.kt deleted file mode 100644 index aff82a755..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/classpath/Types.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.classpath - -import org.jacodb.api.common.CommonType -import org.jacodb.api.common.CommonTypeName - -sealed interface PandaType : CommonType, CommonTypeName { - val array: PandaArrayType -} - -data class PandaArrayType( - val dimensions: Int, - private val wrappedType: PandaSingleType, -) : PandaType { - init { - require(dimensions > 0) { "Cannot create array with $dimensions dimensions" } - } - - override val typeName: String - get() = wrappedType.typeName + "[]".repeat(dimensions) - - override val nullable: Boolean - get() = true - - val elementType: PandaType - get() = if (dimensions == 1) { - wrappedType - } else { - PandaArrayType(dimensions - 1, wrappedType) - } - - override val array: PandaArrayType - get() = PandaArrayType(dimensions + 1, wrappedType) - - override fun toString(): String = "$elementType[]" -} - -/** any kind of non-array type */ -sealed interface PandaSingleType : PandaType { - override val array: PandaArrayType - get() = PandaArrayType(1, this) -} - -sealed interface PandaObjectType : PandaSingleType { - val project: PandaProject - - val pandaClassOrInterface: PandaClassOrInterface - - override val typeName: String - get() = pandaClassOrInterface.name - - override val nullable: Boolean - get() = true -} - -data class PandaClassType( - override val project: PandaProject, - override val pandaClassOrInterface: PandaClass, -) : PandaObjectType { - override fun toString(): String = pandaClassOrInterface.name -} - -data class PandaInterfaceType( - override val project: PandaProject, - override val pandaClassOrInterface: PandaInterface, -) : PandaObjectType { - override fun toString(): String = pandaClassOrInterface.name -} - -data class PandaUnionType( - val types: Set, -) : PandaSingleType { - init { - require(types.isNotEmpty()) { "Cannot create empty union type" } - } - - override val typeName: String - get() = types.joinToString(" | ") { it.typeName } - - override val nullable: Boolean - get() = TODO() - - val methods: List - get() = types.flatMap { if (it is PandaObjectType) it.pandaClassOrInterface.methods else emptyList() } - - override fun toString(): String = typeName -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ets/Parameter.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ets/Parameter.kt deleted file mode 100644 index 5a845dd07..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ets/Parameter.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.ets - -data class Parameter( - val td: TypeDesc, - val name: String, - val attributes: Attributes, -) { - val type: Type - get() = Type.resolve(td)!! - - fun isRest(): Boolean = attributes.isRest() - fun isOptional(): Boolean = attributes.isOptional() - - override fun toString(): String = "$name: $type" -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ets/Type.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ets/Type.kt deleted file mode 100644 index 52ec0ab87..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ets/Type.kt +++ /dev/null @@ -1,872 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.ets - -/** - * Type descriptor. - * - * ``` - * TypeDescriptor -> PrimitiveType | ArrayType | RefType - * PrimitiveType -> 'Z' | 'B' | 'H' | 'S' | 'C' | 'I' | 'U' | 'J' | 'Q' | 'F' | 'D' | 'A' - * ArrayType -> '[' TypeDescriptor - * RefType -> 'L' ClassName ';' - * ``` - * - * `PrimitiveType` is a one letter encoding for primitive type - * - * | Type | Encoding | - * | ---- | :--: | - * | `u1` | `Z` | - * | `i8` | `B` | - * | `u8` | `H` | - * | `i16` | `S` | - * | `u16` | `C` | - * | `i32` | `I` | - * | `u32` | `U` | - * | `f32` | `F` | - * | `f64` | `D` | - * | `i64` | `J` | - * | `u64` | `Q` | - * | `any` | `A` | - * - * `ClassName` is a qualified name of a class with `.` replaced with `/`. - */ -data class TypeDesc(val typeDesc: String) { - override fun toString(): String = typeDesc - - fun getKind(): TypeKind { - return if (this == NULL) { - TypeKind.NULL - } else if (typeDesc[0] == 'M') { - TypeKind.METHOD - } else if (typeDesc[0] == 'V') { - TypeKind.VOID - } else if (typeDesc[0] == '[') { - TypeKind.ARRAY - } else if (typeDesc[0] == 'L') { - check(typeDesc.last() == ';') - val className = typeDesc.substring(1, typeDesc.length - 1) - when (className) { - "std/core/Boolean" -> { - TypeKind.BOOLEAN - } - - "std/core/Byte" -> { - TypeKind.BYTE - } - - "std/core/Char" -> { - TypeKind.CHAR - } - - "std/core/Short" -> { - TypeKind.SHORT - } - - "std/core/Int" -> { - TypeKind.INT - } - - "std/core/Long" -> { - TypeKind.LONG - } - - "std/core/Float" -> { - TypeKind.FLOAT - } - - "std/core/Double" -> { - TypeKind.DOUBLE - } - - "std/core/__internal_undefined" -> { - TypeKind.UNDEFINED - } - - else -> { - TypeKind.CLASS - } - } - } else when (this) { - ValueTypeDesc.BOOLEAN -> TypeKind.BOOLEAN - ValueTypeDesc.BYTE -> TypeKind.BYTE - ValueTypeDesc.SHORT -> TypeKind.SHORT - ValueTypeDesc.CHAR -> TypeKind.CHAR - ValueTypeDesc.INT -> TypeKind.INT - ValueTypeDesc.LONG -> TypeKind.LONG - ValueTypeDesc.FLOAT -> TypeKind.FLOAT - ValueTypeDesc.DOUBLE -> TypeKind.DOUBLE - else -> TypeKind.NONE - } - } - - fun isValueType(): Boolean { - TODO() - } - - fun getArrayElementType(): TypeDesc { - TODO() - } - - companion object { - val U1: TypeDesc = TypeDesc("Z") - val I8: TypeDesc = TypeDesc("B") - val U8: TypeDesc = TypeDesc("H") - val I16: TypeDesc = TypeDesc("S") - val U16: TypeDesc = TypeDesc("C") - val I32: TypeDesc = TypeDesc("I") - val U32: TypeDesc = TypeDesc("U") - val F32: TypeDesc = TypeDesc("F") - val F64: TypeDesc = TypeDesc("D") - val I64: TypeDesc = TypeDesc("J") - val U64: TypeDesc = TypeDesc("Q") - val ANY: TypeDesc = TypeDesc("A") - val NULL: TypeDesc = TypeDesc("Null") - fun array(elemType: TypeDesc): TypeDesc = TypeDesc("[$elemType") - fun ref(className: String): TypeDesc = TypeDesc("L${className.replace('.', '/')};") - } -} - -/** - * Type kind. - */ -enum class TypeKind(val value: Byte) { - NONE(0x0), - VOID(0x1), - - CHAR(0x2), - BOOLEAN(0x3), - BYTE(0x4), - SHORT(0x5), - INT(0x6), - LONG(0x7), - FLOAT(0x8), - DOUBLE(0x9), - - CLASS(0xA), - STRING(0xB), - INTERFACE(0xC), - ARRAY(0xD), - TUPLE(0xE), - LAMBDA(0xF), - METHOD(0x10), - - UNION(0x11), - UNDEFINED(0x12), - NULL(0x13), - - ENUM(0x14), -} - -/** - * Value type descriptor. - */ -object ValueTypeDesc { - val BOOLEAN: TypeDesc = TypeDesc.U1 - val BYTE: TypeDesc = TypeDesc.I8 - val SHORT: TypeDesc = TypeDesc.I16 - val CHAR: TypeDesc = TypeDesc.U16 - val INT: TypeDesc = TypeDesc.I32 - val LONG: TypeDesc = TypeDesc.I64 - val FLOAT: TypeDesc = TypeDesc.F32 - val DOUBLE: TypeDesc = TypeDesc.F64 -} - -val OBJECT_TYPE_DESC = TypeDesc.ref("std.core.Object") - -val ObjectType = ClassType(OBJECT_TYPE_DESC, Attributes(0)) - -/** - * Attribute flags. - */ -data class Attributes(val value: Int) { - - fun isStatic(): Boolean = (value and STATIC) != 0 - fun isInherited(): Boolean = (value and INHERITED) != 0 - fun isReadOnly(): Boolean = (value and READONLY) != 0 - fun isFinal(): Boolean = (value and FINAL) != 0 - fun isAbstract(): Boolean = (value and ABSTRACT) != 0 - fun isConstructor(): Boolean = (value and CONSTRUCTOR) != 0 - fun isRest(): Boolean = (value and REST) != 0 - fun isOptional(): Boolean = (value and OPTIONAL) != 0 - fun isThrowing(): Boolean = (value and THROWING) != 0 - fun isNative(): Boolean = (value and NATIVE) != 0 - fun isAsync(): Boolean = (value and ASYNC) != 0 - fun isNeverResult(): Boolean = (value and NEVERRESULT) != 0 - fun isGetter(): Boolean = (value and GETTER) != 0 - fun isSetter(): Boolean = (value and SETTER) != 0 - - companion object { - const val STATIC: Int = 1 shl 0 - const val INHERITED: Int = 1 shl 1 - const val READONLY: Int = 1 shl 2 - const val FINAL: Int = 1 shl 3 - const val ABSTRACT: Int = 1 shl 4 - const val CONSTRUCTOR: Int = 1 shl 5 - const val REST: Int = 1 shl 6 - const val OPTIONAL: Int = 1 shl 7 - const val THROWING: Int = 1 shl 8 - const val NATIVE: Int = 1 shl 9 - const val ASYNC: Int = 1 shl 10 - const val NEVERRESULT: Int = 1 shl 11 - const val GETTER: Int = 1 shl 12 - const val SETTER: Int = 1 shl 13 - } -} - -/** - * Access modifier. - */ -enum class AccessModifier(val value: Byte) { - PUBLIC(0), - PRIVATE(1), - PROTECTED(2), -} - -abstract class Type { - abstract val td: TypeDesc - - abstract fun isPrimitive(): Boolean - abstract fun isReference(): Boolean - abstract fun hasName(): Boolean - abstract fun getName(): String - abstract fun getLiteral(): String - - /** - * Checks if this type is a subtype of another type. - * - * `T.subTypeOf(U)` means `T extends U` - */ - open fun subTypeOf(other: Type): Boolean { - if (this == other) return true - if (other == ObjectType) { - val isNullish = this is UndefinedType || this is NullType - return this.isReference() && !isNullish - } - return false - } - - /** - * Checks if this type is assignable from another type. - * - * `T.assignableFrom(U)` means `T <- U` - */ - open fun assignableFrom(other: Type): Boolean { - if (other.subTypeOf(this)) return true - if (this.isNumericType() && other.isNumericType()) return true - return false - } - - private fun isNumericType(): Boolean = - this is ByteType - || this is ShortType - || this is IntType - || this is LongType - || this is FloatType - || this is DoubleType - - override fun toString(): String = if (hasName()) getName() else getLiteral() - - companion object { - fun resolve(td: TypeDesc): Type? { - return when (td.getKind()) { - TypeKind.NONE -> null - TypeKind.VOID -> VoidType.REF - TypeKind.CHAR -> TODO() - TypeKind.BOOLEAN -> TODO() - TypeKind.BYTE -> TODO() - TypeKind.SHORT -> TODO() - TypeKind.INT -> TODO() - TypeKind.LONG -> TODO() - TypeKind.FLOAT -> TODO() - TypeKind.DOUBLE -> TODO() - TypeKind.CLASS -> TODO() - TypeKind.STRING -> TODO() - TypeKind.INTERFACE -> TODO() - TypeKind.ARRAY -> TODO() - TypeKind.TUPLE -> TODO() - TypeKind.LAMBDA -> TODO() - TypeKind.METHOD -> TODO() - TypeKind.UNION -> TODO() - TypeKind.UNDEFINED -> TODO() - TypeKind.NULL -> TODO() - TypeKind.ENUM -> TODO() - // else -> null - } - } - } -} - -class NullType private constructor( - override val td: TypeDesc, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = true - override fun hasName(): Boolean = true - override fun getName(): String = "null" - override fun getLiteral(): String = "null" - - override fun equals(other: Any?): Boolean { - return other is NullType - } - - override fun hashCode(): Int { - return td.hashCode() - } - - companion object { - val REF: NullType = NullType(TypeDesc.NULL) - } -} - -class UndefinedType private constructor( - override val td: TypeDesc, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = true - override fun hasName(): Boolean = true - override fun getName(): String = "undefined" - override fun getLiteral(): String = "undefined" - - override fun equals(other: Any?): Boolean { - return other is UndefinedType - } - - override fun hashCode(): Int { - return td.hashCode() - } - - companion object { - val REF: UndefinedType = UndefinedType(TypeDesc("undefined")) - } -} - -class VoidType private constructor( - override val td: TypeDesc, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = true - override fun hasName(): Boolean = true - override fun getName(): String = "void" - override fun getLiteral(): String = "void" - - override fun equals(other: Any?): Boolean { - return other is VoidType - } - - override fun hashCode(): Int { - return td.hashCode() - } - - companion object { - val REF: VoidType = VoidType(TypeDesc("void")) - } -} - -class CharType private constructor( - override val td: TypeDesc, - private val isValue: Boolean, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = !isValue - override fun hasName(): Boolean = !isValue - override fun getName(): String = if (isValue) "" else td.toString() - override fun getLiteral(): String = if (isValue) "char" else "Char" - - override fun equals(other: Any?): Boolean { - return other is CharType && this.isValue != other.isReference() - } - - override fun hashCode(): Int { - return td.hashCode() - } - - companion object { - val VAL: CharType = CharType(ValueTypeDesc.CHAR, true) - val REF: CharType = CharType(TypeDesc.ref("std.core.Char"), false) - } -} - -class BooleanType private constructor( - override val td: TypeDesc, - private val isValue: Boolean, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = !isValue - override fun hasName(): Boolean = !isValue - override fun getName(): String = if (isValue) "" else td.toString() - override fun getLiteral(): String = if (isValue) "boolean" else "Boolean" - - override fun equals(other: Any?): Boolean { - return other is BooleanType && this.isValue != other.isReference() - } - - override fun hashCode(): Int { - return td.hashCode() - } - - companion object { - val VAL: BooleanType = BooleanType(ValueTypeDesc.BOOLEAN, true) - val REF: BooleanType = BooleanType(TypeDesc.ref("std.core.Boolean"), false) - } -} - -class ByteType private constructor( - override val td: TypeDesc, - private val isValue: Boolean, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = !isValue - override fun hasName(): Boolean = !isValue - override fun getName(): String = if (isValue) "" else td.toString() - override fun getLiteral(): String = if (isValue) "byte" else "Byte" - - override fun equals(other: Any?): Boolean { - return other is ByteType && this.isValue != other.isReference() - } - - override fun hashCode(): Int { - return td.hashCode() - } - - companion object { - val VAL: ByteType = ByteType(ValueTypeDesc.BYTE, true) - val REF: ByteType = ByteType(TypeDesc.ref("std.core.Byte"), false) - } -} - -class ShortType private constructor( - override val td: TypeDesc, - private val isValue: Boolean, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = !isValue - override fun hasName(): Boolean = !isValue - override fun getName(): String = if (isValue) "" else td.toString() - override fun getLiteral(): String = if (isValue) "short" else "Short" - - override fun equals(other: Any?): Boolean { - return other is ShortType && this.isValue != other.isReference() - } - - override fun hashCode(): Int { - return td.hashCode() - } - - companion object { - val VAL: ShortType = ShortType(ValueTypeDesc.SHORT, true) - val REF: ShortType = ShortType(TypeDesc.ref("std.core.Short"), false) - } -} - -class IntType private constructor( - override val td: TypeDesc, - private val isValue: Boolean, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = !isValue - override fun hasName(): Boolean = !isValue - override fun getName(): String = if (isValue) "" else td.toString() - override fun getLiteral(): String = if (isValue) "int" else "Int" - - companion object { - val VAL: IntType = IntType(ValueTypeDesc.INT, true) - val REF: IntType = IntType(TypeDesc.ref("std.core.Int"), false) - } -} - -class LongType private constructor( - override val td: TypeDesc, - private val isValue: Boolean, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = !isValue - override fun hasName(): Boolean = !isValue - override fun getName(): String = if (isValue) "" else td.toString() - override fun getLiteral(): String = if (isValue) "long" else "Long" - - override fun equals(other: Any?): Boolean { - return other is LongType && this.isValue != other.isReference() - } - - override fun hashCode(): Int { - return td.hashCode() - } - - companion object { - val VAL: LongType = LongType(ValueTypeDesc.LONG, true) - val REF: LongType = LongType(TypeDesc.ref("std.core.Long"), false) - } -} - -class FloatType private constructor( - override val td: TypeDesc, - private val isValue: Boolean, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = !isValue - override fun hasName(): Boolean = !isValue - override fun getName(): String = if (isValue) "" else td.toString() - override fun getLiteral(): String = if (isValue) "float" else "Float" - - override fun equals(other: Any?): Boolean { - return other is FloatType && this.isValue != other.isReference() - } - - override fun hashCode(): Int { - return td.hashCode() - } - - companion object { - val VAL: FloatType = FloatType(ValueTypeDesc.FLOAT, true) - val REF: FloatType = FloatType(TypeDesc.ref("std.core.Float"), false) - } -} - -class DoubleType private constructor( - override val td: TypeDesc, - private val isValue: Boolean, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = !isValue - override fun hasName(): Boolean = !isValue - override fun getName(): String = if (isValue) "" else td.toString() - override fun getLiteral(): String = if (isValue) "double" else "Double" - - override fun equals(other: Any?): Boolean { - return other is DoubleType && this.isValue != other.isReference() - } - - override fun hashCode(): Int { - return td.hashCode() - } - - companion object { - val VAL: DoubleType = DoubleType(ValueTypeDesc.DOUBLE, true) - val REF: DoubleType = DoubleType(TypeDesc.ref("std.core.Double"), false) - } -} - -class ClassType( - override val td: TypeDesc, - val attrs: Attributes, -) : Type() { - - override fun isPrimitive(): Boolean = false - override fun isReference(): Boolean = true - override fun hasName(): Boolean = true - override fun getName(): String = td.toString() - override fun getLiteral(): String = "class {...}" // TODO - - fun getBaseType(): ClassType { - TODO() - } - - fun isFinal(): Boolean = attrs.isFinal() - - override fun subTypeOf(other: Type): Boolean { - if (super.subTypeOf(other)) return true - if (other is ClassType) { - var bt = this - while (bt != bt.getBaseType()) { - if (bt == other) return true - bt = bt.getBaseType() - } - return false - } - // if (other is InterfaceType) { - // TODO() - // } - return false - } - - override fun equals(other: Any?): Boolean { - return other is ClassType && other.td == this.td - } - - override fun hashCode(): Int { - return td.hashCode() - } -} - -// TODO: InterfaceType - -class ArrayType( - override val td: TypeDesc, - val elemTD: TypeDesc, -) : Type() { - - override fun isPrimitive(): Boolean = false - override fun isReference(): Boolean = true - override fun hasName(): Boolean = false - override fun getName(): String = "" - override fun getLiteral(): String = "${getElementType()}[]" - - fun getElementType(): Type { - // TODO: return Type.resolve(elemTD)!! - TODO() - } - - override fun assignableFrom(other: Type): Boolean { - if (super.assignableFrom(other)) return true - if (other is ArrayType) { - return this.getElementType().subTypeOf(other.getElementType()) - } - return false - } - - override fun equals(other: Any?): Boolean { - if (other is ArrayType) { - return this.getElementType() == other.getElementType() - } - return false - } - - override fun hashCode(): Int { - return elemTD.hashCode() - } - - companion object { - private fun arrayWithElements(elemTD: TypeDesc): ArrayType = ArrayType(TypeDesc.array(elemTD), elemTD) - - val BOOLEAN_VAL: ArrayType = arrayWithElements(ValueTypeDesc.BOOLEAN) - val BOOLEAN_REF: ArrayType = arrayWithElements(TypeDesc.ref("std.core.Boolean")) - val CHAR_VAL: ArrayType = arrayWithElements(ValueTypeDesc.CHAR) - val CHAR_REF: ArrayType = arrayWithElements(TypeDesc.ref("std.core.Char")) - val BYTE_VAL: ArrayType = arrayWithElements(ValueTypeDesc.BYTE) - val BYTE_REF: ArrayType = arrayWithElements(TypeDesc.ref("std.core.Byte")) - val SHORT_VAL: ArrayType = arrayWithElements(ValueTypeDesc.SHORT) - val SHORT_REF: ArrayType = arrayWithElements(TypeDesc.ref("std.core.Short")) - val INT_VAL: ArrayType = arrayWithElements(ValueTypeDesc.INT) - val INT_REF: ArrayType = arrayWithElements(TypeDesc.ref("std.core.Int")) - val LONG_VAL: ArrayType = arrayWithElements(ValueTypeDesc.LONG) - val LONG_REF: ArrayType = arrayWithElements(TypeDesc.ref("std.core.Long")) - val FLOAT_VAL: ArrayType = arrayWithElements(ValueTypeDesc.FLOAT) - val FLOAT_REF: ArrayType = arrayWithElements(TypeDesc.ref("std.core.Float")) - val DOUBLE_VAL: ArrayType = arrayWithElements(ValueTypeDesc.DOUBLE) - val DOUBLE_REF: ArrayType = arrayWithElements(TypeDesc.ref("std.core.Double")) - - internal fun getInstance(td: TypeDesc, elemTD: TypeDesc): ArrayType { - return when (elemTD.getKind()) { - TypeKind.BOOLEAN -> if (elemTD.isValueType()) BOOLEAN_VAL else BOOLEAN_REF - TypeKind.CHAR -> if (elemTD.isValueType()) CHAR_VAL else CHAR_REF - TypeKind.BYTE -> if (elemTD.isValueType()) BYTE_VAL else BYTE_REF - TypeKind.SHORT -> if (elemTD.isValueType()) SHORT_VAL else SHORT_REF - TypeKind.INT -> if (elemTD.isValueType()) INT_VAL else INT_REF - TypeKind.LONG -> if (elemTD.isValueType()) LONG_VAL else LONG_REF - TypeKind.FLOAT -> if (elemTD.isValueType()) FLOAT_VAL else FLOAT_REF - TypeKind.DOUBLE -> if (elemTD.isValueType()) DOUBLE_VAL else DOUBLE_REF - TypeKind.CLASS -> ArrayType(td, elemTD) - TypeKind.INTERFACE -> ArrayType(td, elemTD) - TypeKind.STRING -> ArrayType(td, elemTD) - TypeKind.ARRAY -> ArrayType(td, elemTD) - TypeKind.TUPLE -> ArrayType(td, elemTD) - TypeKind.LAMBDA -> ArrayType(td, elemTD) - TypeKind.METHOD -> ArrayType(td, elemTD) - TypeKind.UNION -> ArrayType(td, elemTD) - else -> error("Cannot create ArrayType with element type $elemTD") - } - } - - internal fun getInstance(td: TypeDesc): ArrayType { - return getInstance(td, td.getArrayElementType()) - } - } -} - -// TODO: TupleType - -abstract class FunctionType( - override val td: TypeDesc, - val attrs: Attributes, -) : Type() { - - override fun isPrimitive(): Boolean = false - override fun isReference(): Boolean = true - override fun hasName(): Boolean = false - override fun getName(): String = "" - - fun getResultType(): Type { - // TODO: return Type.resolve(td.getResultType()) - TODO() - } - - fun isThrowing(): Boolean = attrs.isThrowing() - fun isNative(): Boolean = attrs.isNative() - fun isAsync(): Boolean = attrs.isAsync() - fun isNeverResult(): Boolean = attrs.isNeverResult() - - override fun equals(other: Any?): Boolean { - return other is FunctionType && other.td == this.td - } - - override fun hashCode(): Int { - return td.hashCode() - } -} - -class LambdaType( - td: TypeDesc, - attrs: Attributes, -) : FunctionType(td, attrs) { - - override fun getLiteral(): String = buildString { - append("(") - append("...TODO...") - // TODO: - // val paramsNum = getParametersNum() - // for (i in 0 until paramsNum) { - // if (i > 0) { - // append(", ") - // } - // append(getParameter(i)) - // } - append("): ") - append(getResultType()) - } - - fun getReceiverType(): Type { - // TODO: return Type.resolve(td.getReceiverType()) - TODO() - } - - fun getParametersNum(): Int { - TODO() - } - - fun getParameter(index: Int): Parameter { - TODO() - } - - override fun assignableFrom(other: Type): Boolean { - if (super.assignableFrom(other)) return true - if (other !is LambdaType) return false - - if (this.getParametersNum() != other.getParametersNum()) return false - - // Parameter types are using contravariance - for (i in 0 until this.getParametersNum()) { - // if (this.getParameter(i) != other.getParameter(i)) return false - val lt = this.getParameter(i).type - val rt = other.getParameter(i).type - if (!lt.subTypeOf(rt)) return false - } - - // Return types are using covariance - return other.getResultType().subTypeOf(this.getResultType()) - } -} - -class MethodType( - td: TypeDesc, - attrs: Attributes, -) : FunctionType(td, attrs) { - - override fun getLiteral(): String = buildString { - append("(") - append("...TODO...") - append("): ") - append(getResultType()) - } - - fun getReceiverType(): Type { - // TODO: return Type.resolve(td.getReceiverType()) - TODO() - } - - override fun assignableFrom(other: Type): Boolean { - return false - } -} - -class StringType( - override val td: TypeDesc, -) : Type() { - - override fun isPrimitive(): Boolean = true - override fun isReference(): Boolean = true - override fun hasName(): Boolean = false - override fun getName(): String = "" - override fun getLiteral(): String = "string" // TODO - - override fun equals(other: Any?): Boolean { - return other is StringType - } - - override fun hashCode(): Int { - return td.hashCode() - } -} - -class EnumType( - override val td: TypeDesc, -) : Type() { - - override fun isPrimitive(): Boolean = false - override fun isReference(): Boolean = false - override fun hasName(): Boolean = true - override fun getName(): String = td.toString() - override fun getLiteral(): String = "enum {...}" // TODO - - override fun assignableFrom(other: Type): Boolean { - if (super.assignableFrom(other)) return true - if (other is EnumType) { - return this.getName() == other.getName() - } - return false - } - - override fun equals(other: Any?): Boolean { - // TODO - return false - } - - override fun hashCode(): Int { - return td.hashCode() - } -} - -class UnionType( - override val td: TypeDesc, -) : Type() { - - override fun isPrimitive(): Boolean = false - override fun isReference(): Boolean = true - override fun hasName(): Boolean = false - override fun getName(): String = "" - override fun getLiteral(): String = "(... | ...)" // TODO - - override fun equals(other: Any?): Boolean { - // TODO - return false - } - - override fun hashCode(): Int { - return td.hashCode() - } -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/EtsStdlib.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/EtsStdlib.kt deleted file mode 100644 index 5aab28aff..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/EtsStdlib.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.ir - -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.json.decodeFromStream - -@OptIn(ExperimentalSerializationApi::class) -object EtsStdlib { - val program: PandaProgramIr - - init { - val stream = this::class.java.getResourceAsStream("/stdlib.ir") - ?: error("Not found stdlib, run arkcompiler fork: \"es2panda --dump-ir --gen-stdlib > stdlib.ir\"") - program = PandaProgramIr.json.decodeFromStream(stream) - } -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaInstIr.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaInstIr.kt deleted file mode 100644 index 0aa45b0eb..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaInstIr.kt +++ /dev/null @@ -1,1269 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.ir - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -sealed interface PandaInstIr { - val id: String - val inputs: List - val users: List - val opcode: String - val type: String - val catchers: List - val visit: String - - fun accept(visitor: PandaInstIrVisitor): T -} - -@Serializable -sealed interface PandaComparisonInstIr : PandaInstIr { - val operator: String - val operandsType: String -} - -@Serializable -sealed interface PandaWithPropertyInstIr : PandaInstIr { - val enclosingClass: String - val field: String -} - -@Serializable -sealed interface PandaTerminatingInstIr : PandaInstIr - -@Serializable -@SerialName("Constant") -data class PandaConstantInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val value: ULong, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaConstantInstIr(this) -} - -@Serializable -@SerialName("SafePoint") -data class PandaSafePointInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaSafePointInstIr(this) -} - -@Serializable -@SerialName("SaveState") -data class PandaSaveStateInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaSaveStateInstIr(this) -} - -@Serializable -@SerialName("NewObject") -data class PandaNewObjectInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val objectClass: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaNewObjectInstIr(this) -} - -@Serializable -@SerialName("NewArray") -data class PandaNewArrayInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val arrayType: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaNewArrayInstIr(this) -} - -@Serializable -@SerialName("CallStatic") -data class PandaCallStaticInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val method: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCallStaticInstIr(this) -} - -@Serializable -@SerialName("NullCheck") -data class PandaNullCheckInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaNullCheckInstIr(this) -} - -@Serializable -@SerialName("ZeroCheck") -data class PandaZeroCheckInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaZeroCheckInstIr(this) -} - -@Serializable -@SerialName("LoadString") -data class PandaLoadStringInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val string: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadStringInstIr(this) -} - -@Serializable -@SerialName("LoadType") -data class PandaLoadTypeInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val loadedType: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadTypeInstIr(this) -} - -@Serializable -@SerialName("LoadRuntimeClass") -data class PandaLoadRuntimeClassInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val loadedClass: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadRuntimeClassInstIr(this) -} - -@Serializable -@SerialName("CallVirtual") -data class PandaCallVirtualInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val method: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCallVirtualInstIr(this) -} - -@Serializable -@SerialName("CallLaunchVirtual") -data class PandaCallLaunchVirtualInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val method: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCallLaunchVirtualInstIr(this) -} - -@Serializable -@SerialName("CallLaunchStatic") -data class PandaCallLaunchStaticInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val method: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCallLaunchStaticInstIr(this) -} - -@Serializable -@SerialName("LoadAndInitClass") -data class PandaLoadAndInitClassInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val loadedClass: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadAndInitClassInstIr(this) -} - -@Serializable -@SerialName("LoadClass") -data class PandaLoadClassInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadClassInstIr(this) -} - -@Serializable -@SerialName("InitClass") -data class PandaInitClassInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaInitClassInstIr(this) -} - -@Serializable -@SerialName("ReturnVoid") -data class PandaReturnVoidInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaTerminatingInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaReturnVoidInstIr(this) -} - -@Serializable -@SerialName("Return") -data class PandaReturnInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaTerminatingInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaReturnInstIr(this) -} - -@Serializable -@SerialName("Parameter") -data class PandaParameterInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val index: Int, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaParameterInstIr(this) -} - -@Serializable -@SerialName("LoadStatic") -data class PandaLoadStaticInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - override val enclosingClass: String, - override val field: String, -) : PandaWithPropertyInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadStaticInstIr(this) -} - -@Serializable -@SerialName("LoadObject") -data class PandaLoadObjectInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - override val enclosingClass: String, - override val field: String, -) : PandaWithPropertyInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadObjectInstIr(this) -} - -@Serializable -@SerialName("StoreStatic") -data class PandaStoreStaticInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - override val enclosingClass: String, - override val field: String, -) : PandaWithPropertyInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaStoreStaticInstIr(this) -} - -@Serializable -@SerialName("StoreObject") -data class PandaStoreObjectInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - override val enclosingClass: String, - override val field: String, -) : PandaWithPropertyInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaStoreObjectInstIr(this) -} - -@Serializable -@SerialName("LoadArray") -data class PandaLoadArrayInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadArrayInstIr(this) -} - -@Serializable -@SerialName("StoreArray") -data class PandaStoreArrayInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaStoreArrayInstIr(this) -} - -@Serializable -@SerialName("IsInstance") -data class PandaIsInstanceInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val candidateType: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaIsInstanceInstIr(this) -} - -@Serializable -@SerialName("CheckCast") -data class PandaCheckCastInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val candidateType: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCheckCastInstIr(this) -} - -@Serializable -@SerialName("Bitcast") -data class PandaBitcastInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val candidateType: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaBitcastInstIr(this) -} - -@Serializable -@SerialName("Cast") -data class PandaCastInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val candidateType: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCastInstIr(this) -} - -@Serializable -@SerialName("IfImm") -data class PandaIfImmInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - override val operator: String, - override val operandsType: String, - val immediate: ULong, -) : PandaComparisonInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaIfImmInstIr(this) -} - -@Serializable -@SerialName("Compare") -data class PandaCompareInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - override val operator: String, - override val operandsType: String, -) : PandaComparisonInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCompareInstIr(this) -} - -@Serializable -@SerialName("Phi") -data class PandaPhiInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val inputBlocks: List, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaPhiInstIr(this) -} - -@Serializable -@SerialName("Add") -data class PandaAddInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaAddInstIr(this) -} - -@Serializable -@SerialName("Sub") -data class PandaSubInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaSubInstIr(this) -} - -@Serializable -@SerialName("Mul") -data class PandaMulInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaMulInstIr(this) -} - -@Serializable -@SerialName("Div") -data class PandaDivInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaDivInstIr(this) -} - -@Serializable -@SerialName("Mod") -data class PandaModInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaModInstIr(this) -} - -@Serializable -@SerialName("And") -data class PandaAndInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaAndInstIr(this) -} - -@Serializable -@SerialName("Or") -data class PandaOrInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaOrInstIr(this) -} - -@Serializable -@SerialName("Xor") -data class PandaXorInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaXorInstIr(this) -} - -@Serializable -@SerialName("Shl") -data class PandaShlInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaShlInstIr(this) -} - -@Serializable -@SerialName("Shr") -data class PandaShrInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaShrInstIr(this) -} - -@Serializable -@SerialName("AShl") -data class PandaAShlInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaAShlInstIr(this) -} - -@Serializable -@SerialName("AShr") -data class PandaAShrInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaAShrInstIr(this) -} - -@Serializable -@SerialName("Cmp") -data class PandaCmpInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - override val operator: String, - override val operandsType: String, -) : PandaComparisonInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCmpInstIr(this) -} - -@Serializable -@SerialName("Throw") -data class PandaThrowInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val method: String = "", // TODO: remove default value -) : PandaTerminatingInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaThrowInstIr(this) -} - -@Serializable -@SerialName("NegativeCheck") -data class PandaNegativeCheckInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaNegativeCheckInstIr(this) -} - -@Serializable -@SerialName("SaveStateDeoptimize") -data class PandaSaveStateDeoptimizeInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaSaveStateDeoptimizeInstIr(this) -} - -@Serializable -@SerialName("Neg") -data class PandaNegInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaNegInstIr(this) -} - -@Serializable -@SerialName("Not") -data class PandaNotInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaNotInstIr(this) -} - -@Serializable -@SerialName("LenArray") -data class PandaLenArrayInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLenArrayInstIr(this) -} - -@Serializable -@SerialName("BoundsCheck") -data class PandaBoundsCheckInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaBoundsCheckInstIr(this) -} - -@Serializable -@SerialName("NullPtr") -data class PandaNullPtrInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaNullPtrInstIr(this) -} - -@Serializable -@SerialName("LoadUndefined") -data class PandaLoadUndefinedInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadUndefinedInstIr(this) -} - -@Serializable -@SerialName("RefTypeCheck") -data class PandaRefTypeCheckInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaRefTypeCheckInstIr(this) -} - -@Serializable -@SerialName("Try") -data class PandaTryInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val end_bb: Int = 0, // TODO: remove default value -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaTryInstIr(this) -} - -@Serializable -@SerialName("CatchPhi") -data class PandaCatchPhiInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val throwers: List = emptyList(), -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCatchPhiInstIr(this) -} - -@Serializable -@SerialName("Intrinsic") -data class PandaIntrinsicInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val intrinsicId: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaIntrinsicInstIr(this) -} - -@Serializable -@SerialName("LoadFromConstantPool") -data class PandaLoadFromConstantPoolInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val isString: Boolean, - val objectType: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadFromConstantPoolInstIr(this) -} - -@Serializable -@SerialName("ResolveStatic") -data class PandaResolveStaticInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaResolveStaticInstIr(this) -} - -@Serializable -@SerialName("ResolveVirtual") -data class PandaResolveVirtualInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaResolveVirtualInstIr(this) -} - -@Serializable -@SerialName("CallDynamic") -data class PandaCallDynamicInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val method: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCallDynamicInstIr(this) -} - -@Serializable -@SerialName("CallResolvedVirtual") -data class PandaCallResolvedVirtualInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val method: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCallResolvedVirtualInstIr(this) -} - -@Serializable -@SerialName("CallResolvedStatic") -data class PandaCallResolvedStaticInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val method: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaCallResolvedStaticInstIr(this) -} - -@Serializable -@SerialName("FillConstArray") -data class PandaFillConstArrayInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val objectClass: String, - val length: Int, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaFillConstArrayInstIr(this) -} - -@Serializable -@SerialName("Builtin") -data class PandaBuiltinInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val intrinsicId: String, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaBuiltinInstIr(this) -} - -@Serializable -@SerialName("LoadResolvedObjectField") -data class PandaLoadResolvedObjectFieldInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - override val enclosingClass: String, - override val field: String, -) : PandaWithPropertyInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadResolvedObjectFieldInstIr(this) -} - -@Serializable -@SerialName("LoadResolvedObjectFieldStatic") -data class PandaLoadResolvedObjectFieldStaticInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - override val enclosingClass: String, - override val field: String, -) : PandaWithPropertyInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadResolvedObjectFieldStaticInstIr(this) -} - -@Serializable -@SerialName("StoreResolvedObjectField") -data class PandaStoreResolvedObjectFieldInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - override val enclosingClass: String, - override val field: String, -) : PandaWithPropertyInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaStoreResolvedObjectFieldInstIr(this) -} - -@Serializable -@SerialName("StoreResolvedObjectFieldStatic") -data class PandaStoreResolvedObjectFieldStaticInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - override val enclosingClass: String, - override val field: String, -) : PandaWithPropertyInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaStoreResolvedObjectFieldStaticInstIr(this) -} - -@Serializable -@SerialName("LoadObjectDynamic") -data class PandaLoadObjectDynamicInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val accessType: Int, - val accessMode: Int, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadObjectDynamicInstIr(this) -} - -@Serializable -@SerialName("StoreObjectDynamic") -data class PandaStoreObjectDynamicInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val accessType: Int, - val accessMode: Int, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaStoreObjectDynamicInstIr(this) -} - -@Serializable -@SerialName("FunctionImmediate") -data class PandaFunctionImmediateInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val funcPtr: Long, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaFunctionImmediateInstIr(this) -} - -@Serializable -@SerialName("HclassCheck") -data class PandaHclassCheckInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val checkIsFunction: Boolean, - val checkFunctionIsNotClassConstructor: Boolean, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaHclassCheckInstIr(this) -} - -@Serializable -@SerialName("LoadObjFromConst") -data class PandaLoadObjFromConstInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val objPtr: Long, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadObjFromConstInstIr(this) -} - -@Serializable -@SerialName("LoadImmediate") -data class PandaLoadImmediateInstIr( - override val id: String, - override val inputs: List = emptyList(), - override val users: List = emptyList(), - override val type: String, - override val opcode: String, - override val catchers: List = emptyList(), - override val visit: String = "", - val immediateType: Int, - val immediateClass: String? = null, - val method: String? = null, - val constantPool: Long? = null, - val string: String? = null, - val offset: Long? = null, -) : PandaInstIr { - override fun accept(visitor: PandaInstIrVisitor): T = - visitor.visitPandaLoadImmediateInstIr(this) -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaInstIrVisitor.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaInstIrVisitor.kt deleted file mode 100644 index 3d566fdf9..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaInstIrVisitor.kt +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.ir - -interface PandaInstIrVisitor { - fun visitPandaConstantInstIr(inst: PandaConstantInstIr): T - fun visitPandaSafePointInstIr(inst: PandaSafePointInstIr): T - fun visitPandaSaveStateInstIr(inst: PandaSaveStateInstIr): T - fun visitPandaNewObjectInstIr(inst: PandaNewObjectInstIr): T - fun visitPandaNewArrayInstIr(inst: PandaNewArrayInstIr): T - fun visitPandaCallStaticInstIr(inst: PandaCallStaticInstIr): T - fun visitPandaNullCheckInstIr(inst: PandaNullCheckInstIr): T - fun visitPandaZeroCheckInstIr(inst: PandaZeroCheckInstIr): T - fun visitPandaLoadStringInstIr(inst: PandaLoadStringInstIr): T - fun visitPandaLoadTypeInstIr(inst: PandaLoadTypeInstIr): T - fun visitPandaLoadRuntimeClassInstIr(inst: PandaLoadRuntimeClassInstIr): T - fun visitPandaCallVirtualInstIr(inst: PandaCallVirtualInstIr): T - fun visitPandaCallLaunchVirtualInstIr(inst: PandaCallLaunchVirtualInstIr): T - fun visitPandaCallLaunchStaticInstIr(inst: PandaCallLaunchStaticInstIr): T - fun visitPandaLoadAndInitClassInstIr(inst: PandaLoadAndInitClassInstIr): T - fun visitPandaLoadClassInstIr(inst: PandaLoadClassInstIr): T - fun visitPandaInitClassInstIr(inst: PandaInitClassInstIr): T - fun visitPandaReturnVoidInstIr(inst: PandaReturnVoidInstIr): T - fun visitPandaReturnInstIr(inst: PandaReturnInstIr): T - fun visitPandaParameterInstIr(inst: PandaParameterInstIr): T - fun visitPandaLoadStaticInstIr(inst: PandaLoadStaticInstIr): T - fun visitPandaLoadObjectInstIr(inst: PandaLoadObjectInstIr): T - fun visitPandaStoreStaticInstIr(inst: PandaStoreStaticInstIr): T - fun visitPandaStoreObjectInstIr(inst: PandaStoreObjectInstIr): T - fun visitPandaLoadArrayInstIr(inst: PandaLoadArrayInstIr): T - fun visitPandaStoreArrayInstIr(inst: PandaStoreArrayInstIr): T - fun visitPandaIsInstanceInstIr(inst: PandaIsInstanceInstIr): T - fun visitPandaCheckCastInstIr(inst: PandaCheckCastInstIr): T - fun visitPandaBitcastInstIr(inst: PandaBitcastInstIr): T - fun visitPandaCastInstIr(inst: PandaCastInstIr): T - fun visitPandaIfImmInstIr(inst: PandaIfImmInstIr): T - fun visitPandaCompareInstIr(inst: PandaCompareInstIr): T - fun visitPandaPhiInstIr(inst: PandaPhiInstIr): T - fun visitPandaAddInstIr(inst: PandaAddInstIr): T - fun visitPandaSubInstIr(inst: PandaSubInstIr): T - fun visitPandaMulInstIr(inst: PandaMulInstIr): T - fun visitPandaDivInstIr(inst: PandaDivInstIr): T - fun visitPandaModInstIr(inst: PandaModInstIr): T - fun visitPandaAndInstIr(inst: PandaAndInstIr): T - fun visitPandaOrInstIr(inst: PandaOrInstIr): T - fun visitPandaXorInstIr(inst: PandaXorInstIr): T - fun visitPandaShlInstIr(inst: PandaShlInstIr): T - fun visitPandaShrInstIr(inst: PandaShrInstIr): T - fun visitPandaAShlInstIr(inst: PandaAShlInstIr): T - fun visitPandaAShrInstIr(inst: PandaAShrInstIr): T - fun visitPandaCmpInstIr(inst: PandaCmpInstIr): T - fun visitPandaThrowInstIr(inst: PandaThrowInstIr): T - fun visitPandaNegativeCheckInstIr(inst: PandaNegativeCheckInstIr): T - fun visitPandaSaveStateDeoptimizeInstIr(inst: PandaSaveStateDeoptimizeInstIr): T - fun visitPandaNegInstIr(inst: PandaNegInstIr): T - fun visitPandaNotInstIr(inst: PandaNotInstIr): T - fun visitPandaLenArrayInstIr(inst: PandaLenArrayInstIr): T - fun visitPandaBoundsCheckInstIr(inst: PandaBoundsCheckInstIr): T - fun visitPandaNullPtrInstIr(inst: PandaNullPtrInstIr): T - fun visitPandaLoadUndefinedInstIr(inst: PandaLoadUndefinedInstIr): T - fun visitPandaRefTypeCheckInstIr(inst: PandaRefTypeCheckInstIr): T - fun visitPandaTryInstIr(inst: PandaTryInstIr): T - fun visitPandaCatchPhiInstIr(inst: PandaCatchPhiInstIr): T - fun visitPandaIntrinsicInstIr(inst: PandaIntrinsicInstIr): T - fun visitPandaLoadFromConstantPoolInstIr(inst: PandaLoadFromConstantPoolInstIr): T - fun visitPandaResolveStaticInstIr(inst: PandaResolveStaticInstIr): T - fun visitPandaResolveVirtualInstIr(inst: PandaResolveVirtualInstIr): T - fun visitPandaCallDynamicInstIr(inst: PandaCallDynamicInstIr): T - fun visitPandaCallResolvedVirtualInstIr(inst: PandaCallResolvedVirtualInstIr): T - fun visitPandaCallResolvedStaticInstIr(inst: PandaCallResolvedStaticInstIr): T - fun visitPandaFillConstArrayInstIr(inst: PandaFillConstArrayInstIr): T - fun visitPandaBuiltinInstIr(inst: PandaBuiltinInstIr): T - fun visitPandaLoadResolvedObjectFieldInstIr(inst: PandaLoadResolvedObjectFieldInstIr): T - fun visitPandaLoadResolvedObjectFieldStaticInstIr(inst: PandaLoadResolvedObjectFieldStaticInstIr): T - fun visitPandaStoreResolvedObjectFieldInstIr(inst: PandaStoreResolvedObjectFieldInstIr): T - fun visitPandaStoreResolvedObjectFieldStaticInstIr(inst: PandaStoreResolvedObjectFieldStaticInstIr): T - fun visitPandaLoadObjectDynamicInstIr(inst: PandaLoadObjectDynamicInstIr): T - fun visitPandaStoreObjectDynamicInstIr(inst: PandaStoreObjectDynamicInstIr): T - fun visitPandaFunctionImmediateInstIr(inst: PandaFunctionImmediateInstIr): T - fun visitPandaHclassCheckInstIr(inst: PandaHclassCheckInstIr): T - fun visitPandaLoadObjFromConstInstIr(inst: PandaLoadObjFromConstInstIr): T - fun visitPandaLoadImmediateInstIr(inst: PandaLoadImmediateInstIr): T -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaProgramIr.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaProgramIr.kt deleted file mode 100644 index 1e645fb26..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaProgramIr.kt +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.ir - -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.Serializable -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.decodeFromStream -import org.jacodb.panda.staticvm.classpath.AccessFlags -import org.jacodb.panda.staticvm.classpath.PandaClass -import org.jacodb.panda.staticvm.classpath.PandaField -import org.jacodb.panda.staticvm.classpath.PandaInterface -import org.jacodb.panda.staticvm.classpath.PandaMethod -import org.jacodb.panda.staticvm.classpath.PandaProject -import org.jacodb.panda.staticvm.classpath.PandaType -import org.jacodb.panda.staticvm.utils.OneDirectionGraph -import org.jacodb.panda.staticvm.utils.applyFold -import org.jacodb.panda.staticvm.utils.inTopsortOrder -import java.io.File -import java.io.InputStream -import java.nio.file.Path -import kotlin.io.path.inputStream - -@Serializable -data class PandaProgramIr( - val classes: List = emptyList(), -) { - companion object { - val json = Json { - // ignoreUnknownKeys = true - classDiscriminator = "opcode" - } - - fun fromJson(jsonString: String): PandaProgramIr { - return json.decodeFromString(jsonString) - } - - @OptIn(ExperimentalSerializationApi::class) - fun from(inputStream: InputStream): PandaProgramIr { - return json.decodeFromStream(inputStream) - } - - fun from(file: File): PandaProgramIr { - return from(file.inputStream().buffered()) - } - - fun from(path: Path): PandaProgramIr { - return from(path.inputStream().buffered()) - } - } - - fun addClassesHierarchyToPandaClasspath(project: PandaProject) { - val classesMap = classes - .filterNot { AccessFlags(it.accessFlags).isInterface } - .associateBy { it.name } - - val graph = OneDirectionGraph(classesMap.values) { - setOfNotNull(it.superClass?.let(classesMap::get)) - } - - requireNotNull(graph.inTopsortOrder()) { - "Found cyclic inheritance" - }.reversed().applyFold(project) { - val superClass = it.superClass?.let { superClassName -> - requireNotNull(findClassOrNull(superClassName)) - } - val interfaces = it.interfaces.mapTo(hashSetOf()) { interfaceName -> - requireNotNull(findInterfaceOrNull(interfaceName)) - } - val pandaClass = PandaClass( - project = this, - name = it.name, - directSuperClass = superClass, - directSuperInterfaces = interfaces, - flags = AccessFlags(it.accessFlags) - ) - addClass(pandaClass) - } - } - - fun addInterfacesHierarchyToPandaClasspath(project: PandaProject) { - val interfacesMap = classes - .filter { AccessFlags(it.accessFlags).isInterface } - .associateBy { it.name } - - val graph = OneDirectionGraph(interfacesMap.values) { - it.interfaces.mapNotNullTo(hashSetOf()) { interfacesMap[it] } - } - - requireNotNull(graph.inTopsortOrder()) { - "Found cyclic inheritance" - }.reversed().applyFold(project) { - val interfaces = it.interfaces.mapTo(hashSetOf()) { interfaceName -> - requireNotNull(findInterfaceOrNull(interfaceName)) - } - val pandaInterface = PandaInterface( - project = this, - name = it.name, - directSuperInterfaces = interfaces, - flags = AccessFlags(it.accessFlags) - ) - addInterface(pandaInterface) - } - } - - fun addFieldsToPandaClasspath(project: PandaProject) { - classes.applyFold(project) { clazz -> - val enclosingClass = requireNotNull(findClassOrInterfaceOrNull(clazz.name)) - clazz.fields.applyFold(this) { field -> - val fieldType = requireNotNull(findTypeOrNull(field.type)) - val pandaField = PandaField( - enclosingClass = enclosingClass, - name = field.name, - type = fieldType, - flags = AccessFlags(field.accessFlags) - ) - addField(pandaField) - } - } - } - - fun addMethodsToPandaClasspath(project: PandaProject) { - classes.applyFold(project) { clazz -> - val enclosingClass = requireNotNull(findClassOrInterfaceOrNull(clazz.name)) - clazz.methods.applyFold(this) { method -> - val returnType = findType(method.returnType) - val isStatic = AccessFlags(method.accessFlags).isStatic - val enclosing: List = if (isStatic) emptyList() else listOf(enclosingClass.type) - val parameters: List = method.parameters.map { requireNotNull(findTypeOrNull(it)) } - val parameterTypes = enclosing + parameters - val pandaMethod = PandaMethod( - signature = method.signature, - name = method.name, - enclosingClass = enclosingClass, - returnType = returnType, - parameterTypes = parameterTypes, - flags = AccessFlags(method.accessFlags) - ) - addMethod(pandaMethod) - } - } - } - - fun addFlowGraphsToPandaClasspath(project: PandaProject) { - classes.applyFold(project) { clazz -> - clazz.methods.applyFold(this) { method -> - val methodNode = requireNotNull(project.findMethod(method.signature)) - if (method.basicBlocks.isNotEmpty()) { - addFlowGraph(methodNode, method.basicBlocks) - } - } - } - } -} - -@Serializable -data class PandaClassIr( - val name: String, - val simpleName: String, - val superClass: String? = null, - val interfaces: List = emptyList(), - val accessFlags: Int = 1, - val fields: List = emptyList(), - val methods: List = emptyList(), -) - -@Serializable -data class PandaFieldIr( - val name: String, - val type: String, - val accessFlags: Int, -) - -@Serializable -data class PandaMethodIr( - val name: String, - val signature: String, - val returnType: String, - val parameters: List = emptyList(), - val accessFlags: Int, - val basicBlocks: List = emptyList(), -) - -@Serializable -data class PandaBasicBlockIr( - val id: Int, - val predecessors: List = emptyList(), - val successors: List = emptyList(), - val insts: List = emptyList(), - val isCatchBegin: Boolean = false, - val isTryBegin: Boolean = false, - val isTryEnd: Boolean = false, - private val handlerIds: List = emptyList(), - private val handledTypes: List = emptyList(), -) { - data class Handler(val id: Int, val type: String?) - - val handlers: List - get() = handlerIds.zip(handledTypes) { id, type -> Handler(id, if (type == "finally") null else type) } -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaProgramIrToDot.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaProgramIrToDot.kt deleted file mode 100644 index 5a6cb9212..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/ir/PandaProgramIrToDot.kt +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.ir - -import java.io.File -import java.nio.file.Path -import kotlin.io.path.writeText - -fun PandaProgramIr.toDot(): String { - val lines: MutableList = mutableListOf() - lines += "digraph {" - lines += " rankdir=LR;" - lines += " compound=true;" - - val classes = this.classes - .filterNot { it.name.startsWith("std.") } - .filterNot { it.name.startsWith("escompat.") } - .filterNot { it.name.startsWith("FunctionalInterface") } - - // Classes with properties: - classes.forEach { clazz -> - // CLASS - run { - val labelLines: MutableList = mutableListOf() - labelLines += clazz.name - labelLines += "Fields: (${clazz.fields.size})" - for (field in clazz.fields) { - labelLines += " ${field.name}: ${field.type}" - } - labelLines += "Methods: (${clazz.methods.size})" - for (method in clazz.methods) { - labelLines += " ${method.name}: ${method.returnType}" - } - lines += "" - lines += " \"${clazz.name}\" [shape=rectangle,label=\"${ - labelLines.joinToString("") { "$it\\l" } - }\"]" - } - - // Methods inside class: - clazz.methods.forEach { method -> - // METHOD - lines += " \"${clazz.name}.${method.name}\" [shape=diamond,label=\"${clazz.name}::${method.name}\"];" - lines += " \"${clazz.name}\" -> \"${clazz.name}.${method.name}\"" - } - - // Basic blocks inside method: - clazz.methods.forEach { method -> - // Link to the first basic block inside method: - if (method.basicBlocks.isNotEmpty()) { - lines += " \"${clazz.name}.${method.name}\" -> \"${clazz.name}.${method.name}.bb${method.basicBlocks.first().id}.0\" [lhead=\"${clazz.name}.${method.name}.bb${method.basicBlocks.first().id}\"];" - } - - method.basicBlocks.forEach { bb -> - val last = bb.insts.lastOrNull() - val i = if (bb.insts.isNotEmpty()) bb.insts.lastIndex else 0 - when (last) { - is PandaIfImmInstIr -> { - for ((j, succ) in bb.successors.withIndex()) { - lines += " \"${clazz.name}.${method.name}.bb${bb.id}.${i}\" -> \"${clazz.name}.${method.name}.bb${succ}.0\" [lhead=\"${clazz.name}.${method.name}.bb${succ}\", label=\"${if (j == 0) "true" else "false"}\"];" - } - } - - is PandaTryInstIr -> { - for ((j, succ) in bb.successors.withIndex()) { - lines += " \"${clazz.name}.${method.name}.bb${bb.id}.${i}\" -> \"${clazz.name}.${method.name}.bb${succ}.0\" [lhead=\"${clazz.name}.${method.name}.bb${succ}\", label=\"${if (j == 0) "try" else "catch"}\"];" - } - } - - else -> { - // check(bb.successors.size <= 1) - for (succ in bb.successors) { - lines += " \"${clazz.name}.${method.name}.bb${bb.id}.${i}\" -> \"${clazz.name}.${method.name}.bb${succ}.0\" [lhead=\"${clazz.name}.${method.name}.bb${succ}\"];" - } - } - } - } - - // Basic blocks with instructions: - method.basicBlocks.forEach { bb -> - // BASIC BLOCK - lines += "" - lines += " subgraph \"${clazz.name}.${method.name}.bb${bb.id}\" {" - lines += " cluster=true;" - lines += " label=\"BB ${bb.id}\\nsuccessors = ${bb.successors}\\nisCatchBegin = ${bb.isCatchBegin}\\nisTryBegin = ${bb.isTryBegin}\\nisTryEnd = ${bb.isTryEnd}\";" - - if (bb.insts.isEmpty()) { - lines += " \"${clazz.name}.${method.name}.bb${bb.id}.0\" [shape=box,label=\"NOP\"];" - } - - // Instructions inside basic block: - bb.insts.forEachIndexed { i, inst -> - val labelLines: MutableList = mutableListOf() - labelLines += "${inst.id}: ${inst.opcode}: ${inst.type}" - if (inst is PandaConstantInstIr) { - labelLines += "value = ${inst.value}" - } - if (inst is PandaLoadStringInstIr) { - labelLines += "string = ${inst.string}" - } - if (inst.inputs.isNotEmpty()) { - labelLines += "inputs = ${inst.inputs}" - } - if (inst.users.isNotEmpty()) { - labelLines += "users = ${inst.users}" - } - if (inst.catchers.isNotEmpty()) { - labelLines += "catchers = ${inst.catchers}" - } - if (inst is PandaCatchPhiInstIr) { - labelLines += "throwers = ${inst.throwers}" - } - // INSTRUCTION - lines += " \"${clazz.name}.${method.name}.bb${bb.id}.${i}\" [shape=box,label=\"${ - labelLines.joinToString("") { "${it}\\l" } - }\"];" - } - - // Instructions chain: - if (bb.insts.isNotEmpty()) { - lines += " ${ - List(bb.insts.size) { i -> - "\"${clazz.name}.${method.name}.bb${bb.id}.${i}\"" - }.joinToString(" -> ") - };" - } - - lines += " }" - } - } - } - - lines += "}" - return lines.joinToString("\n") -} - -fun PandaProgramIr.dumpDot(file: File) { - file.writeText(toDot()) -} - -fun PandaProgramIr.dumpDot(path: Path) { - path.writeText(toDot()) -} - -fun PandaProgramIr.dumpDot(path: String) { - dumpDot(File(path)) -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/GraphUtils.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/GraphUtils.kt deleted file mode 100644 index 5e8330a18..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/GraphUtils.kt +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.utils - -import org.jacodb.api.common.cfg.Graph - -fun search( - start: T, - successors: (T) -> Iterable, - visitor: (T) -> Unit, -): Set { - val visited = hashSetOf() - fun dfs(node: T) = node.takeIf(visited::add)?.also(visitor)?.let { successors(it).forEach(::dfs) } - dfs(start) - return visited -} - -fun components( - starts: Iterable, - successors: (T) -> Iterable, -): List> { - val visited = hashSetOf() - return starts.mapNotNull { start -> - if (start !in visited) search(start, { successors(it).filter { it !in visited } }, visited::add) - else null - } -} - -fun reachable( - starts: Iterable, - successors: (T) -> Iterable, -): Set = - starts.applyFold(hashSetOf()) { start -> - if (!contains(start)) - addAll(search(start, { successors(it).filterNot(this::contains) }, {})) - } - -fun Graph.rpo(): List { - val visited = hashSetOf() - val order = mutableListOf() - val onStack = hashSetOf() - - fun dfs(node: T) = node.takeIf(visited::add)?.also(onStack::add)?.let { - successors(it).forEach(::dfs) - onStack.remove(it) - order.add(it) - } - - this.forEach { if (it !in visited) dfs(it) } - return order.reversed() -} - -fun Graph.inTopsortOrder(): List? { - val visited = hashSetOf() - val order = mutableListOf() - val stack = hashSetOf() - var foundCycle = false - - fun dfs(node: T) { - if (visited.add(node)) { - stack.add(node) - for (next in successors(node)) { - if (next in stack) { - foundCycle = true - } - dfs(next) - } - stack.remove(node) - order.add(node) - } - } - - val nodes = this.toHashSet() - for (node in nodes) { - dfs(node) - } - return if (foundCycle) null else order.reversed().filter { it in nodes } -} - -fun Graph.SCCs(): OneDirectionGraph> { - val components = components(rpo()) { predecessors(it) } - val colorMap = components.applyFold(hashMapOf>()) { nodes -> - nodes.forEach { put(it, nodes) } - } - return OneDirectionGraph(components) { nodes -> - nodes - .asSequence() - .flatMap { successors(it) } - .map { colorMap[it] } - .requireNoNulls() - .filterNotTo(hashSetOf()) { it == nodes } - } -} - -fun Map.removeNulls(): Map = - entries.filterIsInstance>().associate { (k, v) -> k to v } - -fun Graph.runDP(transition: (T, Map) -> V): Map { - val tsOrder = inTopsortOrder() ?: error("Cannot run DP because of cycle found") - return tsOrder.reversed().applyFold(hashMapOf()) { v -> - put(v, transition.invoke(v, successors(v).associateWith(this::get).removeNulls())) - } -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/Loops.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/Loops.kt deleted file mode 100644 index b6e7859a0..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/Loops.kt +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.utils - -import org.jacodb.panda.staticvm.cfg.PandaGraph -import org.jacodb.panda.staticvm.cfg.PandaInst -import org.jacodb.panda.staticvm.cfg.findDominators -import java.util.ArrayDeque -import kotlin.LazyThreadSafetyMode.PUBLICATION - -class PandaLoop( - val graph: PandaGraph, - val head: PandaInst, - val instructions: List, -) { - val exits: Collection by lazy(PUBLICATION) { - val result = hashSetOf() - for (s in instructions) { - graph.successors(s).forEach { - if (!instructions.contains(it)) { - result.add(s) - } - } - } - result - } - - val backJump: PandaInst get() = instructions.last() - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as PandaLoop - - if (head != other.head) return false - if (instructions != other.instructions) return false - - return true - } - - override fun hashCode(): Int { - var result = head.hashCode() - result = 31 * result + instructions.hashCode() - return result - } -} - -val PandaGraph.loops: Set - get() { - val finder = findDominators() - val loops = HashMap>() - instructions.forEach { inst -> - val dominators = finder.dominators(inst) - - val headers = arrayListOf() - successors(inst).forEach { - if (dominators.contains(it)) { - headers.add(it) - } - } - headers.forEach { header -> - val loopBody = loopBodyOf(header, inst) - loops[header] = loops[header]?.union(loopBody) ?: loopBody - } - } - return loops.map { (key, value) -> - newLoop(key, value) - }.toSet() - } - -private fun PandaGraph.newLoop(head: PandaInst, loopStatements: MutableList): PandaLoop { - // put header to the top - loopStatements.remove(head) - loopStatements.add(0, head) - - // last statement - val backJump = loopStatements.last() - // must branch back to the head - assert(successors(backJump).contains(head)) - return PandaLoop(this, head = head, instructions = loopStatements) -} - -private fun PandaGraph.loopBodyOf(header: PandaInst, inst: PandaInst): MutableList { - val loopBody = arrayListOf(header) - val stack = ArrayDeque().also { - it.push(inst) - } - while (!stack.isEmpty()) { - val next = stack.pop() - if (!loopBody.contains(next)) { - loopBody.add(0, next) - predecessors(next).forEach { stack.push(it) } - } - } - assert(inst === header && loopBody.size == 1 || loopBody[loopBody.size - 2] === inst) - assert(loopBody[loopBody.size - 1] === header) - return loopBody -} - -private fun MutableList.union(another: List): MutableList = apply { - addAll(another.filter { !contains(it) }) -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/OneDirectionGraph.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/OneDirectionGraph.kt deleted file mode 100644 index e19a4cf07..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/OneDirectionGraph.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.utils - -import org.jacodb.api.common.cfg.Graph - -class OneDirectionGraph( - val nodes: Collection, - val successorsGetter: (T) -> Collection, -) : Graph, Collection by nodes.toSet() { - private val successorsMap = hashMapOf>() - - override fun successors(node: T): Set = if (node in nodes) { - successorsMap.getOrPut(node) { successorsGetter(node).toSet() } - } else { - emptySet() - } - - private val predecessorsMap: Map> by lazy { - nodes.applyFold(hashMapOf>()) { - successors(it) - .also { vs -> check(this@OneDirectionGraph.containsAll(vs)) { "Cannot reverse non-closed relation" } } - .map { v -> getOrPut(v) { hashSetOf() }.add(it) } - } - } - - override fun predecessors(node: T) = reversed.successors(node) - - val reversed: OneDirectionGraph by lazy { - OneDirectionGraph(nodes) { predecessorsMap[it].orEmpty() } - } -} diff --git a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/Utils.kt b/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/Utils.kt deleted file mode 100644 index ac4327668..000000000 --- a/jacodb-panda-static/src/main/kotlin/org/jacodb/panda/staticvm/utils/Utils.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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.jacodb.panda.staticvm.utils - -import org.jacodb.panda.staticvm.cfg.PandaCallExpr -import org.jacodb.panda.staticvm.cfg.PandaInst - -/** - * Applies [operation] to [initial] object with all arguments from [Iterable] consecutively - */ -fun Iterable.applyFold(initial: A, operation: A.(T) -> Unit) = - fold(initial) { acc, elem -> acc.apply { operation(elem) } } - -val PandaInst.callExpr: PandaCallExpr? - get() = operands.filterIsInstance().firstOrNull() diff --git a/jacodb-panda-static/src/main/resources/intrinsics.json b/jacodb-panda-static/src/main/resources/intrinsics.json deleted file mode 100644 index 26db08002..000000000 --- a/jacodb-panda-static/src/main/resources/intrinsics.json +++ /dev/null @@ -1,1892 +0,0 @@ -[ - { - "intrinsicId": "MathAbsI32", - "className": "Math", - "methodName": "absI32" - }, - { - "intrinsicId": "MathAbsI64", - "className": "Math", - "methodName": "absI64" - }, - { - "intrinsicId": "MathAbsF32", - "className": "Math", - "methodName": "absF32" - }, - { - "intrinsicId": "MathAbsF64", - "className": "Math", - "methodName": "absF64" - }, - { - "intrinsicId": "MathMinI32", - "className": "Math", - "methodName": "minI32" - }, - { - "intrinsicId": "MathMinI64", - "className": "Math", - "methodName": "minI64" - }, - { - "intrinsicId": "MathMinF32", - "className": "Math", - "methodName": "minF32" - }, - { - "intrinsicId": "MathMinF64", - "className": "Math", - "methodName": "minF64" - }, - { - "intrinsicId": "MathMaxI32", - "className": "Math", - "methodName": "maxI32" - }, - { - "intrinsicId": "MathMaxI64", - "className": "Math", - "methodName": "maxI64" - }, - { - "intrinsicId": "MathMaxF32", - "className": "Math", - "methodName": "maxF32" - }, - { - "intrinsicId": "MathMaxF64", - "className": "Math", - "methodName": "maxF64" - }, - { - "intrinsicId": "DoubleIsInf", - "className": "Double", - "methodName": "isInfinite" - }, - { - "intrinsicId": "FloatIsInf", - "className": "Float", - "methodName": "isInfinite" - }, - { - "intrinsicId": "MathSinF32", - "className": "Math", - "methodName": "fsin" - }, - { - "intrinsicId": "MathSinF64", - "className": "Math", - "methodName": "sin" - }, - { - "intrinsicId": "MathCosF32", - "className": "Math", - "methodName": "fcos" - }, - { - "intrinsicId": "MathCosF64", - "className": "Math", - "methodName": "cos" - }, - { - "intrinsicId": "MathPowF32", - "className": "Math", - "methodName": "fpow" - }, - { - "intrinsicId": "MathPowF64", - "className": "Math", - "methodName": "pow" - }, - { - "intrinsicId": "MathSqrtF32", - "className": "Math", - "methodName": "fsqrt" - }, - { - "intrinsicId": "MathSqrtF64", - "className": "Math", - "methodName": "sqrt" - }, - { - "intrinsicId": "MathCalculateDouble", - "className": "Math", - "methodName": "calculateDouble" - }, - { - "intrinsicId": "MathCalculateFloat", - "className": "Math", - "methodName": "calculateFloat" - }, - { - "intrinsicId": "IOPrintString", - "className": "IO", - "methodName": "printString" - }, - { - "intrinsicId": "IOPrintF32", - "className": "IO", - "methodName": "printF32" - }, - { - "intrinsicId": "IOPrintF64", - "className": "IO", - "methodName": "printF64" - }, - { - "intrinsicId": "IOPrintI32", - "className": "IO", - "methodName": "printI32" - }, - { - "intrinsicId": "IOPrintU32", - "className": "IO", - "methodName": "printU32" - }, - { - "intrinsicId": "IOPrintI64", - "className": "IO", - "methodName": "printI64" - }, - { - "intrinsicId": "IOPrintU64", - "className": "IO", - "methodName": "printU64" - }, - { - "intrinsicId": "SystemCompileMethod", - "className": "System", - "methodName": "compileMethod" - }, - { - "intrinsicId": "SystemExit", - "className": "System", - "methodName": "exit" - }, - { - "intrinsicId": "SystemNanoTime", - "className": "System", - "methodName": "nanoTime" - }, - { - "intrinsicId": "SystemAssert", - "className": "System", - "methodName": "assert" - }, - { - "intrinsicId": "SystemAssertPrint", - "className": "System", - "methodName": "assertPrint" - }, - { - "intrinsicId": "SystemScheduleCoroutine", - "className": "System", - "methodName": "scheduleCoroutine" - }, - { - "intrinsicId": "SystemCoroutineGetWorkerId", - "className": "System", - "methodName": "getCoroutineWorkerId" - }, - { - "intrinsicId": "CheckTag", - "className": "DebugUtils", - "methodName": "checkTag" - }, - { - "intrinsicId": "ConvertStringToI32", - "className": "Convert", - "methodName": "stringToI32" - }, - { - "intrinsicId": "ConvertStringToU32", - "className": "Convert", - "methodName": "stringToU32" - }, - { - "intrinsicId": "ConvertStringToI64", - "className": "Convert", - "methodName": "stringToI64" - }, - { - "intrinsicId": "ConvertStringToU64", - "className": "Convert", - "methodName": "stringToU64" - }, - { - "intrinsicId": "ConvertStringToF32", - "className": "Convert", - "methodName": "stringToF32" - }, - { - "intrinsicId": "ConvertStringToF64", - "className": "Convert", - "methodName": "stringToF64" - }, - { - "intrinsicId": "ObjectCreateNonMovable", - "className": "Object", - "methodName": "createNonMovable" - }, - { - "intrinsicId": "ObjectMonitorEnter", - "className": "Object", - "methodName": "monitorEnter" - }, - { - "intrinsicId": "ObjectMonitorExit", - "className": "Object", - "methodName": "monitorExit" - }, - { - "intrinsicId": "ObjectWait", - "className": "Object", - "methodName": "Wait" - }, - { - "intrinsicId": "ObjectTimedWait", - "className": "Object", - "methodName": "TimedWait" - }, - { - "intrinsicId": "ObjectTimedWaitNanos", - "className": "Object", - "methodName": "TimedWaitNanos" - }, - { - "intrinsicId": "ObjectNotify", - "className": "Object", - "methodName": "Notify" - }, - { - "intrinsicId": "ObjectNotifyAll", - "className": "Object", - "methodName": "NotifyAll" - }, - { - "intrinsicId": "SlowPathEntry", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "SaveRegistersEp", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "RestoreRegistersEp", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "Unreachable", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "TailCall", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "InterpreterReturn", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "LoadAcquireMarkWordExclusive", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "StoreReleaseMarkWordExclusive", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "CompareAndSetMarkWord", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "DataMemoryBarrierFull", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "CompressEightUtf16ToUtf8CharsUsingSimd", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "CompressSixteenUtf16ToUtf8CharsUsingSimd", - "className": "Irtoc", - "methodName": null - }, - { - "intrinsicId": "StdMathSin", - "className": "std.math.ETSGLOBAL", - "methodName": "sin" - }, - { - "intrinsicId": "StdMathCos", - "className": "std.math.ETSGLOBAL", - "methodName": "cos" - }, - { - "intrinsicId": "StdMathPower", - "className": "std.math.ETSGLOBAL", - "methodName": "power" - }, - { - "intrinsicId": "StdMathSqrt", - "className": "std.math.ETSGLOBAL", - "methodName": "sqrt" - }, - { - "intrinsicId": "StdMathAbs", - "className": "std.math.ETSGLOBAL", - "methodName": "abs" - }, - { - "intrinsicId": "StdMathMaxI32", - "className": "std.math.ETSGLOBAL", - "methodName": "max" - }, - { - "intrinsicId": "StdMathMaxI64", - "className": "std.math.ETSGLOBAL", - "methodName": "max" - }, - { - "intrinsicId": "StdMathMaxF32", - "className": "std.math.ETSGLOBAL", - "methodName": "max" - }, - { - "intrinsicId": "StdMathMaxF64", - "className": "std.math.ETSGLOBAL", - "methodName": "max" - }, - { - "intrinsicId": "StdMathMinI32", - "className": "std.math.ETSGLOBAL", - "methodName": "min" - }, - { - "intrinsicId": "StdMathMinI64", - "className": "std.math.ETSGLOBAL", - "methodName": "min" - }, - { - "intrinsicId": "StdMathMinF32", - "className": "std.math.ETSGLOBAL", - "methodName": "min" - }, - { - "intrinsicId": "StdMathMinF64", - "className": "std.math.ETSGLOBAL", - "methodName": "min" - }, - { - "intrinsicId": "StdMathRandom", - "className": "std.math.ETSGLOBAL", - "methodName": "random" - }, - { - "intrinsicId": "StdMathAcos", - "className": "std.math.ETSGLOBAL", - "methodName": "acos" - }, - { - "intrinsicId": "StdMathAcosh", - "className": "std.math.ETSGLOBAL", - "methodName": "acosh" - }, - { - "intrinsicId": "StdMathAsin", - "className": "std.math.ETSGLOBAL", - "methodName": "asin" - }, - { - "intrinsicId": "StdMathAsinh", - "className": "std.math.ETSGLOBAL", - "methodName": "asinh" - }, - { - "intrinsicId": "StdMathAtan2", - "className": "std.math.ETSGLOBAL", - "methodName": "atan2" - }, - { - "intrinsicId": "StdMathAtanh", - "className": "std.math.ETSGLOBAL", - "methodName": "atanh" - }, - { - "intrinsicId": "StdMathAtan", - "className": "std.math.ETSGLOBAL", - "methodName": "atan" - }, - { - "intrinsicId": "StdMathSinh", - "className": "std.math.ETSGLOBAL", - "methodName": "sinh" - }, - { - "intrinsicId": "StdMathCosh", - "className": "std.math.ETSGLOBAL", - "methodName": "cosh" - }, - { - "intrinsicId": "StdMathFloor", - "className": "std.math.ETSGLOBAL", - "methodName": "floor" - }, - { - "intrinsicId": "StdMathRound", - "className": "std.math.ETSGLOBAL", - "methodName": "round" - }, - { - "intrinsicId": "StdMathTrunc", - "className": "std.math.ETSGLOBAL", - "methodName": "trunc" - }, - { - "intrinsicId": "StdMathCbrt", - "className": "std.math.ETSGLOBAL", - "methodName": "cbrt" - }, - { - "intrinsicId": "StdMathTan", - "className": "std.math.ETSGLOBAL", - "methodName": "tan" - }, - { - "intrinsicId": "StdMathTanh", - "className": "std.math.ETSGLOBAL", - "methodName": "tanh" - }, - { - "intrinsicId": "StdMathExp", - "className": "std.math.ETSGLOBAL", - "methodName": "exp" - }, - { - "intrinsicId": "StdMathLog10", - "className": "std.math.ETSGLOBAL", - "methodName": "log10" - }, - { - "intrinsicId": "StdMathExpm1", - "className": "std.math.ETSGLOBAL", - "methodName": "expm1" - }, - { - "intrinsicId": "StdMathCeil", - "className": "std.math.ETSGLOBAL", - "methodName": "ceil" - }, - { - "intrinsicId": "StdMathLog", - "className": "std.math.ETSGLOBAL", - "methodName": "log" - }, - { - "intrinsicId": "StdMathRem", - "className": "std.math.ETSGLOBAL", - "methodName": "rem" - }, - { - "intrinsicId": "StdMathMod", - "className": "std.math.ETSGLOBAL", - "methodName": "mod" - }, - { - "intrinsicId": "StdMathClz64", - "className": "std.math.ETSGLOBAL", - "methodName": "clz64" - }, - { - "intrinsicId": "StdMathClz32", - "className": "std.math.ETSGLOBAL", - "methodName": "clz32" - }, - { - "intrinsicId": "StdMathClz32Double", - "className": "std.math.ETSGLOBAL", - "methodName": "clz32Double" - }, - { - "intrinsicId": "StdMathSignbit", - "className": "std.math.ETSGLOBAL", - "methodName": "signbit" - }, - { - "intrinsicId": "StdMathImul", - "className": "std.math.ETSGLOBAL", - "methodName": "imul" - }, - { - "intrinsicId": "StdMathFround", - "className": "std.math.ETSGLOBAL", - "methodName": "fround" - }, - { - "intrinsicId": "StdConsolePrintString", - "className": "std.core.Console", - "methodName": "print" - }, - { - "intrinsicId": "StdConsolePrintU1", - "className": "std.core.Console", - "methodName": "print" - }, - { - "intrinsicId": "StdConsolePrintI8", - "className": "std.core.Console", - "methodName": "print" - }, - { - "intrinsicId": "StdConsolePrintI16", - "className": "std.core.Console", - "methodName": "print" - }, - { - "intrinsicId": "StdConsolePrintU16", - "className": "std.core.Console", - "methodName": "print" - }, - { - "intrinsicId": "StdConsolePrintI32", - "className": "std.core.Console", - "methodName": "print" - }, - { - "intrinsicId": "StdConsolePrintI64", - "className": "std.core.Console", - "methodName": "print" - }, - { - "intrinsicId": "StdConsolePrintln", - "className": "std.core.Console", - "methodName": "println" - }, - { - "intrinsicId": "StdCoreLoadLibrary", - "className": "std.core.ETSGLOBAL", - "methodName": "loadLibrary" - }, - { - "intrinsicId": "StdCoreStringGetChars", - "className": "std.core.String", - "methodName": "getChars" - }, - { - "intrinsicId": "StdCoreStringGetLength", - "className": "std.core.String", - "methodName": "getLength" - }, - { - "intrinsicId": "StdCoreStringLength", - "className": "std.core.String", - "methodName": "length" - }, - { - "intrinsicId": "StdCoreStringIsEmpty", - "className": "std.core.String", - "methodName": "isEmpty" - }, - { - "intrinsicId": "StdCoreStringCharAt", - "className": "std.core.String", - "methodName": "charAt" - }, - { - "intrinsicId": "StdCoreStringEquals", - "className": "std.core.String", - "methodName": "equals" - }, - { - "intrinsicId": "StdCoreStringLocaleCmp", - "className": "std.core.String", - "methodName": "localeCompare" - }, - { - "intrinsicId": "StdCoreStringNormalizeNFC", - "className": "std.core.String", - "methodName": "normalizeNFC" - }, - { - "intrinsicId": "StdCoreStringNormalizeNFD", - "className": "std.core.String", - "methodName": "normalizeNFD" - }, - { - "intrinsicId": "StdCoreStringNormalizeNFKC", - "className": "std.core.String", - "methodName": "normalizeNFKC" - }, - { - "intrinsicId": "StdCoreStringNormalizeNFKD", - "className": "std.core.String", - "methodName": "normalizeNFKD" - }, - { - "intrinsicId": "StdCoreStringToLowerCase", - "className": "std.core.String", - "methodName": "toLowerCase" - }, - { - "intrinsicId": "StdCoreStringToUpperCase", - "className": "std.core.String", - "methodName": "toUpperCase" - }, - { - "intrinsicId": "StdCoreStringToLocaleLowerCase", - "className": "std.core.String", - "methodName": "toLocaleLowerCase" - }, - { - "intrinsicId": "StdCoreStringToLocaleUpperCase", - "className": "std.core.String", - "methodName": "toLocaleUpperCase" - }, - { - "intrinsicId": "StdCoreStringIsWellFormed", - "className": "std.core.String", - "methodName": "isWellFormed" - }, - { - "intrinsicId": "StdCoreStringIndexOf", - "className": "std.core.String", - "methodName": "indexOf" - }, - { - "intrinsicId": "StdCoreStringIndexOfAfter", - "className": "std.core.String", - "methodName": "indexOf" - }, - { - "intrinsicId": "StdCoreStringIndexOfString", - "className": "std.core.String", - "methodName": "indexOf" - }, - { - "intrinsicId": "StdCoreStringLastIndexOfString", - "className": "std.core.String", - "methodName": "lastIndexOf" - }, - { - "intrinsicId": "StdCoreStringSubstring", - "className": "std.core.String", - "methodName": "substring" - }, - { - "intrinsicId": "StdCoreStringCodePointToChar", - "className": "std.core.String", - "methodName": "codePointToChar" - }, - { - "intrinsicId": "StdCoreStringHashCode", - "className": "std.core.String", - "methodName": "$_hashCode" - }, - { - "intrinsicId": "StdCoreStringIsCompressed", - "className": "std.core.String", - "methodName": "isCompressed" - }, - { - "intrinsicId": "StdCoreStringBuilderConcatStrings", - "className": "std.core.StringBuilder", - "methodName": "concatStrings" - }, - { - "intrinsicId": "StdCoreToStringBoolean", - "className": "std.core.StringBuilder", - "methodName": "toString" - }, - { - "intrinsicId": "StdCoreToStringByte", - "className": "std.core.StringBuilder", - "methodName": "toString" - }, - { - "intrinsicId": "StdCoreToStringChar", - "className": "std.core.StringBuilder", - "methodName": "toString" - }, - { - "intrinsicId": "StdCoreToStringShort", - "className": "std.core.StringBuilder", - "methodName": "toString" - }, - { - "intrinsicId": "StdCoreToStringInt", - "className": "std.core.StringBuilder", - "methodName": "toString" - }, - { - "intrinsicId": "StdCoreToStringLong", - "className": "std.core.StringBuilder", - "methodName": "toString" - }, - { - "intrinsicId": "StdCoreSbAppendFloat", - "className": "std.core.StringBuilder", - "methodName": "append" - }, - { - "intrinsicId": "StdCoreSbAppendDouble", - "className": "std.core.StringBuilder", - "methodName": "append" - }, - { - "intrinsicId": "StdCoreSbAppendLong", - "className": "std.core.StringBuilder", - "methodName": "append" - }, - { - "intrinsicId": "StdCoreSbAppendInt", - "className": "std.core.StringBuilder", - "methodName": "append" - }, - { - "intrinsicId": "StdCoreSbAppendShort", - "className": "std.core.StringBuilder", - "methodName": "append" - }, - { - "intrinsicId": "StdCoreSbAppendByte", - "className": "std.core.StringBuilder", - "methodName": "append" - }, - { - "intrinsicId": "StdCoreSbAppendChar", - "className": "std.core.StringBuilder", - "methodName": "append" - }, - { - "intrinsicId": "StdCoreSbAppendBool", - "className": "std.core.StringBuilder", - "methodName": "append" - }, - { - "intrinsicId": "StdCoreSbAppendString", - "className": "std.core.StringBuilder", - "methodName": "append" - }, - { - "intrinsicId": "StdCoreSbToString", - "className": "std.core.StringBuilder", - "methodName": "toString" - }, - { - "intrinsicId": "EscompatDateNow", - "className": "escompat.Date", - "methodName": "now" - }, - { - "intrinsicId": "EscompatDateGetLocalTimezoneOffset", - "className": "escompat.Date", - "methodName": "getLocalTimezoneOffset" - }, - { - "intrinsicId": "EscompatDateGetTimezoneName", - "className": "escompat.Date", - "methodName": "getTimezoneName" - }, - { - "intrinsicId": "EscompatDateGetLocaleString", - "className": "escompat.Date", - "methodName": "getLocaleString" - }, - { - "intrinsicId": "EscompatArrayBufferFrom", - "className": "escompat.ArrayBuffer", - "methodName": "from" - }, - { - "intrinsicId": "StdTimeDateNanoNow", - "className": "std.time.Chrono", - "methodName": "nanoNow" - }, - { - "intrinsicId": "StdFloatToString", - "className": "std.core.Float", - "methodName": "toString" - }, - { - "intrinsicId": "StdFloatIsNan", - "className": "std.core.Float", - "methodName": "isNaN" - }, - { - "intrinsicId": "StdFloatIsFinite", - "className": "std.core.Float", - "methodName": "isFinite" - }, - { - "intrinsicId": "StdFloatBitCastFromInt", - "className": "std.core.Float", - "methodName": "bitCastFromInt" - }, - { - "intrinsicId": "StdFloatBitCastToInt", - "className": "std.core.Float", - "methodName": "bitCastToInt" - }, - { - "intrinsicId": "StdFloatIsInteger", - "className": "std.core.Float", - "methodName": "isInteger" - }, - { - "intrinsicId": "StdFloatIsSafeInteger", - "className": "std.core.Float", - "methodName": "isSafeInteger" - }, - { - "intrinsicId": "StdDoubleToString", - "className": "std.core.Double", - "methodName": "toString" - }, - { - "intrinsicId": "StdCoreDoubleToLocaleString", - "className": "std.core.Double", - "methodName": "toLocaleString" - }, - { - "intrinsicId": "StdCoreDoubleParseFloat", - "className": "std.core.Double", - "methodName": "parseFloat" - }, - { - "intrinsicId": "StdCoreDoubleParseInt", - "className": "std.core.Double", - "methodName": "parseIntCore" - }, - { - "intrinsicId": "StdCoreDoubleToExponential", - "className": "std.core.Double", - "methodName": "toExponential" - }, - { - "intrinsicId": "StdCoreDoubleToPrecision", - "className": "std.core.Double", - "methodName": "toPrecision" - }, - { - "intrinsicId": "StdCoreDoubleToFixed", - "className": "std.core.Double", - "methodName": "toFixed" - }, - { - "intrinsicId": "StdCoreDoubleNumberFromString", - "className": "std.core.Double", - "methodName": "numberFromString" - }, - { - "intrinsicId": "StdDoubleIsNan", - "className": "std.core.Double", - "methodName": "isNaN" - }, - { - "intrinsicId": "StdDoubleIsFinite", - "className": "std.core.Double", - "methodName": "isFinite" - }, - { - "intrinsicId": "StdDoubleBitCastFromLong", - "className": "std.core.Double", - "methodName": "bitCastFromLong" - }, - { - "intrinsicId": "StdDoubleBitCastToLong", - "className": "std.core.Double", - "methodName": "bitCastToLong" - }, - { - "intrinsicId": "StdDoubleIsInteger", - "className": "std.core.Double", - "methodName": "isInteger" - }, - { - "intrinsicId": "StdDoubleIsSafeInteger", - "className": "std.core.Double", - "methodName": "isSafeInteger" - }, - { - "intrinsicId": "StdCoreAllocGenericArray", - "className": "std.core.ETSGLOBAL", - "methodName": "__alloc_array" - }, - { - "intrinsicId": "StdCoreBoolCopyTo", - "className": "std.core.ETSGLOBAL", - "methodName": "copyTo" - }, - { - "intrinsicId": "StdCoreCharCopyTo", - "className": "std.core.ETSGLOBAL", - "methodName": "copyTo" - }, - { - "intrinsicId": "StdCoreByteCopyTo", - "className": "std.core.ETSGLOBAL", - "methodName": "copyTo" - }, - { - "intrinsicId": "StdCoreShortCopyTo", - "className": "std.core.ETSGLOBAL", - "methodName": "copyTo" - }, - { - "intrinsicId": "StdCoreIntCopyTo", - "className": "std.core.ETSGLOBAL", - "methodName": "copyTo" - }, - { - "intrinsicId": "StdCoreLongCopyTo", - "className": "std.core.ETSGLOBAL", - "methodName": "copyTo" - }, - { - "intrinsicId": "StdCoreFloatCopyTo", - "className": "std.core.ETSGLOBAL", - "methodName": "copyTo" - }, - { - "intrinsicId": "StdCoreDoubleCopyTo", - "className": "std.core.ETSGLOBAL", - "methodName": "copyTo" - }, - { - "intrinsicId": "StdCorePrintStackTrace", - "className": "std.core.ETSGLOBAL", - "methodName": "printStackTrace" - }, - { - "intrinsicId": "StdCoreStackTraceLines", - "className": "std.core.ETSGLOBAL", - "methodName": "stackTraceLines" - }, - { - "intrinsicId": "StdCoreStackTraceProvisionStackTrace", - "className": "std.core.StackTrace", - "methodName": "provisionStackTrace" - }, - { - "intrinsicId": "StdCoreExit", - "className": "std.core.ETSGLOBAL", - "methodName": "exit" - }, - { - "intrinsicId": "StdGCStartGC", - "className": "std.core.GC", - "methodName": "startGCImpl" - }, - { - "intrinsicId": "StdGCWaitForFinishGC", - "className": "std.core.GC", - "methodName": "waitForFinishGC" - }, - { - "intrinsicId": "StdGCScheduleGCAfterNthAlloc", - "className": "std.core.GC", - "methodName": "scheduleGcAfterNthAlloc" - }, - { - "intrinsicId": "StdGCIsScheduledGCTriggered", - "className": "std.core.GC", - "methodName": "isScheduledGCTriggered" - }, - { - "intrinsicId": "StdGCPostponeGCStart", - "className": "std.core.GC", - "methodName": "postponeGCStart" - }, - { - "intrinsicId": "StdGCPostponeGCEnd", - "className": "std.core.GC", - "methodName": "postponeGCEnd" - }, - { - "intrinsicId": "StdGCAllocatePinnedBooleanArray", - "className": "std.core.GC", - "methodName": "allocatePinnedBooleanArray" - }, - { - "intrinsicId": "StdGCAllocatePinnedByteArray", - "className": "std.core.GC", - "methodName": "allocatePinnedByteArray" - }, - { - "intrinsicId": "StdGCAllocatePinnedCharArray", - "className": "std.core.GC", - "methodName": "allocatePinnedCharArray" - }, - { - "intrinsicId": "StdGCAllocatePinnedShortArray", - "className": "std.core.GC", - "methodName": "allocatePinnedShortArray" - }, - { - "intrinsicId": "StdGCAllocatePinnedIntArray", - "className": "std.core.GC", - "methodName": "allocatePinnedIntArray" - }, - { - "intrinsicId": "StdGCAllocatePinnedLongArray", - "className": "std.core.GC", - "methodName": "allocatePinnedLongArray" - }, - { - "intrinsicId": "StdGCAllocatePinnedFloatArray", - "className": "std.core.GC", - "methodName": "allocatePinnedFloatArray" - }, - { - "intrinsicId": "StdGCAllocatePinnedDoubleArray", - "className": "std.core.GC", - "methodName": "allocatePinnedDoubleArray" - }, - { - "intrinsicId": "StdGCGetObjectSpaceType", - "className": "std.core.GC", - "methodName": "getObjectSpaceType" - }, - { - "intrinsicId": "StdGCGetObjectAddress", - "className": "std.core.GC", - "methodName": "getObjectAddress" - }, - { - "intrinsicId": "StdGCPinObject", - "className": "std.core.GC", - "methodName": "pinObject" - }, - { - "intrinsicId": "StdGCUnpinObject", - "className": "std.core.GC", - "methodName": "unpinObject" - }, - { - "intrinsicId": "StdGetFreeHeapSize", - "className": "std.core.GC", - "methodName": "getFreeHeapSize" - }, - { - "intrinsicId": "StdGetUsedHeapSize", - "className": "std.core.GC", - "methodName": "getUsedHeapSize" - }, - { - "intrinsicId": "StdGetReservedHeapSize", - "className": "std.core.GC", - "methodName": "getReservedHeapSize" - }, - { - "intrinsicId": "StdGCRegisterNativeAllocation", - "className": "std.core.GC", - "methodName": "registerNativeAllocation" - }, - { - "intrinsicId": "StdGCRegisterNativeFree", - "className": "std.core.GC", - "methodName": "registerNativeFree" - }, - { - "intrinsicId": "StdFinalizationRegistryRegisterInstance", - "className": "std.core.FinalizationRegistry", - "methodName": "registerInstance" - }, - { - "intrinsicId": "StdPromiseResolve", - "className": "std.core.Promise", - "methodName": "resolveImpl" - }, - { - "intrinsicId": "StdPromiseReject", - "className": "std.core.Promise", - "methodName": "rejectImpl" - }, - { - "intrinsicId": "StdPromiseAddToJobQueue", - "className": "std.core.Promise", - "methodName": "addToJobQueue" - }, - { - "intrinsicId": "StdPromiseAwait", - "className": "std.core.Promise", - "methodName": "awaitResolution" - }, - { - "intrinsicId": "StdCoroutineSchedule", - "className": "std.core.Coroutine", - "methodName": "Schedule" - }, - { - "intrinsicId": "SharedMemoryCreate", - "className": "escompat.SharedMemory", - "methodName": "create" - }, - { - "intrinsicId": "SharedMemoryAddI8", - "className": "escompat.SharedMemory", - "methodName": "atomicAddI8" - }, - { - "intrinsicId": "SharedMemoryAndI8", - "className": "escompat.SharedMemory", - "methodName": "atomicAndI8" - }, - { - "intrinsicId": "SharedMemoryCompareExchangeI8", - "className": "escompat.SharedMemory", - "methodName": "atomicCompareExchangeI8" - }, - { - "intrinsicId": "SharedMemoryExchangeI8", - "className": "escompat.SharedMemory", - "methodName": "atomicExchangeI8" - }, - { - "intrinsicId": "SharedMemoryLoadI8", - "className": "escompat.SharedMemory", - "methodName": "atomicLoadI8" - }, - { - "intrinsicId": "SharedMemoryOrI8", - "className": "escompat.SharedMemory", - "methodName": "atomicOrI8" - }, - { - "intrinsicId": "SharedMemoryStoreI8", - "className": "escompat.SharedMemory", - "methodName": "atomicStoreI8" - }, - { - "intrinsicId": "SharedMemorySubI8", - "className": "escompat.SharedMemory", - "methodName": "atomicSubI8" - }, - { - "intrinsicId": "SharedMemoryXorI8", - "className": "escompat.SharedMemory", - "methodName": "atomicXorI8" - }, - { - "intrinsicId": "SharedMemoryWaitI32", - "className": "escompat.SharedMemory", - "methodName": "atomicWaitI32" - }, - { - "intrinsicId": "SharedMemoryWaitI64", - "className": "escompat.SharedMemory", - "methodName": "atomicWaitI64" - }, - { - "intrinsicId": "SharedMemoryTimedWaitI32", - "className": "escompat.SharedMemory", - "methodName": "atomicTimedWaitI32" - }, - { - "intrinsicId": "SharedMemoryTimedWaitI64", - "className": "escompat.SharedMemory", - "methodName": "atomicTimedWaitI64" - }, - { - "intrinsicId": "SharedMemoryNotify", - "className": "escompat.SharedMemory", - "methodName": "atomicNotify" - }, - { - "intrinsicId": "SharedMemoryBoundedNotify", - "className": "escompat.SharedMemory", - "methodName": "atomicBoundedNotify" - }, - { - "intrinsicId": "StdCoroutineGetWorkerId", - "className": "std.debug.concurrency.CoroutineExtras", - "methodName": "getWorkerId" - }, - { - "intrinsicId": "StdCoroutineSetSchedulingPolicy", - "className": "std.debug.concurrency.CoroutineExtras", - "methodName": "setSchedulingPolicy" - }, - { - "intrinsicId": "StdAtomicFlagSet", - "className": "std.debug.concurrency.AtomicFlag", - "methodName": "set" - }, - { - "intrinsicId": "StdAtomicFlagGet", - "className": "std.debug.concurrency.AtomicFlag", - "methodName": "get" - }, - { - "intrinsicId": "StdRuntimeGetPlatformIsLittleEndian", - "className": "escompat.ETSGLOBAL", - "methodName": "RuntimeGetPlatformIsLittleEndian" - }, - { - "intrinsicId": "StdCoreRuntimeIsSameReference", - "className": "std.core.Runtime", - "methodName": "isSameReference" - }, - { - "intrinsicId": "StdRuntimeGetHashCode", - "className": "std.core.Runtime", - "methodName": "getHashCode" - }, - { - "intrinsicId": "StdCoreRuntimeFailedTypeCastException", - "className": "std.core.Runtime", - "methodName": "failedTypeCastException" - }, - { - "intrinsicId": "StdCoreRuntimeTypeof", - "className": "std.core.Runtime", - "methodName": "typeOf" - }, - { - "intrinsicId": "escompatJSONStringifyObj", - "className": "escompat.JSON", - "methodName": "stringifyObj" - }, - { - "intrinsicId": "EscompatRegExpCompile", - "className": "escompat.RegExp", - "methodName": "compile" - }, - { - "intrinsicId": "EscompatRegExpExec", - "className": "escompat.RegExp", - "methodName": "execImpl" - }, - { - "intrinsicId": "TypeAPIGetTypeDescriptor", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetTypeDescriptor" - }, - { - "intrinsicId": "TypeAPIGetTypeKind", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetTypeKind" - }, - { - "intrinsicId": "TypeAPIIsValueType", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIIsValueType" - }, - { - "intrinsicId": "TypeAPIGetTypeName", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetTypeName" - }, - { - "intrinsicId": "TypeAPIGetClassAttributes", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetClassAttributes" - }, - { - "intrinsicId": "TypeAPIGetFieldsNum", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetFieldsNum" - }, - { - "intrinsicId": "TypeAPIGetOwnFieldsNum", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetOwnFieldsNum" - }, - { - "intrinsicId": "TypeAPIGetField", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetField" - }, - { - "intrinsicId": "TypeAPIGetOwnField", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetOwnField" - }, - { - "intrinsicId": "TypeAPIGetFieldByName", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetFieldByName" - }, - { - "intrinsicId": "TypeAPIGetStaticFieldValue", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetStaticFieldValue" - }, - { - "intrinsicId": "TypeAPIGetMethodsNum", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetMethodsNum" - }, - { - "intrinsicId": "TypeAPIGetMethod", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetMethod" - }, - { - "intrinsicId": "TypeAPIGetConstructorsNum", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetConstructorsNum" - }, - { - "intrinsicId": "TypeAPIGetConstructor", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetConstructor" - }, - { - "intrinsicId": "TypeAPIGetParametersNum", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetParametersNum" - }, - { - "intrinsicId": "TypeAPIGetParameter", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetParameter" - }, - { - "intrinsicId": "TypeAPIGetTypeId", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetTypeId" - }, - { - "intrinsicId": "TypeAPIGetArrayElementType", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetArrayElementType" - }, - { - "intrinsicId": "TypeAPIMakeArrayInstance", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIMakeArrayInstance" - }, - { - "intrinsicId": "TypeAPIGetBaseType", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetBaseType" - }, - { - "intrinsicId": "TypeAPIGetInterfacesNum", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetInterfacesNum" - }, - { - "intrinsicId": "TypeAPIGetInterface", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetInterface" - }, - { - "intrinsicId": "TypeAPISetStaticFieldValue", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPISetStaticFieldValue" - }, - { - "intrinsicId": "TypeAPIIsInheritedFrom", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIIsInheritedFrom" - }, - { - "intrinsicId": "TypeAPIGetFunctionAttributes", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetFunctionAttributes" - }, - { - "intrinsicId": "TypeAPIGetResultType", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetResultType" - }, - { - "intrinsicId": "StdMethodInvoke", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIMethodInvoke" - }, - { - "intrinsicId": "StdMethodInvokeConstructor", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIMethodInvokeConstructor" - }, - { - "intrinsicId": "TypeAPIGetReceiverType", - "className": "std.core.ETSGLOBAL", - "methodName": "TypeAPIGetReceiverType" - }, - { - "intrinsicId": "StdCoreCharIsUpperCase", - "className": "std.core.Char", - "methodName": "isUpperCase" - }, - { - "intrinsicId": "StdCoreCharToUpperCase", - "className": "std.core.Char", - "methodName": "toUpperCase" - }, - { - "intrinsicId": "StdCoreCharIsLowerCase", - "className": "std.core.Char", - "methodName": "isLowerCase" - }, - { - "intrinsicId": "StdCoreCharToLowerCase", - "className": "std.core.Char", - "methodName": "toLowerCase" - }, - { - "intrinsicId": "ValueAPIGetFieldObject", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldObject" - }, - { - "intrinsicId": "ValueAPIGetFieldBoolean", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldBoolean" - }, - { - "intrinsicId": "ValueAPIGetFieldByte", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldByte" - }, - { - "intrinsicId": "ValueAPIGetFieldChar", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldChar" - }, - { - "intrinsicId": "ValueAPIGetFieldShort", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldShort" - }, - { - "intrinsicId": "ValueAPIGetFieldInt", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldInt" - }, - { - "intrinsicId": "ValueAPIGetFieldLong", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldLong" - }, - { - "intrinsicId": "ValueAPIGetFieldFloat", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldFloat" - }, - { - "intrinsicId": "ValueAPIGetFieldDouble", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldDouble" - }, - { - "intrinsicId": "ValueAPIGetFieldByNameObject", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldByNameObject" - }, - { - "intrinsicId": "ValueAPIGetFieldByNameBoolean", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldByNameBoolean" - }, - { - "intrinsicId": "ValueAPIGetFieldByNameByte", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldByNameByte" - }, - { - "intrinsicId": "ValueAPIGetFieldByNameChar", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldByNameChar" - }, - { - "intrinsicId": "ValueAPIGetFieldByNameShort", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldByNameShort" - }, - { - "intrinsicId": "ValueAPIGetFieldByNameInt", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldByNameInt" - }, - { - "intrinsicId": "ValueAPIGetFieldByNameLong", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldByNameLong" - }, - { - "intrinsicId": "ValueAPIGetFieldByNameFloat", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldByNameFloat" - }, - { - "intrinsicId": "ValueAPIGetFieldByNameDouble", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetFieldByNameDouble" - }, - { - "intrinsicId": "ValueAPISetFieldObject", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldObject" - }, - { - "intrinsicId": "ValueAPISetFieldBoolean", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldBoolean" - }, - { - "intrinsicId": "ValueAPISetFieldByte", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldByte" - }, - { - "intrinsicId": "ValueAPISetFieldChar", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldChar" - }, - { - "intrinsicId": "ValueAPISetFieldShort", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldShort" - }, - { - "intrinsicId": "ValueAPISetFieldInt", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldInt" - }, - { - "intrinsicId": "ValueAPISetFieldLong", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldLong" - }, - { - "intrinsicId": "ValueAPISetFieldFloat", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldFloat" - }, - { - "intrinsicId": "ValueAPISetFieldDouble", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldDouble" - }, - { - "intrinsicId": "ValueAPISetFieldByNameObject", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldByNameObject" - }, - { - "intrinsicId": "ValueAPISetFieldByNameBoolean", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldByNameBoolean" - }, - { - "intrinsicId": "ValueAPISetFieldByNameByte", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldByNameByte" - }, - { - "intrinsicId": "ValueAPISetFieldByNameChar", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldByNameChar" - }, - { - "intrinsicId": "ValueAPISetFieldByNameShort", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldByNameShort" - }, - { - "intrinsicId": "ValueAPISetFieldByNameInt", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldByNameInt" - }, - { - "intrinsicId": "ValueAPISetFieldByNameLong", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldByNameLong" - }, - { - "intrinsicId": "ValueAPISetFieldByNameFloat", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldByNameFloat" - }, - { - "intrinsicId": "ValueAPISetFieldByNameDouble", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetFieldByNameDouble" - }, - { - "intrinsicId": "ValueAPIGetArrayLength", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetArrayLength" - }, - { - "intrinsicId": "ValueAPISetElementObject", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetElementObject" - }, - { - "intrinsicId": "ValueAPISetElementBoolean", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetElementBoolean" - }, - { - "intrinsicId": "ValueAPISetElementByte", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetElementByte" - }, - { - "intrinsicId": "ValueAPISetElementChar", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetElementChar" - }, - { - "intrinsicId": "ValueAPISetElementShort", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetElementShort" - }, - { - "intrinsicId": "ValueAPISetElementInt", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetElementInt" - }, - { - "intrinsicId": "ValueAPISetElementLong", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetElementLong" - }, - { - "intrinsicId": "ValueAPISetElementFloat", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetElementFloat" - }, - { - "intrinsicId": "ValueAPISetElementDouble", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPISetElementDouble" - }, - { - "intrinsicId": "ValueAPIGetElementObject", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetElementObject" - }, - { - "intrinsicId": "ValueAPIGetElementBoolean", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetElementBoolean" - }, - { - "intrinsicId": "ValueAPIGetElementByte", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetElementByte" - }, - { - "intrinsicId": "ValueAPIGetElementChar", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetElementChar" - }, - { - "intrinsicId": "ValueAPIGetElementShort", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetElementShort" - }, - { - "intrinsicId": "ValueAPIGetElementInt", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetElementInt" - }, - { - "intrinsicId": "ValueAPIGetElementLong", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetElementLong" - }, - { - "intrinsicId": "ValueAPIGetElementFloat", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetElementFloat" - }, - { - "intrinsicId": "ValueAPIGetElementDouble", - "className": "std.core.ETSGLOBAL", - "methodName": "ValueAPIGetElementDouble" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxCreate", - "className": "std.core.TypeCreatorCtx", - "methodName": "createCtx" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxDestroy", - "className": "std.core.TypeCreatorCtx", - "methodName": "destroyCtx" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxCommit", - "className": "std.core.TypeCreatorCtx", - "methodName": "commit" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxGetError", - "className": "std.core.TypeCreatorCtx", - "methodName": "getError" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxGetObjectsArrayForCCtor", - "className": "std.core.TypeCreatorCtx", - "methodName": "getObjectsArrayForCCtor" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxGetTypeDescFromPointer", - "className": "std.core.TypeCreatorCtx", - "methodName": "getTypeDescFromPointer" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxClassCreate", - "className": "std.core.TypeCreatorCtx", - "methodName": "classCreate" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxClassSetBase", - "className": "std.core.TypeCreatorCtx", - "methodName": "classSetBase" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxClassAddIface", - "className": "std.core.TypeCreatorCtx", - "methodName": "classAddIface" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxClassAddField", - "className": "std.core.TypeCreatorCtx", - "methodName": "classAddField" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxInterfaceCreate", - "className": "std.core.TypeCreatorCtx", - "methodName": "interfaceCreate" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxInterfaceAddBase", - "className": "std.core.TypeCreatorCtx", - "methodName": "interfaceAddBase" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxMethodCreate", - "className": "std.core.TypeCreatorCtx", - "methodName": "methodCreate" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxMethodAddAccessMod", - "className": "std.core.TypeCreatorCtx", - "methodName": "methodAddAccessMod" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxMethodAddParam", - "className": "std.core.TypeCreatorCtx", - "methodName": "methodAddParam" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxMethodAddBodyFromMethod", - "className": "std.core.TypeCreatorCtx", - "methodName": "methodAddBodyFromMethod" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxMethodAddBodyFromLambda", - "className": "std.core.TypeCreatorCtx", - "methodName": "methodAddBodyFromLambda" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxMethodAddBodyFromErasedLambda", - "className": "std.core.TypeCreatorCtx", - "methodName": "methodAddBodyFromErasedLambda" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxMethodAddBodyDefault", - "className": "std.core.TypeCreatorCtx", - "methodName": "methodAddBodyDefault" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxMethodAddResult", - "className": "std.core.TypeCreatorCtx", - "methodName": "methodAddResult" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxMethodAdd", - "className": "std.core.TypeCreatorCtx", - "methodName": "methodAdd" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxLambdaTypeCreate", - "className": "std.core.TypeCreatorCtx", - "methodName": "lambdaTypeCreate" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxLambdaTypeAddParam", - "className": "std.core.TypeCreatorCtx", - "methodName": "lambdaTypeAddParam" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxLambdaTypeAddResult", - "className": "std.core.TypeCreatorCtx", - "methodName": "lambdaTypeAddResult" - }, - { - "intrinsicId": "TypeAPITypeCreatorCtxLambdaTypeAdd", - "className": "std.core.TypeCreatorCtx", - "methodName": "lambdaTypeAdd" - }, - { - "intrinsicId": "CompilerEtsLdObjByNameObj", - "className": null, - "methodName": null - }, - { - "intrinsicId": "CompilerEtsLdObjByNameI32", - "className": null, - "methodName": null - }, - { - "intrinsicId": "CompilerEtsLdObjByNameI64", - "className": null, - "methodName": null - }, - { - "intrinsicId": "CompilerEtsLdObjByNameF32", - "className": null, - "methodName": null - }, - { - "intrinsicId": "CompilerEtsLdObjByNameF64", - "className": null, - "methodName": null - }, - { - "intrinsicId": "CompilerEtsStObjByNameObj", - "className": null, - "methodName": null - }, - { - "intrinsicId": "CompilerEtsStObjByNameI32", - "className": null, - "methodName": null - }, - { - "intrinsicId": "CompilerEtsStObjByNameI64", - "className": null, - "methodName": null - }, - { - "intrinsicId": "CompilerEtsStObjByNameF32", - "className": null, - "methodName": null - }, - { - "intrinsicId": "CompilerEtsStObjByNameF64", - "className": null, - "methodName": null - } -] diff --git a/jacodb-panda-static/src/test/kotlin/panda/PandaDemoCases.kt b/jacodb-panda-static/src/test/kotlin/panda/PandaDemoCases.kt deleted file mode 100644 index e4bb096b5..000000000 --- a/jacodb-panda-static/src/test/kotlin/panda/PandaDemoCases.kt +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 panda - -import org.jacodb.analysis.ifds.SingletonUnit -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.taint.ForwardTaintFlowFunctions -import org.jacodb.analysis.taint.TaintAnalysisOptions -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.util.PandaStaticTraits -import org.jacodb.panda.staticvm.cfg.PandaApplicationGraph -import org.jacodb.panda.staticvm.cfg.PandaInst -import org.jacodb.panda.staticvm.classpath.PandaMethod -import org.jacodb.panda.staticvm.classpath.PandaProject -import org.jacodb.taint.configuration.Argument -import org.jacodb.taint.configuration.AssignMark -import org.jacodb.taint.configuration.ConstantTrue -import org.jacodb.taint.configuration.ContainsMark -import org.jacodb.taint.configuration.Result -import org.jacodb.taint.configuration.TaintConfigurationItem -import org.jacodb.taint.configuration.TaintMark -import org.jacodb.taint.configuration.TaintMethodSink -import org.jacodb.taint.configuration.TaintMethodSource -import org.junit.jupiter.api.condition.EnabledIf -import kotlin.test.Test -import kotlin.test.assertTrue -import kotlin.time.Duration.Companion.seconds - -private val logger = mu.KotlinLogging.logger {} - -class PandaDemoCases { - - companion object : PandaStaticTraits - - private fun loadProject(path: String): PandaProject { - val program = loadProgram("/$path") - val project = PandaProject.fromProgramIr(program, withStdLib = true) - return project - } - - private fun stdlibAvailable() = EtsStdlib.stdlibAvailable() - - @EnabledIf("stdlibAvailable") - @Test - fun `taint analysis on case1`() { - val path = "cases/case1.ir" - val project = loadProject(path) - val graph = PandaApplicationGraph(project) - val unitResolver = UnitResolver { SingletonUnit } - val getConfigForMethod: ForwardTaintFlowFunctions.(PandaMethod) -> List? = - { method -> - val rules = buildList { - if (method.name == "readInt") add( - TaintMethodSource( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - AssignMark(mark = TaintMark("UNTRUSTED"), position = Result), - ), - ) - ) - } - // Return the rules if they are not empty, otherwise return null: - rules.ifEmpty { null } - } - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = getConfigForMethod, - ) - - // Enable untrusted loop bounds analysis: - TaintAnalysisOptions.UNTRUSTED_LOOP_BOUND_SINK = true - - val method = project.classes.flatMap { it.methods }.single { it.name == "onRequest" } - logger.info { "Method: $method" } - val sinks = manager.analyze(listOf(method), timeout = 30.seconds) - logger.info { "Sinks: $sinks" } - assertTrue(sinks.isNotEmpty()) - } - - @EnabledIf("stdlibAvailable") - @Test - fun `taint analysis on case2`() { - val path = "cases/case2.ir" - val project = loadProject(path) - val graph = PandaApplicationGraph(project) - val unitResolver = UnitResolver { SingletonUnit } - val getConfigForMethod: ForwardTaintFlowFunctions.(PandaMethod) -> List? = - { method -> - val rules = buildList { - if (method.name == "readInt") add( - TaintMethodSource( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - AssignMark(mark = TaintMark("UNTRUSTED"), position = Result), - ), - ) - ) - if (method.isConstructor && method.enclosingClass.name == "escompat.ArrayBuffer") add( - TaintMethodSink( - method = method, - ruleNote = "ArrayBuffer constructor", - cwe = emptyList(), - condition = ContainsMark(position = Argument(1), mark = TaintMark("UNTRUSTED")), - ) - ) - } - // Return the rules if they are not empty, otherwise return null: - rules.ifEmpty { null } - } - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = getConfigForMethod, - ) - - // Enable untrusted loop bounds analysis: - TaintAnalysisOptions.UNTRUSTED_LOOP_BOUND_SINK = true - - val method = project.classes.single { - it.name == "Request" - }.methods.single { - it.name == "onRemoteMessageRequest" - } - logger.info { "Method: $method" } - val sinks = manager.analyze(listOf(method), timeout = 30.seconds) - logger.info { "Sinks: $sinks" } - assertTrue(sinks.isNotEmpty()) - } -} diff --git a/jacodb-panda-static/src/test/kotlin/panda/PandaIfdsTest.kt b/jacodb-panda-static/src/test/kotlin/panda/PandaIfdsTest.kt deleted file mode 100644 index fc358d299..000000000 --- a/jacodb-panda-static/src/test/kotlin/panda/PandaIfdsTest.kt +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 panda - -import org.jacodb.analysis.ifds.SingletonUnit -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.taint.ForwardTaintFlowFunctions -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.util.PandaStaticTraits -import org.jacodb.panda.staticvm.cfg.PandaApplicationGraph -import org.jacodb.panda.staticvm.cfg.PandaInst -import org.jacodb.panda.staticvm.classpath.PandaMethod -import org.jacodb.panda.staticvm.classpath.PandaProject -import org.jacodb.taint.configuration.Argument -import org.jacodb.taint.configuration.AssignMark -import org.jacodb.taint.configuration.ConstantTrue -import org.jacodb.taint.configuration.ContainsMark -import org.jacodb.taint.configuration.CopyAllMarks -import org.jacodb.taint.configuration.RemoveMark -import org.jacodb.taint.configuration.Result -import org.jacodb.taint.configuration.TaintConfigurationItem -import org.jacodb.taint.configuration.TaintMark -import org.jacodb.taint.configuration.TaintMethodSink -import org.jacodb.taint.configuration.TaintMethodSource -import org.jacodb.taint.configuration.TaintPassThrough -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.condition.EnabledIf -import kotlin.time.Duration.Companion.seconds - -private val logger = mu.KotlinLogging.logger {} - -class PandaIfdsTest { - - companion object : PandaStaticTraits - - private fun stdlibAvailable() = EtsStdlib.stdlibAvailable() - - private fun loadProject(programName: String): PandaProject { - val program = loadProgram("/$programName.ir") - val project = PandaProject.fromProgramIr(program, withStdLib = true) - return project - } - - @Test - @EnabledIf("stdlibAvailable") - fun `test taint analysis on program 2`() { - runTaintAnalysis("Program2") - } - - @Test - @EnabledIf("stdlibAvailable") - fun `test taint analysis on program with catch`() { - runTaintAnalysis("testCatch") - } - - private fun runTaintAnalysis(programName: String) { - val project = loadProject(programName) - val graph = PandaApplicationGraph(project) - val unitResolver = UnitResolver { SingletonUnit } - val getConfigForMethod: ForwardTaintFlowFunctions.(PandaMethod) -> List? = - { method -> - val rules = buildList { - if (method.name == "source") add( - TaintMethodSource( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - AssignMark(mark = TaintMark("TAINT"), position = Result), - ), - ) - ) - if (method.name == "sink") add( - TaintMethodSink( - method = method, - ruleNote = "SINK", // FIXME - cwe = listOf(), // FIXME - condition = ContainsMark(position = Argument(0), mark = TaintMark("TAINT")) - ) - ) - if (method.name == "pass") add( - TaintPassThrough( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - CopyAllMarks(from = Argument(0), to = Result) - ), - ) - ) - if (method.name == "validate") add( - TaintPassThrough( - method = method, - condition = ConstantTrue, - actionsAfter = listOf( - RemoveMark(mark = TaintMark("TAINT"), position = Argument(0)) - ), - ) - ) - } - rules.ifEmpty { null } - } - val manager = TaintManager( - graph = graph, - unitResolver = unitResolver, - getConfigForMethod = getConfigForMethod, - ) - - val goodMethod = project.classes.flatMap { it.methods }.single { it.name == "good" } - logger.info { "good() method: $goodMethod" } - val goodSinks = manager.analyze(listOf(goodMethod), timeout = 60.seconds) - logger.info { "Sinks in good(): $goodSinks" } - Assertions.assertTrue(goodSinks.isEmpty()) - - val badMethod = project.classes.flatMap { it.methods }.single { it.name == "bad" } - logger.info { "bad() method: $badMethod" } - val badSinks = manager.analyze(listOf(badMethod), timeout = 60.seconds) - logger.info { "Sinks in bad(): $badSinks" } - Assertions.assertTrue(badSinks.isNotEmpty()) - } -} diff --git a/jacodb-panda-static/src/test/kotlin/panda/PandaIrDeserializationTest.kt b/jacodb-panda-static/src/test/kotlin/panda/PandaIrDeserializationTest.kt deleted file mode 100644 index 4bed0edea..000000000 --- a/jacodb-panda-static/src/test/kotlin/panda/PandaIrDeserializationTest.kt +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 panda - -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.json.decodeFromStream -import org.jacodb.panda.staticvm.cfg.PandaApplicationGraph -import org.jacodb.panda.staticvm.classpath.PandaProject -import org.jacodb.panda.staticvm.ir.PandaProgramIr -import org.jacodb.panda.staticvm.ir.PandaProgramIr.Companion.json -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.condition.EnabledIf -import java.io.FileInputStream -import kotlin.time.ExperimentalTime -import kotlin.time.measureTimedValue - -class PandaIrDeserializationTest { - - companion object { - private const val SAMPLE_FILE_PATH: String = "sample.abc.ir" - } - - private fun stdlibAvailable() = EtsStdlib.stdlibAvailable() - - @EnabledIf("stdlibAvailable") - @Test - fun deserializationTest() { - val filePath = SAMPLE_FILE_PATH - val program = loadProgram("/$filePath") - val project = PandaProject.fromProgramIr(program, withStdLib = true) - val applicationGraph = PandaApplicationGraph(project) - } - - @EnabledIf("stdlibAvailable") - @Test - fun catchTest() { - val filePath = "testCatch.ir" - val program = loadProgram("/$filePath") - val project = PandaProject.fromProgramIr(program, withStdLib = true) - val applicationGraph = PandaApplicationGraph(project) - } - - @EnabledIf("stdlibAvailable") - @OptIn(ExperimentalSerializationApi::class, ExperimentalTime::class) - @Test - fun pandaStdLibTest() { - val input = FileInputStream(EtsStdlib.STDLIB_FILE_PATH!!.path) - - val (program, deserializationDuration) = measureTimedValue { - json.decodeFromStream(input) - } - val (project, linkageDuration) = measureTimedValue { - PandaProject.fromProgramIr(program) - } - - println("deserialization: $deserializationDuration, linkage: $linkageDuration") - println("total: ${deserializationDuration + linkageDuration}") - } - - - @EnabledIf("stdlibAvailable") - @Test - fun pandaClasspathFlowGraphTest() { - val filePath = SAMPLE_FILE_PATH - val program = loadProgram("/$filePath") - val project = PandaProject.fromProgramIr(program, withStdLib = true) - val method = project.findMethod("A.greet:i32;void;") - val flowGraph = method.flowGraph() - } -} diff --git a/jacodb-panda-static/src/test/kotlin/panda/TestUtils.kt b/jacodb-panda-static/src/test/kotlin/panda/TestUtils.kt deleted file mode 100644 index 17b5abf0a..000000000 --- a/jacodb-panda-static/src/test/kotlin/panda/TestUtils.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 panda - -import org.jacodb.panda.staticvm.cfg.toDot -import org.jacodb.panda.staticvm.classpath.PandaProject -import org.jacodb.panda.staticvm.ir.EtsStdlib -import org.jacodb.panda.staticvm.ir.PandaProgramIr -import org.jacodb.panda.staticvm.ir.dumpDot -import java.io.File -import java.nio.file.Files -import java.nio.file.Paths - -internal object EtsStdlib { - val STDLIB_FILE_PATH = EtsStdlib::class.java.getResource("stdlib.ir") - - fun stdlibAvailable(): Boolean { - val resource = STDLIB_FILE_PATH?.toURI() - return resource != null && Files.exists(Paths.get(resource)) - } -} - -fun loadProgram(path: String): PandaProgramIr { - val input = object {}::class.java.getResourceAsStream(path) - ?: error("Could not find resource: $path") - val program = PandaProgramIr.from(input) - return program -} - -object DumpIrToDot { - @JvmStatic - fun main(args: Array) { - val filePath = "try_catch_finally.abc.ir" - val program = loadProgram("/$filePath") - - val path = "dump" - val dotFile = File("$path.dot") - program.dumpDot(dotFile) - println("Generated DOT file: ${dotFile.absolutePath}") - for (format in listOf("pdf")) { - val formatFile = File("$path.$format") - val p = Runtime.getRuntime().exec("dot -T$format $dotFile -o $formatFile") - p.waitFor() - print(p.inputStream.bufferedReader().readText()) - print(p.errorStream.bufferedReader().readText()) - println("Generated ${format.uppercase()} file: ${formatFile.absolutePath}") - } - } -} - -object DumpCFGToDot { - @JvmStatic - fun main(args: Array) { - val filePath = "try_catch_finally.abc.ir" - val program = loadProgram("/$filePath") - val cfg = PandaProject.fromProgramIr(program, withStdLib = true) - .findMethod("ETSGLOBAL.main:void;") - .flowGraph() - - val path = "cfg_dump" - val dotFile = File("$path.dot") - dotFile.writer().use { it.write(cfg.toDot()) } - println("Generated DOT file: ${dotFile.absolutePath}") - for (format in listOf("pdf")) { - val formatFile = File("$path.$format") - val p = Runtime.getRuntime().exec("dot -T$format $dotFile -o $formatFile") - p.waitFor() - print(p.inputStream.bufferedReader().readText()) - print(p.errorStream.bufferedReader().readText()) - println("Generated ${format.uppercase()} file: ${formatFile.absolutePath}") - } - } -} diff --git a/jacodb-panda-static/src/test/resources/Program2.ets b/jacodb-panda-static/src/test/resources/Program2.ets deleted file mode 100644 index 6fd3722ab..000000000 --- a/jacodb-panda-static/src/test/resources/Program2.ets +++ /dev/null @@ -1,32 +0,0 @@ -type MaybeString = String | null - -function source(): MaybeString { - return null -} - -function getNull(): MaybeString { - return null -} - -function pass(data: MaybeString) { - return data -} - -function validate(data: MaybeString): MaybeString { - if (data == null) return "OK" - return data -} - -function sink(data: MaybeString) { - if (data == null) throw new Error("Error!") -} - -function bad() { - let data = source() - sink(pass(data)) -} - -function good() { - let data = source() - sink(validate(data)) -} diff --git a/jacodb-panda-static/src/test/resources/Program2.ir b/jacodb-panda-static/src/test/resources/Program2.ir deleted file mode 100644 index ae357b329..000000000 --- a/jacodb-panda-static/src/test/resources/Program2.ir +++ /dev/null @@ -1,1163 +0,0 @@ -{ - "classes": [ - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "attrs", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "td", - "type": "std.core.String" - } - ], - "name": "std.core.FunctionType", - "simpleName": "FunctionType" - }, - { - "accessFlags": 1537, - "name": "std.core.Function10", - "simpleName": "Function10" - }, - { - "accessFlags": 1537, - "name": "std.core.Function0", - "simpleName": "Function0" - }, - { - "accessFlags": 1537, - "name": "std.core.Function3", - "simpleName": "Function3" - }, - { - "accessFlags": 1537, - "name": "std.core.Function7", - "simpleName": "Function7" - }, - { - "accessFlags": 1537, - "name": "std.core.Function6", - "simpleName": "Function6" - }, - { - "accessFlags": 1537, - "name": "std.core.Function", - "simpleName": "Function" - }, - { - "accessFlags": 1537, - "name": "std.core.Function1", - "simpleName": "Function1" - }, - { - "accessFlags": 1537, - "name": "std.core.Function8", - "simpleName": "Function8" - }, - { - "accessFlags": 1537, - "name": "std.core.Function2", - "simpleName": "Function2" - }, - { - "accessFlags": 1537, - "name": "std.core.Function16", - "simpleName": "Function16" - }, - { - "accessFlags": 1025, - "methods": [ - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "SaveState", - "type": "void", - "users": [ - "v2" - ] - }, - { - "id": "v2", - "inputs": [ - "v1" - ], - "method": "ETSGLOBAL.source:std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v3", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v2", - "v3" - ], - "method": "ETSGLOBAL.pass:std.core.String;std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v6" - ] - }, - { - "id": "v5", - "opcode": "SaveState", - "type": "void", - "users": [ - "v6" - ] - }, - { - "id": "v6", - "inputs": [ - "v4", - "v5" - ], - "method": "ETSGLOBAL.sink:std.core.String;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v7", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "bad", - "returnType": "void", - "signature": "ETSGLOBAL.bad:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 4, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v2", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v3" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "Compare", - "operandsType": "ref", - "operator": "EQ", - "type": "u1", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "immediate": 0, - "inputs": [ - "v3" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "insts": [ - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2 - ], - "successors": [ - 5 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v7", - "opcode": "SaveState", - "type": "void", - "users": [ - "v6" - ] - }, - { - "id": "v6", - "inputs": [ - "v7" - ], - "opcode": "LoadString", - "string": "Error!", - "type": "ref", - "users": [ - "v11" - ] - }, - { - "id": "v8", - "opcode": "SaveState", - "type": "void", - "users": [ - "v10", - "v9" - ] - }, - { - "id": "v9", - "inputs": [ - "v8" - ], - "loadedClass": "escompat.Error", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v10" - ] - }, - { - "id": "v10", - "inputs": [ - "v9", - "v8" - ], - "objectClass": "escompat.Error", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v14", - "v11" - ] - }, - { - "id": "v12", - "opcode": "SaveState", - "type": "void", - "users": [ - "v11" - ] - }, - { - "id": "v11", - "inputs": [ - "v10", - "v6", - "v12" - ], - "method": "escompat.Error.:std.core.Object;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v13", - "opcode": "SaveState", - "type": "void", - "users": [ - "v14" - ] - }, - { - "id": "v14", - "inputs": [ - "v10", - "v13" - ], - "opcode": "Throw", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1, - 3 - ] - } - ], - "name": "sink", - "parameters": [ - "std.core.String" - ], - "returnType": "void", - "signature": "ETSGLOBAL.sink:std.core.String;void;" - }, - { - "accessFlags": 8, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "ETSGLOBAL.:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 4, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v8", - "v7", - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v2", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v3" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "Compare", - "operandsType": "ref", - "operator": "EQ", - "type": "u1", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "immediate": 0, - "inputs": [ - "v3" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "insts": [ - { - "id": "v5", - "opcode": "SaveState", - "type": "void", - "users": [ - "v7", - "v6" - ] - }, - { - "id": "v6", - "inputs": [ - "v5" - ], - "opcode": "LoadClass", - "type": "ref", - "users": [ - "v7" - ] - }, - { - "candidateType": "std.core.String", - "id": "v7", - "inputs": [ - "v0", - "v6", - "v5" - ], - "opcode": "CheckCast", - "type": "void" - }, - { - "id": "v8", - "inputs": [ - "v0" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2 - ], - "successors": [ - 5 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v10", - "opcode": "SaveState", - "type": "void", - "users": [ - "v9" - ] - }, - { - "id": "v9", - "inputs": [ - "v10" - ], - "opcode": "LoadString", - "string": "OK", - "type": "ref", - "users": [ - "v11" - ] - }, - { - "id": "v11", - "inputs": [ - "v9" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1, - 3 - ] - } - ], - "name": "validate", - "parameters": [ - "std.core.String" - ], - "returnType": "std.core.String", - "signature": "ETSGLOBAL.validate:std.core.String;std.core.String;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v2" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "inputs": [ - "v0" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "pass", - "parameters": [ - "std.core.String" - ], - "returnType": "std.core.String", - "signature": "ETSGLOBAL.pass:std.core.String;std.core.String;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "SaveState", - "type": "void", - "users": [ - "v2" - ] - }, - { - "id": "v2", - "inputs": [ - "v1" - ], - "method": "ETSGLOBAL.source:std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v3", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v2", - "v3" - ], - "method": "ETSGLOBAL.validate:std.core.String;std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v6" - ] - }, - { - "id": "v5", - "opcode": "SaveState", - "type": "void", - "users": [ - "v6" - ] - }, - { - "id": "v6", - "inputs": [ - "v4", - "v5" - ], - "method": "ETSGLOBAL.sink:std.core.String;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v7", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "good", - "returnType": "void", - "signature": "ETSGLOBAL.good:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v1", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v2" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "inputs": [ - "v1" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "source", - "returnType": "std.core.String", - "signature": "ETSGLOBAL.source:std.core.String;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "_$init$_", - "returnType": "void", - "signature": "ETSGLOBAL._$init$_:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v1", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v2" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "inputs": [ - "v1" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "getNull", - "returnType": "std.core.String", - "signature": "ETSGLOBAL.getNull:std.core.String;" - } - ], - "name": "ETSGLOBAL", - "simpleName": "ETSGLOBAL", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function11", - "simpleName": "Function11" - }, - { - "accessFlags": 1537, - "name": "std.core.FunctionN", - "simpleName": "FunctionN" - }, - { - "accessFlags": 1537, - "name": "std.core.Function15", - "simpleName": "Function15" - }, - { - "accessFlags": 1537, - "name": "std.core.Function12", - "simpleName": "Function12" - }, - { - "accessFlags": 1537, - "name": "std.core.Function5", - "simpleName": "Function5" - }, - { - "accessFlags": 1537, - "name": "std.core.Function14", - "simpleName": "Function14" - }, - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "KEY_NOT_FOUND", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "OBJECT_HAS_OWN_PROPERTY_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "ARRAY_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "MAX_CONSOLE_PRINT_DEPTH", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_LOCALE_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "ObjectTD", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_NAME_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "coroutine", - "type": "std.core.Coroutine" - }, - { - "accessFlags": 0, - "name": "console", - "type": "std.core.Console" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_POINT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_UNIT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "runtime", - "type": "std.core.Runtime" - }, - { - "accessFlags": 0, - "name": "TypeKindMask", - "type": "i8" - }, - { - "accessFlags": 0, - "name": "ObjectType", - "type": "std.core.ClassType" - } - ], - "name": "std.core.ETSGLOBAL", - "simpleName": "ETSGLOBAL" - }, - { - "accessFlags": 1537, - "name": "std.core.Function9", - "simpleName": "Function9" - }, - { - "accessFlags": 1537, - "name": "std.core.Function4", - "simpleName": "Function4" - }, - { - "accessFlags": 1537, - "name": "std.core.Function13", - "simpleName": "Function13" - } - ] -} \ No newline at end of file diff --git a/jacodb-panda-static/src/test/resources/cases/case1.ets b/jacodb-panda-static/src/test/resources/cases/case1.ets deleted file mode 100644 index 9a6cea628..000000000 --- a/jacodb-panda-static/src/test/resources/cases/case1.ets +++ /dev/null @@ -1,13 +0,0 @@ -interface Message { - readInt(): number; -} - -function onRequest(data: Message) { - let opt = data.readInt(); - - for (let i = 0; i < opt; i++) { - console.log(i); - } - - return true; -} diff --git a/jacodb-panda-static/src/test/resources/cases/case1.ir b/jacodb-panda-static/src/test/resources/cases/case1.ir deleted file mode 100644 index af9fe0c6c..000000000 --- a/jacodb-panda-static/src/test/resources/cases/case1.ir +++ /dev/null @@ -1,966 +0,0 @@ -{ - "classes": [ - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "attrs", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "td", - "type": "std.core.String" - } - ], - "name": "std.core.FunctionType", - "simpleName": "FunctionType" - }, - { - "accessFlags": 1537, - "name": "std.core.Function10", - "simpleName": "Function10" - }, - { - "accessFlags": 1537, - "name": "std.core.Function0", - "simpleName": "Function0" - }, - { - "accessFlags": 1537, - "name": "std.core.Function3", - "simpleName": "Function3" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "u16[][].:u16[][];i32;i32;void;" - } - ], - "name": "u16[][]", - "simpleName": "u16[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function7", - "simpleName": "Function7" - }, - { - "accessFlags": 1537, - "name": "std.core.Function6", - "simpleName": "Function6" - }, - { - "accessFlags": 1537, - "name": "std.core.Function", - "simpleName": "Function" - }, - { - "accessFlags": 1537, - "name": "std.core.Function1", - "simpleName": "Function1" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i64[].:i64[];i32;void;" - } - ], - "name": "i64[]", - "simpleName": "i64[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i32[].:i32[];i32;void;" - } - ], - "name": "i32[]", - "simpleName": "i32[]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function8", - "simpleName": "Function8" - }, - { - "accessFlags": 1537, - "name": "std.core.Function2", - "simpleName": "Function2" - }, - { - "accessFlags": 1537, - "methods": [ - { - "accessFlags": 1025, - "name": "readInt", - "returnType": "f64", - "signature": "Message.readInt:f64;" - } - ], - "name": "Message", - "simpleName": "Message", - "superClass": "std.core.Object" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "u1[][].:u1[][];i32;i32;void;" - } - ], - "name": "u1[][]", - "simpleName": "u1[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function16", - "simpleName": "Function16" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "u1[].:u1[];i32;void;" - } - ], - "name": "u1[]", - "simpleName": "u1[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i16[].:i16[];i32;void;" - } - ], - "name": "i16[]", - "simpleName": "i16[]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function11", - "simpleName": "Function11" - }, - { - "accessFlags": 1537, - "name": "std.core.FunctionN", - "simpleName": "FunctionN" - }, - { - "accessFlags": 1537, - "name": "std.core.Function15", - "simpleName": "Function15" - }, - { - "accessFlags": 1537, - "name": "std.core.Function12", - "simpleName": "Function12" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "f32[][].:f32[][];i32;i32;void;" - } - ], - "name": "f32[][]", - "simpleName": "f32[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function5", - "simpleName": "Function5" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "f64[][].:f64[][];i32;i32;void;" - } - ], - "name": "f64[][]", - "simpleName": "f64[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function14", - "simpleName": "Function14" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "u16[].:u16[];i32;void;" - } - ], - "name": "u16[]", - "simpleName": "u16[]" - }, - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "OBJECT_HAS_OWN_PROPERTY_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "KEY_NOT_FOUND", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "ARRAY_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_LOCALE_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_NAME_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "MAX_CONSOLE_PRINT_DEPTH", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "runtime", - "type": "std.core.Runtime" - }, - { - "accessFlags": 0, - "name": "console", - "type": "std.core.Console" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_UNIT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "TypeKindMask", - "type": "i8" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_POINT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "coroutine", - "type": "std.core.Coroutine" - }, - { - "accessFlags": 0, - "name": "ObjectTD", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "ObjectType", - "type": "std.core.ClassType" - } - ], - "name": "std.core.ETSGLOBAL", - "simpleName": "ETSGLOBAL" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i64[][].:i64[][];i32;i32;void;" - } - ], - "name": "i64[][]", - "simpleName": "i64[][]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i16[][].:i16[][];i32;i32;void;" - } - ], - "name": "i16[][]", - "simpleName": "i16[][]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "f64[].:f64[];i32;void;" - } - ], - "name": "f64[]", - "simpleName": "f64[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i8[].:i8[];i32;void;" - } - ], - "name": "i8[]", - "simpleName": "i8[]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function9", - "simpleName": "Function9" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "f32[].:f32[];i32;void;" - } - ], - "name": "f32[]", - "simpleName": "f32[]" - }, - { - "accessFlags": 1025, - "methods": [ - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 4, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "10p", - "v4" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v6", - "opcode": "Constant", - "type": "i32", - "users": [ - "9p" - ], - "value": 0 - }, - { - "id": "v16", - "opcode": "Constant", - "type": "i64", - "users": [ - "v15" - ], - "value": 0 - }, - { - "id": "v25", - "opcode": "Constant", - "type": "i32", - "users": [ - "v27", - "v24" - ], - "value": 1 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void" - }, - { - "id": "v3", - "opcode": "SaveState", - "type": "void", - "users": [ - "v5", - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v0", - "v3" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v5" - ] - }, - { - "id": "v5", - "inputs": [ - "v4", - "v3" - ], - "method": "Message.readInt:f64;", - "opcode": "CallVirtual", - "type": "f64", - "users": [ - "8p" - ] - }, - { - "id": "v7", - "opcode": "SaveStateDeoptimize", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "insts": [ - { - "id": "8p", - "inputBlocks": [ - 0, - 2 - ], - "inputs": [ - "v5", - "8p" - ], - "opcode": "Phi", - "type": "f64", - "users": [ - "8p", - "v14" - ] - }, - { - "id": "9p", - "inputBlocks": [ - 0, - 2 - ], - "inputs": [ - "v6", - "v24" - ], - "opcode": "Phi", - "type": "i32", - "users": [ - "v24", - "v23", - "v13" - ] - }, - { - "id": "10p", - "inputBlocks": [ - 0, - 2 - ], - "inputs": [ - "v0", - "10p" - ], - "opcode": "Phi", - "type": "ref", - "users": [ - "10p" - ] - }, - { - "id": "v12", - "opcode": "SafePoint", - "type": "void" - }, - { - "candidateType": "f64", - "id": "v13", - "inputs": [ - "9p" - ], - "opcode": "Cast", - "type": "f64", - "users": [ - "v14" - ] - }, - { - "id": "v14", - "inputs": [ - "8p", - "v13" - ], - "opcode": "Cmp", - "operandsType": "f64", - "operator": "FCMPL", - "type": "i32", - "users": [ - "v15" - ] - }, - { - "id": "v15", - "inputs": [ - "v14", - "v16" - ], - "opcode": "Compare", - "operandsType": "i32", - "operator": "LE", - "type": "u1", - "users": [ - "v17" - ] - }, - { - "id": "v17", - "immediate": 0, - "inputs": [ - "v15" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0, - 2 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "insts": [ - { - "id": "v18", - "opcode": "SaveState", - "type": "void", - "users": [ - "v19" - ] - }, - { - "id": "v19", - "inputs": [ - "v18" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v20" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v20", - "inputs": [ - "v19" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v22" - ] - }, - { - "id": "v21", - "opcode": "SaveState", - "type": "void", - "users": [ - "v23", - "v22" - ] - }, - { - "id": "v22", - "inputs": [ - "v20", - "v21" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v23" - ] - }, - { - "id": "v23", - "inputs": [ - "v22", - "9p", - "v21" - ], - "method": "std.core.Console.log:i32;void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v24", - "inputs": [ - "9p", - "v25" - ], - "opcode": "Add", - "type": "i32", - "users": [ - "9p" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 3 - ], - "successors": [ - 3 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v26", - "opcode": "SaveState", - "type": "void" - }, - { - "id": "v27", - "inputs": [ - "v25" - ], - "opcode": "Return", - "type": "u1" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 3 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ] - } - ], - "name": "onRequest", - "parameters": [ - "Message" - ], - "returnType": "u1", - "signature": "ETSGLOBAL.onRequest:Message;u1;" - }, - { - "accessFlags": 8, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "ETSGLOBAL.:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "_$init$_", - "returnType": "void", - "signature": "ETSGLOBAL._$init$_:void;" - } - ], - "name": "ETSGLOBAL", - "simpleName": "ETSGLOBAL", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function4", - "simpleName": "Function4" - }, - { - "accessFlags": 1537, - "name": "std.core.Function13", - "simpleName": "Function13" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i32[][].:i32[][];i32;i32;void;" - } - ], - "name": "i32[][]", - "simpleName": "i32[][]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i8[][].:i8[][];i32;i32;void;" - } - ], - "name": "i8[][]", - "simpleName": "i8[][]" - } - ] -} \ No newline at end of file diff --git a/jacodb-panda-static/src/test/resources/cases/case2.ets b/jacodb-panda-static/src/test/resources/cases/case2.ets deleted file mode 100644 index a2b5d1ddb..000000000 --- a/jacodb-panda-static/src/test/resources/cases/case2.ets +++ /dev/null @@ -1,34 +0,0 @@ -interface Message { - readInt(): int; - - readBoolean(): boolean; -} - -class PixelMap { -} - -class Size { - height: int - width: int -} - -function createPixelMap(bytes: ArrayBuffer, size: Size): PixelMap { - return new PixelMap(); -} - -class Request { - onRemoteMessageRequest(data: Message): boolean { - try { - if (data.readBoolean()) { - let height = data.readInt(); - let width = data.readInt(); - let bytesNumber = data.readInt(); - let pixelMap = createPixelMap(new ArrayBuffer(bytesNumber), {height: height, width: width}); - } - return true; - } catch (e) { - console.log(e); - } - return false; - } -} diff --git a/jacodb-panda-static/src/test/resources/cases/case2.ir b/jacodb-panda-static/src/test/resources/cases/case2.ir deleted file mode 100644 index 5391cc6f6..000000000 --- a/jacodb-panda-static/src/test/resources/cases/case2.ir +++ /dev/null @@ -1,1860 +0,0 @@ -{ - "classes": [ - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "attrs", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "td", - "type": "std.core.String" - } - ], - "name": "std.core.FunctionType", - "simpleName": "FunctionType" - }, - { - "accessFlags": 1537, - "name": "std.core.Function10", - "simpleName": "Function10" - }, - { - "accessFlags": 1537, - "name": "std.core.Function0", - "simpleName": "Function0" - }, - { - "accessFlags": 1537, - "name": "std.core.Function3", - "simpleName": "Function3" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "u16[][].:u16[][];i32;i32;void;" - } - ], - "name": "u16[][]", - "simpleName": "u16[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function7", - "simpleName": "Function7" - }, - { - "accessFlags": 1537, - "name": "std.core.Function", - "simpleName": "Function" - }, - { - "accessFlags": 1537, - "name": "std.core.Function1", - "simpleName": "Function1" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "u1[].:u1[];i32;void;" - } - ], - "name": "u1[]", - "simpleName": "u1[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i16[].:i16[];i32;void;" - } - ], - "name": "i16[]", - "simpleName": "i16[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i64[].:i64[];i32;void;" - } - ], - "name": "i64[]", - "simpleName": "i64[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i32[].:i32[];i32;void;" - } - ], - "name": "i32[]", - "simpleName": "i32[]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function8", - "simpleName": "Function8" - }, - { - "accessFlags": 1537, - "name": "std.core.Function2", - "simpleName": "Function2" - }, - { - "accessFlags": 1, - "fields": [ - { - "accessFlags": 1, - "name": "height", - "type": "i32" - }, - { - "accessFlags": 1, - "name": "width", - "type": "i32" - }, - { - "accessFlags": 1, - "name": "height", - "type": "i32" - }, - { - "accessFlags": 1, - "name": "width", - "type": "i32" - } - ], - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "Size.:void;" - } - ], - "name": "Size", - "simpleName": "Size", - "superClass": "std.core.Object" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "u1[][].:u1[][];i32;i32;void;" - } - ], - "name": "u1[][]", - "simpleName": "u1[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function6", - "simpleName": "Function6" - }, - { - "accessFlags": 1537, - "name": "std.core.Function16", - "simpleName": "Function16" - }, - { - "accessFlags": 1537, - "methods": [ - { - "accessFlags": 1025, - "name": "readInt", - "returnType": "i32", - "signature": "Message.readInt:i32;" - }, - { - "accessFlags": 1025, - "name": "readBoolean", - "returnType": "u1", - "signature": "Message.readBoolean:u1;" - } - ], - "name": "Message", - "simpleName": "Message", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function11", - "simpleName": "Function11" - }, - { - "accessFlags": 1537, - "name": "std.core.Function4", - "simpleName": "Function4" - }, - { - "accessFlags": 1537, - "name": "std.core.FunctionN", - "simpleName": "FunctionN" - }, - { - "accessFlags": 1537, - "name": "std.core.Function15", - "simpleName": "Function15" - }, - { - "accessFlags": 1537, - "name": "std.core.Function12", - "simpleName": "Function12" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "f32[][].:f32[][];i32;i32;void;" - } - ], - "name": "f32[][]", - "simpleName": "f32[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function5", - "simpleName": "Function5" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "f64[][].:f64[][];i32;i32;void;" - } - ], - "name": "f64[][]", - "simpleName": "f64[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function14", - "simpleName": "Function14" - }, - { - "accessFlags": 1, - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "PixelMap.:void;" - } - ], - "name": "PixelMap", - "simpleName": "PixelMap", - "superClass": "std.core.Object" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i16[][].:i16[][];i32;i32;void;" - } - ], - "name": "i16[][]", - "simpleName": "i16[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function13", - "simpleName": "Function13" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i32[][].:i32[][];i32;i32;void;" - } - ], - "name": "i32[][]", - "simpleName": "i32[][]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "u16[].:u16[];i32;void;" - } - ], - "name": "u16[]", - "simpleName": "u16[]" - }, - { - "accessFlags": 1025, - "methods": [ - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "_$init$_", - "returnType": "void", - "signature": "ETSGLOBAL._$init$_:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v2", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "opcode": "SaveState", - "type": "void", - "users": [ - "v5", - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3" - ], - "loadedClass": "PixelMap", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v5" - ] - }, - { - "id": "v5", - "inputs": [ - "v4", - "v3" - ], - "objectClass": "PixelMap", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v8", - "v6" - ] - }, - { - "id": "v7", - "opcode": "SaveState", - "type": "void", - "users": [ - "v6" - ] - }, - { - "id": "v6", - "inputs": [ - "v5", - "v7" - ], - "method": "PixelMap.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v8", - "inputs": [ - "v5" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "createPixelMap", - "parameters": [ - "escompat.ArrayBuffer", - "Size" - ], - "returnType": "PixelMap", - "signature": "ETSGLOBAL.createPixelMap:escompat.ArrayBuffer;Size;PixelMap;" - }, - { - "accessFlags": 8, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "ETSGLOBAL.:void;" - } - ], - "name": "ETSGLOBAL", - "simpleName": "ETSGLOBAL", - "superClass": "std.core.Object" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "f64[].:f64[];i32;void;" - } - ], - "name": "f64[]", - "simpleName": "f64[]" - }, - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "OBJECT_HAS_OWN_PROPERTY_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "KEY_NOT_FOUND", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "ARRAY_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_LOCALE_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_NAME_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "MAX_CONSOLE_PRINT_DEPTH", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "runtime", - "type": "std.core.Runtime" - }, - { - "accessFlags": 0, - "name": "console", - "type": "std.core.Console" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_UNIT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "TypeKindMask", - "type": "i8" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_POINT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "coroutine", - "type": "std.core.Coroutine" - }, - { - "accessFlags": 0, - "name": "ObjectTD", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "ObjectType", - "type": "std.core.ClassType" - } - ], - "name": "std.core.ETSGLOBAL", - "simpleName": "ETSGLOBAL" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i64[][].:i64[][];i32;i32;void;" - } - ], - "name": "i64[][]", - "simpleName": "i64[][]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i8[].:i8[];i32;void;" - } - ], - "name": "i8[]", - "simpleName": "i8[]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function9", - "simpleName": "Function9" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "f32[].:f32[];i32;void;" - } - ], - "name": "f32[]", - "simpleName": "f32[]" - }, - { - "accessFlags": 1, - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "Request.:void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 7, - "insts": [ - { - "id": "v12", - "index": 0, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v13", - "index": 1, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v28", - "v25", - "v22", - "v16" - ] - }, - { - "id": "v14", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v19", - "opcode": "Constant", - "type": "i64", - "users": [ - "v18" - ], - "value": 0 - }, - { - "id": "v58", - "opcode": "Constant", - "type": "i32", - "users": [ - "v64", - "v59" - ], - "value": 1 - }, - { - "id": "v67", - "opcode": "Constant", - "type": "i32", - "users": [ - "v77", - "v71" - ], - "value": 0 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 4 - ] - }, - { - "id": 4, - "insts": [ - { - "id": "v0", - "opcode": "Try", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": true, - "isTryEnd": false, - "predecessors": [ - 7 - ], - "successors": [ - 0, - 9 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v15", - "opcode": "SaveState", - "type": "void", - "users": [ - "v17", - "v16" - ] - }, - { - "id": "v16", - "inputs": [ - "v13", - "v15" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v17" - ] - }, - { - "catchers": [ - 9 - ], - "id": "v17", - "inputs": [ - "v16", - "v15" - ], - "method": "Message.readBoolean:u1;", - "opcode": "CallVirtual", - "type": "u1", - "users": [ - "v18" - ] - }, - { - "id": "v18", - "inputs": [ - "v17", - "v19" - ], - "opcode": "Compare", - "operandsType": "i32", - "operator": "EQ", - "type": "u1", - "users": [ - "v20" - ] - }, - { - "id": "v20", - "immediate": 0, - "inputs": [ - "v18" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "insts": [ - { - "id": "v21", - "opcode": "SaveState", - "type": "void", - "users": [ - "v23", - "v22" - ] - }, - { - "id": "v22", - "inputs": [ - "v13", - "v21" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v23" - ] - }, - { - "catchers": [ - 9 - ], - "id": "v23", - "inputs": [ - "v22", - "v21" - ], - "method": "Message.readInt:i32;", - "opcode": "CallVirtual", - "type": "i32", - "users": [ - "v42" - ] - }, - { - "id": "v24", - "opcode": "SaveState", - "type": "void", - "users": [ - "v26", - "v25" - ] - }, - { - "id": "v25", - "inputs": [ - "v13", - "v24" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v26" - ] - }, - { - "catchers": [ - 9 - ], - "id": "v26", - "inputs": [ - "v25", - "v24" - ], - "method": "Message.readInt:i32;", - "opcode": "CallVirtual", - "type": "i32", - "users": [ - "v45" - ] - }, - { - "id": "v27", - "opcode": "SaveState", - "type": "void", - "users": [ - "v29", - "v28" - ] - }, - { - "id": "v28", - "inputs": [ - "v13", - "v27" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v29" - ] - }, - { - "catchers": [ - 9 - ], - "id": "v29", - "inputs": [ - "v28", - "v27" - ], - "method": "Message.readInt:i32;", - "opcode": "CallVirtual", - "type": "i32", - "users": [ - "v33" - ] - }, - { - "id": "v30", - "opcode": "SaveState", - "type": "void", - "users": [ - "v32", - "v31" - ] - }, - { - "catchers": [ - 9 - ], - "id": "v31", - "inputs": [ - "v30" - ], - "loadedClass": "escompat.ArrayBuffer", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v32" - ] - }, - { - "catchers": [ - 9 - ], - "id": "v32", - "inputs": [ - "v31", - "v30" - ], - "objectClass": "escompat.ArrayBuffer", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v47", - "v33" - ] - }, - { - "id": "v34", - "opcode": "SaveState", - "type": "void", - "users": [ - "v33" - ] - }, - { - "catchers": [ - 9 - ], - "id": "v33", - "inputs": [ - "v32", - "v29", - "v34" - ], - "method": "escompat.ArrayBuffer.:i32;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v35", - "opcode": "SaveState", - "type": "void", - "users": [ - "v37", - "v36" - ] - }, - { - "catchers": [ - 9 - ], - "id": "v36", - "inputs": [ - "v35" - ], - "loadedClass": "Size", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v37" - ] - }, - { - "catchers": [ - 9 - ], - "id": "v37", - "inputs": [ - "v36", - "v35" - ], - "objectClass": "Size", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v47", - "v44", - "v41", - "v38" - ] - }, - { - "id": "v39", - "opcode": "SaveState", - "type": "void", - "users": [ - "v38" - ] - }, - { - "catchers": [ - 9 - ], - "id": "v38", - "inputs": [ - "v37", - "v39" - ], - "method": "Size.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v40", - "opcode": "SaveState", - "type": "void", - "users": [ - "v41" - ] - }, - { - "id": "v41", - "inputs": [ - "v37", - "v40" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v42" - ] - }, - { - "catchers": [ - 9 - ], - "enclosingClass": "Size", - "field": "height", - "id": "v42", - "inputs": [ - "v41", - "v23" - ], - "opcode": "StoreObject", - "type": "i32" - }, - { - "id": "v43", - "opcode": "SaveState", - "type": "void", - "users": [ - "v44" - ] - }, - { - "id": "v44", - "inputs": [ - "v37", - "v43" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v45" - ] - }, - { - "catchers": [ - 9 - ], - "enclosingClass": "Size", - "field": "width", - "id": "v45", - "inputs": [ - "v44", - "v26" - ], - "opcode": "StoreObject", - "type": "i32" - }, - { - "id": "v46", - "opcode": "SaveState", - "type": "void", - "users": [ - "v48", - "v47" - ] - }, - { - "catchers": [ - 9 - ], - "id": "v48", - "inputs": [ - "v46" - ], - "opcode": "InitClass", - "type": "void" - }, - { - "catchers": [ - 9 - ], - "id": "v47", - "inputs": [ - "v32", - "v37", - "v46" - ], - "method": "ETSGLOBAL.createPixelMap:escompat.ArrayBuffer;Size;PixelMap;", - "opcode": "CallStatic", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 1 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v59", - "inputs": [ - "v58" - ], - "opcode": "Return", - "type": "u1" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0, - 2 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": true, - "predecessors": [ - 1 - ], - "successors": [ - 8, - 9 - ] - }, - { - "id": 9, - "insts": [ - { - "id": "v11", - "opcode": "CatchPhi", - "type": "ref", - "users": [ - "v73" - ] - } - ], - "isCatchBegin": true, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4, - 5 - ], - "successors": [ - 6 - ] - }, - { - "id": 6, - "insts": [ - { - "id": "v60", - "opcode": "SaveState", - "type": "void", - "users": [ - "v61" - ] - }, - { - "id": "v61", - "inputs": [ - "v60" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v62" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v62", - "inputs": [ - "v61" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v75" - ] - }, - { - "id": "v63", - "opcode": "SaveState", - "type": "void", - "users": [ - "v66", - "v65", - "v64" - ] - }, - { - "id": "v65", - "inputs": [ - "v63" - ], - "loadedClass": "[Lstd/core/Object;", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v66" - ] - }, - { - "id": "v64", - "inputs": [ - "v58", - "v63" - ], - "opcode": "NegativeCheck", - "type": "i32", - "users": [ - "v66" - ] - }, - { - "arrayType": "std.core.Object[]", - "id": "v66", - "inputs": [ - "v65", - "v64", - "v63" - ], - "opcode": "NewArray", - "type": "ref", - "users": [ - "v76", - "v69" - ] - }, - { - "id": "v68", - "opcode": "SaveState", - "type": "void", - "users": [ - "v73", - "v71", - "v69" - ] - }, - { - "id": "v69", - "inputs": [ - "v66", - "v68" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v72", - "v73", - "v70" - ] - }, - { - "id": "v70", - "inputs": [ - "v69" - ], - "opcode": "LenArray", - "type": "i32", - "users": [ - "v71" - ] - }, - { - "id": "v71", - "inputs": [ - "v70", - "v67", - "v68" - ], - "opcode": "BoundsCheck", - "type": "i32", - "users": [ - "v72" - ] - }, - { - "id": "v73", - "inputs": [ - "v69", - "v11", - "v68" - ], - "opcode": "RefTypeCheck", - "type": "ref", - "users": [ - "v72" - ] - }, - { - "id": "v72", - "inputs": [ - "v69", - "v71", - "v73" - ], - "opcode": "StoreArray", - "type": "ref" - }, - { - "id": "v74", - "opcode": "SaveState", - "type": "void", - "users": [ - "v76", - "v75" - ] - }, - { - "id": "v75", - "inputs": [ - "v62", - "v74" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v76" - ] - }, - { - "id": "v76", - "inputs": [ - "v75", - "v66", - "v74" - ], - "method": "std.core.Console.log:void;", - "opcode": "CallVirtual", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 9 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "insts": [ - { - "id": "v77", - "inputs": [ - "v67" - ], - "opcode": "Return", - "type": "u1" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 6 - ], - "successors": [ - 8 - ] - }, - { - "id": 8, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 5, - 3 - ] - } - ], - "name": "onRemoteMessageRequest", - "parameters": [ - "Message" - ], - "returnType": "u1", - "signature": "Request.onRemoteMessageRequest:Message;u1;" - } - ], - "name": "Request", - "simpleName": "Request", - "superClass": "std.core.Object" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i8[][].:i8[][];i32;i32;void;" - } - ], - "name": "i8[][]", - "simpleName": "i8[][]" - } - ] -} \ No newline at end of file diff --git a/jacodb-panda-static/src/test/resources/cases/case3.ets b/jacodb-panda-static/src/test/resources/cases/case3.ets deleted file mode 100644 index a95fc17f9..000000000 --- a/jacodb-panda-static/src/test/resources/cases/case3.ets +++ /dev/null @@ -1,38 +0,0 @@ -class CommonEventPublishData { - code: int; - data: string; -} - -interface MyError { - code: int - name: string - message: string - stack?: string -} - -class CommonEventManager { - publish(event: string, options: CommonEventPublishData, callback: (err: MyError) => void) { - // publish event - } -} - -let commonEventManager = new CommonEventManager(); - -class CommonSecurity { - private publish: String = "" - - private publishEventWithData() { - let options: CommonEventPublishData = { - code: 1, - data: "Password123", - }; - // SINK: send with sensitive data - commonEventManager.publish("MyCommonEvent", options, (err) => { - if (err.code) { - this.publish = "publish event error: " + err.code + ", " + err.message + ", " + err.name + ", " + err.stack; - } else { - this.publish = "publish event with data success"; - } - }); - } -} diff --git a/jacodb-panda-static/src/test/resources/cases/case3.ir b/jacodb-panda-static/src/test/resources/cases/case3.ir deleted file mode 100644 index 1aa292665..000000000 --- a/jacodb-panda-static/src/test/resources/cases/case3.ir +++ /dev/null @@ -1,3122 +0,0 @@ -{ - "classes": [ - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "attrs", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "td", - "type": "std.core.String" - } - ], - "name": "std.core.FunctionType", - "simpleName": "FunctionType" - }, - { - "accessFlags": 1537, - "name": "std.core.Function10", - "simpleName": "Function10" - }, - { - "accessFlags": 1537, - "name": "std.core.Function0", - "simpleName": "Function0" - }, - { - "accessFlags": 1537, - "name": "std.core.Function3", - "simpleName": "Function3" - }, - { - "accessFlags": 1537, - "name": "std.core.Function7", - "simpleName": "Function7" - }, - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "OBJECT_HAS_OWN_PROPERTY_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "ARRAY_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "MAX_CONSOLE_PRINT_DEPTH", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_LOCALE_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "TypeKindMask", - "type": "i8" - }, - { - "accessFlags": 0, - "name": "ObjectType", - "type": "std.core.ClassType" - }, - { - "accessFlags": 0, - "name": "ObjectTD", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_NAME_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_UNIT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "KEY_NOT_FOUND", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "console", - "type": "std.core.Console" - }, - { - "accessFlags": 0, - "name": "runtime", - "type": "std.core.Runtime" - }, - { - "accessFlags": 0, - "name": "coroutine", - "type": "std.core.Coroutine" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_POINT", - "type": "i32" - } - ], - "name": "std.core.ETSGLOBAL", - "simpleName": "ETSGLOBAL" - }, - { - "accessFlags": 1537, - "name": "std.core.Function", - "simpleName": "Function" - }, - { - "accessFlags": 1537, - "name": "std.core.Function14", - "simpleName": "Function14" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "u1[].:u1[];i32;void;" - } - ], - "name": "u1[]", - "simpleName": "u1[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "u16[].:u16[];i32;void;" - } - ], - "name": "u16[]", - "simpleName": "u16[]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function1", - "simpleName": "Function1" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i8[][].:i8[][];i32;i32;void;" - } - ], - "name": "i8[][]", - "simpleName": "i8[][]" - }, - { - "accessFlags": 1537, - "methods": [ - { - "accessFlags": 1025, - "name": "message", - "parameters": [ - "std.core.String" - ], - "returnType": "void", - "signature": "MyError.message:std.core.String;void;" - }, - { - "accessFlags": 1025, - "name": "stack", - "returnType": "std.core.Object", - "signature": "MyError.stack:std.core.Object;" - }, - { - "accessFlags": 1025, - "name": "name", - "returnType": "std.core.String", - "signature": "MyError.name:std.core.String;" - }, - { - "accessFlags": 1025, - "name": "code", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "MyError.code:i32;void;" - }, - { - "accessFlags": 1025, - "name": "message", - "returnType": "std.core.String", - "signature": "MyError.message:std.core.String;" - }, - { - "accessFlags": 1025, - "name": "stack", - "parameters": [ - "std.core.Object" - ], - "returnType": "void", - "signature": "MyError.stack:std.core.Object;void;" - }, - { - "accessFlags": 1025, - "name": "code", - "returnType": "i32", - "signature": "MyError.code:i32;" - }, - { - "accessFlags": 1025, - "name": "name", - "parameters": [ - "std.core.String" - ], - "returnType": "void", - "signature": "MyError.name:std.core.String;void;" - } - ], - "name": "MyError", - "simpleName": "MyError", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function8", - "simpleName": "Function8" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "u16[][].:u16[][];i32;i32;void;" - } - ], - "name": "u16[][]", - "simpleName": "u16[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function6", - "simpleName": "Function6" - }, - { - "accessFlags": 1537, - "name": "std.core.Function16", - "simpleName": "Function16" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "f32[][].:f32[][];i32;i32;void;" - } - ], - "name": "f32[][]", - "simpleName": "f32[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function13", - "simpleName": "Function13" - }, - { - "accessFlags": 1537, - "name": "std.core.Function4", - "simpleName": "Function4" - }, - { - "accessFlags": 1537, - "name": "std.core.Function9", - "simpleName": "Function9" - }, - { - "accessFlags": 1, - "fields": [ - { - "accessFlags": 1, - "name": "data", - "type": "std.core.String" - }, - { - "accessFlags": 1, - "name": "code", - "type": "i32" - }, - { - "accessFlags": 1, - "name": "code", - "type": "i32" - }, - { - "accessFlags": 1, - "name": "data", - "type": "std.core.String" - } - ], - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v7", - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v5", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v8" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v7" - ] - }, - { - "id": "v7", - "inputs": [ - "v0", - "v6" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v8" - ] - }, - { - "enclosingClass": "CommonEventPublishData", - "field": "data", - "id": "v8", - "inputs": [ - "v7", - "v5" - ], - "opcode": "StoreObject", - "type": "ref" - }, - { - "id": "v9", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "CommonEventPublishData.:void;" - } - ], - "name": "CommonEventPublishData", - "simpleName": "CommonEventPublishData", - "superClass": "std.core.Object" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i64[].:i64[];i32;void;" - } - ], - "name": "i64[]", - "simpleName": "i64[]" - }, - { - "accessFlags": 1537, - "name": "std.core.FunctionN", - "simpleName": "FunctionN" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i64[][].:i64[][];i32;i32;void;" - } - ], - "name": "i64[][]", - "simpleName": "i64[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function15", - "simpleName": "Function15" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "f64[].:f64[];i32;void;" - } - ], - "name": "f64[]", - "simpleName": "f64[]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function12", - "simpleName": "Function12" - }, - { - "accessFlags": 1537, - "name": "std.core.Function5", - "simpleName": "Function5" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "u1[][].:u1[][];i32;i32;void;" - } - ], - "name": "u1[][]", - "simpleName": "u1[][]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i32[][].:i32[][];i32;i32;void;" - } - ], - "name": "i32[][]", - "simpleName": "i32[][]" - }, - { - "accessFlags": 1, - "fields": [ - { - "accessFlags": 1, - "name": "field0", - "type": "CommonSecurity" - }, - { - "accessFlags": 1, - "name": "field0", - "type": "CommonSecurity" - } - ], - "interfaces": [ - "std.core.Function1" - ], - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v8" - ] - }, - { - "id": "v2", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v0", - "v3" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v5" - ] - }, - { - "enclosingClass": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0", - "field": "field0", - "id": "v5", - "inputs": [ - "v4" - ], - "opcode": "LoadObject", - "type": "ref", - "users": [ - "v7" - ] - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v8", - "v7" - ] - }, - { - "id": "v7", - "inputs": [ - "v5", - "v6" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v8" - ] - }, - { - "id": "v8", - "inputs": [ - "v7", - "v1", - "v6" - ], - "method": "CommonSecurity.lambda$invoke$0:MyError;void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v9", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "invoke", - "parameters": [ - "MyError" - ], - "returnType": "void", - "signature": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0.invoke:MyError;void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v8", - "v5" - ] - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v9" - ] - }, - { - "id": "v2", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v3", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v6" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v4", - "opcode": "SaveState", - "type": "void", - "users": [ - "v5" - ] - }, - { - "id": "v5", - "inputs": [ - "v0", - "v4" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v6" - ] - }, - { - "enclosingClass": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0", - "field": "field0", - "id": "v6", - "inputs": [ - "v5", - "v3" - ], - "opcode": "StoreObject", - "type": "ref" - }, - { - "id": "v7", - "opcode": "SaveState", - "type": "void", - "users": [ - "v8" - ] - }, - { - "id": "v8", - "inputs": [ - "v0", - "v7" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v9" - ] - }, - { - "enclosingClass": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0", - "field": "field0", - "id": "v9", - "inputs": [ - "v8", - "v1" - ], - "opcode": "StoreObject", - "type": "ref" - }, - { - "id": "v10", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "parameters": [ - "CommonSecurity" - ], - "returnType": "void", - "signature": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0.:CommonSecurity;void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 4, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v19", - "v14", - "v11", - "v6" - ] - }, - { - "id": "v2", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v7", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v6" - ] - }, - { - "id": "v15", - "opcode": "LoadUndefined", - "type": "ref", - "users": [ - "v16" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v0", - "v3" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v5" - ] - }, - { - "enclosingClass": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0", - "field": "field0", - "id": "v5", - "inputs": [ - "v4" - ], - "opcode": "LoadObject", - "type": "ref", - "users": [ - "v13" - ] - }, - { - "id": "v6", - "inputs": [ - "v1", - "v7" - ], - "opcode": "Compare", - "operandsType": "ref", - "operator": "EQ", - "type": "u1", - "users": [ - "v8" - ] - }, - { - "id": "v8", - "immediate": 0, - "inputs": [ - "v6" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "insts": [ - { - "id": "v9", - "opcode": "SaveState", - "type": "void", - "users": [ - "v11", - "v10" - ] - }, - { - "id": "v10", - "inputs": [ - "v9" - ], - "opcode": "LoadClass", - "type": "ref", - "users": [ - "v11" - ] - }, - { - "candidateType": "MyError", - "id": "v11", - "inputs": [ - "v1", - "v10", - "v9" - ], - "opcode": "CheckCast", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "insts": [ - { - "id": "v12", - "opcode": "SaveState", - "type": "void", - "users": [ - "v14", - "v13" - ] - }, - { - "id": "v13", - "inputs": [ - "v5", - "v12" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v14" - ] - }, - { - "id": "v14", - "inputs": [ - "v13", - "v1", - "v12" - ], - "method": "CommonSecurity.lambda$invoke$0:MyError;void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v16", - "inputs": [ - "v15" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2 - ], - "successors": [ - 5 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v18", - "opcode": "SaveState", - "type": "void", - "users": [ - "v17" - ] - }, - { - "id": "v17", - "inputs": [ - "v18" - ], - "opcode": "LoadString", - "string": "MyError", - "type": "ref", - "users": [ - "v19" - ] - }, - { - "id": "v20", - "opcode": "SaveState", - "type": "void", - "users": [ - "v19" - ] - }, - { - "id": "v19", - "inputs": [ - "v1", - "v17", - "v20" - ], - "intrinsicId": "StdCoreRuntimeFailedTypeCastException", - "opcode": "Intrinsic", - "type": "ref", - "users": [ - "v22" - ] - }, - { - "id": "v21", - "opcode": "SaveState", - "type": "void", - "users": [ - "v22" - ] - }, - { - "id": "v22", - "inputs": [ - "v19", - "v21" - ], - "opcode": "Throw", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1, - 3 - ] - } - ], - "name": "invoke0", - "parameters": [ - "std.core.Object" - ], - "returnType": "std.core.Object", - "signature": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0.invoke0:std.core.Object;std.core.Object;" - } - ], - "name": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0", - "simpleName": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0", - "superClass": "std.core.Object" - }, - { - "accessFlags": 8192, - "name": "ets/annotation/EnclosingClass", - "simpleName": "ets/annotation/EnclosingClass" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i8[].:i8[];i32;void;" - } - ], - "name": "i8[]", - "simpleName": "i8[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i16[].:i16[];i32;void;" - } - ], - "name": "i16[]", - "simpleName": "i16[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "f32[].:f32[];i32;void;" - } - ], - "name": "f32[]", - "simpleName": "f32[]" - }, - { - "accessFlags": 1, - "fields": [ - { - "accessFlags": 2, - "name": "publish", - "type": "std.core.String" - }, - { - "accessFlags": 2, - "name": "publish", - "type": "std.core.String" - } - ], - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v8", - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v5" - ] - }, - { - "id": "v5", - "inputs": [ - "v6" - ], - "opcode": "LoadString", - "string": "", - "type": "ref", - "users": [ - "v9" - ] - }, - { - "id": "v7", - "opcode": "SaveState", - "type": "void", - "users": [ - "v8" - ] - }, - { - "id": "v8", - "inputs": [ - "v0", - "v7" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v9" - ] - }, - { - "enclosingClass": "CommonSecurity", - "field": "publish", - "id": "v9", - "inputs": [ - "v8", - "v5" - ], - "opcode": "StoreObject", - "type": "ref" - }, - { - "id": "v10", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "CommonSecurity.:void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 4, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v70", - "v65" - ] - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v53", - "v42", - "v31", - "v20", - "v4" - ] - }, - { - "id": "v2", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v7", - "opcode": "Constant", - "type": "i64", - "users": [ - "v6" - ], - "value": 0 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "opcode": "SaveState", - "type": "void", - "users": [ - "v5", - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v1", - "v3" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v5" - ] - }, - { - "id": "v5", - "inputs": [ - "v4", - "v3" - ], - "method": "MyError.code:i32;", - "opcode": "CallVirtual", - "type": "i32", - "users": [ - "v6" - ] - }, - { - "id": "v6", - "inputs": [ - "v5", - "v7" - ], - "opcode": "Compare", - "operandsType": "i32", - "operator": "EQ", - "type": "u1", - "users": [ - "v8" - ] - }, - { - "id": "v8", - "immediate": 0, - "inputs": [ - "v6" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "insts": [ - { - "id": "v9", - "opcode": "SaveState", - "type": "void", - "users": [ - "v11", - "v10" - ] - }, - { - "id": "v10", - "inputs": [ - "v9" - ], - "loadedClass": "std.core.StringBuilder", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v11" - ] - }, - { - "id": "v11", - "inputs": [ - "v10", - "v9" - ], - "objectClass": "std.core.StringBuilder", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v62", - "v59", - "v50", - "v45", - "v39", - "v34", - "v28", - "v23", - "v17", - "v12" - ] - }, - { - "id": "v13", - "opcode": "SaveState", - "type": "void", - "users": [ - "v12" - ] - }, - { - "id": "v12", - "inputs": [ - "v11", - "v13" - ], - "method": "std.core.StringBuilder.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v15", - "opcode": "SaveState", - "type": "void", - "users": [ - "v14" - ] - }, - { - "id": "v14", - "inputs": [ - "v15" - ], - "opcode": "LoadString", - "string": "publish event error: ", - "type": "ref", - "users": [ - "v18" - ] - }, - { - "id": "v16", - "opcode": "SaveState", - "type": "void", - "users": [ - "v18", - "v17" - ] - }, - { - "id": "v17", - "inputs": [ - "v11", - "v16" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v18" - ] - }, - { - "id": "v18", - "inputs": [ - "v17", - "v14", - "v16" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v19", - "opcode": "SaveState", - "type": "void", - "users": [ - "v21", - "v20" - ] - }, - { - "id": "v20", - "inputs": [ - "v1", - "v19" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v21" - ] - }, - { - "id": "v21", - "inputs": [ - "v20", - "v19" - ], - "method": "MyError.code:i32;", - "opcode": "CallVirtual", - "type": "i32", - "users": [ - "v24" - ] - }, - { - "id": "v22", - "opcode": "SaveState", - "type": "void", - "users": [ - "v24", - "v23" - ] - }, - { - "id": "v23", - "inputs": [ - "v11", - "v22" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v24" - ] - }, - { - "id": "v24", - "inputs": [ - "v23", - "v21", - "v22" - ], - "method": "std.core.StringBuilder.append:i32;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v26", - "opcode": "SaveState", - "type": "void", - "users": [ - "v25" - ] - }, - { - "id": "v25", - "inputs": [ - "v26" - ], - "opcode": "LoadString", - "string": ", ", - "type": "ref", - "users": [ - "v29" - ] - }, - { - "id": "v27", - "opcode": "SaveState", - "type": "void", - "users": [ - "v29", - "v28" - ] - }, - { - "id": "v28", - "inputs": [ - "v11", - "v27" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v29" - ] - }, - { - "id": "v29", - "inputs": [ - "v28", - "v25", - "v27" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v30", - "opcode": "SaveState", - "type": "void", - "users": [ - "v32", - "v31" - ] - }, - { - "id": "v31", - "inputs": [ - "v1", - "v30" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v32" - ] - }, - { - "id": "v32", - "inputs": [ - "v31", - "v30" - ], - "method": "MyError.message:std.core.String;", - "opcode": "CallVirtual", - "type": "ref", - "users": [ - "v35" - ] - }, - { - "id": "v33", - "opcode": "SaveState", - "type": "void", - "users": [ - "v35", - "v34" - ] - }, - { - "id": "v34", - "inputs": [ - "v11", - "v33" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v35" - ] - }, - { - "id": "v35", - "inputs": [ - "v34", - "v32", - "v33" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v37", - "opcode": "SaveState", - "type": "void", - "users": [ - "v36" - ] - }, - { - "id": "v36", - "inputs": [ - "v37" - ], - "opcode": "LoadString", - "string": ", ", - "type": "ref", - "users": [ - "v40" - ] - }, - { - "id": "v38", - "opcode": "SaveState", - "type": "void", - "users": [ - "v40", - "v39" - ] - }, - { - "id": "v39", - "inputs": [ - "v11", - "v38" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v40" - ] - }, - { - "id": "v40", - "inputs": [ - "v39", - "v36", - "v38" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v41", - "opcode": "SaveState", - "type": "void", - "users": [ - "v43", - "v42" - ] - }, - { - "id": "v42", - "inputs": [ - "v1", - "v41" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v43" - ] - }, - { - "id": "v43", - "inputs": [ - "v42", - "v41" - ], - "method": "MyError.name:std.core.String;", - "opcode": "CallVirtual", - "type": "ref", - "users": [ - "v46" - ] - }, - { - "id": "v44", - "opcode": "SaveState", - "type": "void", - "users": [ - "v46", - "v45" - ] - }, - { - "id": "v45", - "inputs": [ - "v11", - "v44" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v46" - ] - }, - { - "id": "v46", - "inputs": [ - "v45", - "v43", - "v44" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v48", - "opcode": "SaveState", - "type": "void", - "users": [ - "v47" - ] - }, - { - "id": "v47", - "inputs": [ - "v48" - ], - "opcode": "LoadString", - "string": ", ", - "type": "ref", - "users": [ - "v51" - ] - }, - { - "id": "v49", - "opcode": "SaveState", - "type": "void", - "users": [ - "v51", - "v50" - ] - }, - { - "id": "v50", - "inputs": [ - "v11", - "v49" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v51" - ] - }, - { - "id": "v51", - "inputs": [ - "v50", - "v47", - "v49" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v52", - "opcode": "SaveState", - "type": "void", - "users": [ - "v54", - "v53" - ] - }, - { - "id": "v53", - "inputs": [ - "v1", - "v52" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v54" - ] - }, - { - "id": "v54", - "inputs": [ - "v53", - "v52" - ], - "method": "MyError.stack:std.core.Object;", - "opcode": "CallVirtual", - "type": "ref", - "users": [ - "v56" - ] - }, - { - "id": "v55", - "opcode": "SaveState", - "type": "void", - "users": [ - "v57", - "v56" - ] - }, - { - "id": "v56", - "inputs": [ - "v54", - "v55" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v57" - ] - }, - { - "id": "v57", - "inputs": [ - "v56", - "v55" - ], - "method": "std.core.Object.toString:std.core.String;", - "opcode": "CallVirtual", - "type": "ref", - "users": [ - "v60" - ] - }, - { - "id": "v58", - "opcode": "SaveState", - "type": "void", - "users": [ - "v60", - "v59" - ] - }, - { - "id": "v59", - "inputs": [ - "v11", - "v58" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v60" - ] - }, - { - "id": "v60", - "inputs": [ - "v59", - "v57", - "v58" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v61", - "opcode": "SaveState", - "type": "void", - "users": [ - "v63", - "v62" - ] - }, - { - "id": "v62", - "inputs": [ - "v11", - "v61" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v63" - ] - }, - { - "id": "v63", - "inputs": [ - "v62", - "v61" - ], - "method": "std.core.StringBuilder.toString:std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v66" - ] - }, - { - "id": "v64", - "opcode": "SaveState", - "type": "void", - "users": [ - "v65" - ] - }, - { - "id": "v65", - "inputs": [ - "v0", - "v64" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v66" - ] - }, - { - "enclosingClass": "CommonSecurity", - "field": "publish", - "id": "v66", - "inputs": [ - "v65", - "v63" - ], - "opcode": "StoreObject", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 3 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v68", - "opcode": "SaveState", - "type": "void", - "users": [ - "v67" - ] - }, - { - "id": "v67", - "inputs": [ - "v68" - ], - "opcode": "LoadString", - "string": "publish event with data success", - "type": "ref", - "users": [ - "v71" - ] - }, - { - "id": "v69", - "opcode": "SaveState", - "type": "void", - "users": [ - "v70" - ] - }, - { - "id": "v70", - "inputs": [ - "v0", - "v69" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v71" - ] - }, - { - "enclosingClass": "CommonSecurity", - "field": "publish", - "id": "v71", - "inputs": [ - "v70", - "v67" - ], - "opcode": "StoreObject", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "insts": [ - { - "id": "v75", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2, - 1 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 3 - ] - } - ], - "name": "lambda$invoke$0", - "parameters": [ - "MyError" - ], - "returnType": "void", - "signature": "CommonSecurity.lambda$invoke$0:MyError;void;" - }, - { - "accessFlags": 2, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v24" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v7", - "opcode": "Constant", - "type": "i32", - "users": [ - "v10" - ], - "value": 1 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v2" - ], - "loadedClass": "CommonEventPublishData", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "objectClass": "CommonEventPublishData", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v28", - "v14", - "v9", - "v5" - ] - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v5" - ] - }, - { - "id": "v5", - "inputs": [ - "v4", - "v6" - ], - "method": "CommonEventPublishData.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v8", - "opcode": "SaveState", - "type": "void", - "users": [ - "v9" - ] - }, - { - "id": "v9", - "inputs": [ - "v4", - "v8" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v10" - ] - }, - { - "enclosingClass": "CommonEventPublishData", - "field": "code", - "id": "v10", - "inputs": [ - "v9", - "v7" - ], - "opcode": "StoreObject", - "type": "i32" - }, - { - "id": "v12", - "opcode": "SaveState", - "type": "void", - "users": [ - "v11" - ] - }, - { - "id": "v11", - "inputs": [ - "v12" - ], - "opcode": "LoadString", - "string": "Password123", - "type": "ref", - "users": [ - "v15" - ] - }, - { - "id": "v13", - "opcode": "SaveState", - "type": "void", - "users": [ - "v14" - ] - }, - { - "id": "v14", - "inputs": [ - "v4", - "v13" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v15" - ] - }, - { - "enclosingClass": "CommonEventPublishData", - "field": "data", - "id": "v15", - "inputs": [ - "v14", - "v11" - ], - "opcode": "StoreObject", - "type": "ref" - }, - { - "id": "v16", - "opcode": "SaveState", - "type": "void", - "users": [ - "v17" - ] - }, - { - "id": "v17", - "inputs": [ - "v16" - ], - "loadedClass": "ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v18" - ] - }, - { - "enclosingClass": "ETSGLOBAL", - "field": "commonEventManager", - "id": "v18", - "inputs": [ - "v17" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v27" - ] - }, - { - "id": "v20", - "opcode": "SaveState", - "type": "void", - "users": [ - "v19" - ] - }, - { - "id": "v19", - "inputs": [ - "v20" - ], - "opcode": "LoadString", - "string": "MyCommonEvent", - "type": "ref", - "users": [ - "v28" - ] - }, - { - "id": "v21", - "opcode": "SaveState", - "type": "void", - "users": [ - "v23", - "v22" - ] - }, - { - "id": "v22", - "inputs": [ - "v21" - ], - "loadedClass": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v23" - ] - }, - { - "id": "v23", - "inputs": [ - "v22", - "v21" - ], - "objectClass": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v28", - "v24" - ] - }, - { - "id": "v25", - "opcode": "SaveState", - "type": "void", - "users": [ - "v24" - ] - }, - { - "id": "v24", - "inputs": [ - "v23", - "v0", - "v25" - ], - "method": "LambdaObject-CommonSecurity-lambda$invoke$0-MyError-void-0.:CommonSecurity;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v26", - "opcode": "SaveState", - "type": "void", - "users": [ - "v28", - "v27" - ] - }, - { - "id": "v27", - "inputs": [ - "v18", - "v26" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v28" - ] - }, - { - "id": "v28", - "inputs": [ - "v27", - "v19", - "v4", - "v23", - "v26" - ], - "method": "CommonEventManager.publish:std.core.String;CommonEventPublishData;std.core.Function1;void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v29", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "publishEventWithData", - "returnType": "void", - "signature": "CommonSecurity.publishEventWithData:void;" - } - ], - "name": "CommonSecurity", - "simpleName": "CommonSecurity", - "superClass": "std.core.Object" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "f64[][].:f64[][];i32;i32;void;" - } - ], - "name": "f64[][]", - "simpleName": "f64[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function2", - "simpleName": "Function2" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i16[][].:i16[][];i32;i32;void;" - } - ], - "name": "i16[][]", - "simpleName": "i16[][]" - }, - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 9, - "name": "commonEventManager", - "type": "CommonEventManager" - }, - { - "accessFlags": 9, - "name": "commonEventManager", - "type": "CommonEventManager" - } - ], - "methods": [ - { - "accessFlags": 8, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "SaveState", - "type": "void", - "users": [ - "v2" - ] - }, - { - "id": "v2", - "inputs": [ - "v1" - ], - "method": "ETSGLOBAL._$init$_:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v3", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "ETSGLOBAL.:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "SaveState", - "type": "void", - "users": [ - "v3", - "v2" - ] - }, - { - "id": "v2", - "inputs": [ - "v1" - ], - "loadedClass": "CommonEventManager", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v2", - "v1" - ], - "objectClass": "CommonEventManager", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v8", - "v4" - ] - }, - { - "id": "v5", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v5" - ], - "method": "CommonEventManager.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v7" - ] - }, - { - "id": "v7", - "inputs": [ - "v6" - ], - "loadedClass": "ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v8" - ] - }, - { - "enclosingClass": "ETSGLOBAL", - "field": "commonEventManager", - "id": "v8", - "inputs": [ - "v7", - "v3" - ], - "opcode": "StoreStatic", - "type": "ref" - }, - { - "id": "v9", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "_$init$_", - "returnType": "void", - "signature": "ETSGLOBAL._$init$_:void;" - } - ], - "name": "ETSGLOBAL", - "simpleName": "ETSGLOBAL", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function11", - "simpleName": "Function11" - }, - { - "accessFlags": 1, - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "CommonEventManager.:void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v2", - "index": 2, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v3", - "index": 3, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v4", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "publish", - "parameters": [ - "std.core.String", - "CommonEventPublishData", - "std.core.Function1" - ], - "returnType": "void", - "signature": "CommonEventManager.publish:std.core.String;CommonEventPublishData;std.core.Function1;void;" - } - ], - "name": "CommonEventManager", - "simpleName": "CommonEventManager", - "superClass": "std.core.Object" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i32[].:i32[];i32;void;" - } - ], - "name": "i32[]", - "simpleName": "i32[]" - }, - { - "accessFlags": 8192, - "name": "ets/annotation/InnerClass", - "simpleName": "ets/annotation/InnerClass" - } - ] -} \ No newline at end of file diff --git a/jacodb-panda-static/src/test/resources/cases/case4.ets b/jacodb-panda-static/src/test/resources/cases/case4.ets deleted file mode 100644 index 61ed48503..000000000 --- a/jacodb-panda-static/src/test/resources/cases/case4.ets +++ /dev/null @@ -1,99 +0,0 @@ -interface Context { -} - -declare function getContext(): Context; - -class AtManager { -} - -class AbilityAccessCtrl { - createAtManager(): AtManager { - return {}; - } -} - -let abilityAccessCtrl = new AbilityAccessCtrl(); - -type Permissions = string; - -class PermissionUtil { - static requestPermissionsFromUser(permissions: Permissions[]): boolean { - return true; - } -} - -class Settings { - setValue(context: Context, key: string, value: string) { - } - - getValue(context: Context, key: string): string { - return ""; - } -} - -let settings = new Settings(); - -class Pasteboard { - clear() { - // - } - - setPasteData(pasteData: string) { - // - } -} - -// From 'pasteboard' module. -function getSystemPasteboard(): Pasteboard { - return new Pasteboard(); -} - -// From 'pasteboard' module. -function createPlainTextData(data: string): string { - return data; -} - -class Setting { - private context: Context = getContext(); - - setData() { - let atManager = abilityAccessCtrl.createAtManager(); - let message = "helloWorld"; - let password = "Password123"; - try { - // Verify whether the application is granted setting permission - const permissions: Permissions[] = ['ohos.permission.MANAGE_SECURE_SETTINGS']; - if (PermissionUtil.requestPermissionsFromUser(permissions)) { - settings.setValue(this.context, 'message', message); - - // SINK: The application stores the password of sensitive information in the settings database - settings.setValue(this.context, "password", password) - } else { - // Unauthorized - } - } catch (err) { - return; - } - } - - // SINK: Any application can directly read the data of the settings database, causing information leakage - getData() { - let value = settings.getValue(this.context, "password") - console.log("get settings customs data password: " + value) - } - - // It is forbidden to store severity level data in the clipboard - pasteboard() { - // Counterexample: Text copy - console.log('Get SystemPasteboard') - let systemPasteboard = getSystemPasteboard() - systemPasteboard.clear() - - let password = 'Password123' - console.log('createPlainTextData = ' + password) - let pasteData = createPlainTextData(password) - - console.log('Writes PasteData to the pasteboard') - systemPasteboard.setPasteData(pasteData) - } -} diff --git a/jacodb-panda-static/src/test/resources/cases/case4.ir b/jacodb-panda-static/src/test/resources/cases/case4.ir deleted file mode 100644 index 4814377ad..000000000 --- a/jacodb-panda-static/src/test/resources/cases/case4.ir +++ /dev/null @@ -1,4544 +0,0 @@ -{ - "classes": [ - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "attrs", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "td", - "type": "std.core.String" - } - ], - "name": "std.core.FunctionType", - "simpleName": "FunctionType" - }, - { - "accessFlags": 1537, - "name": "std.core.Function10", - "simpleName": "Function10" - }, - { - "accessFlags": 1537, - "name": "std.core.Function0", - "simpleName": "Function0" - }, - { - "accessFlags": 1537, - "name": "std.core.Function3", - "simpleName": "Function3" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "u16[][].:u16[][];i32;i32;void;" - } - ], - "name": "u16[][]", - "simpleName": "u16[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function7", - "simpleName": "Function7" - }, - { - "accessFlags": 1537, - "name": "std.core.Function", - "simpleName": "Function" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "u1[].:u1[];i32;void;" - } - ], - "name": "u1[]", - "simpleName": "u1[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i16[].:i16[];i32;void;" - } - ], - "name": "i16[]", - "simpleName": "i16[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i64[].:i64[];i32;void;" - } - ], - "name": "i64[]", - "simpleName": "i64[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i32[].:i32[];i32;void;" - } - ], - "name": "i32[]", - "simpleName": "i32[]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function2", - "simpleName": "Function2" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "u1[][].:u1[][];i32;i32;void;" - } - ], - "name": "u1[][]", - "simpleName": "u1[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function6", - "simpleName": "Function6" - }, - { - "accessFlags": 1537, - "name": "std.core.Function16", - "simpleName": "Function16" - }, - { - "accessFlags": 1, - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "Pasteboard.:void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v2", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "setPasteData", - "parameters": [ - "std.core.String" - ], - "returnType": "void", - "signature": "Pasteboard.setPasteData:std.core.String;void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "clear", - "returnType": "void", - "signature": "Pasteboard.clear:void;" - } - ], - "name": "Pasteboard", - "simpleName": "Pasteboard", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function1", - "simpleName": "Function1" - }, - { - "accessFlags": 1537, - "name": "std.core.Function11", - "simpleName": "Function11" - }, - { - "accessFlags": 1, - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "AtManager.:void;" - } - ], - "name": "AtManager", - "simpleName": "AtManager", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function4", - "simpleName": "Function4" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "f32[][].:f32[][];i32;i32;void;" - } - ], - "name": "f32[][]", - "simpleName": "f32[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.FunctionN", - "simpleName": "FunctionN" - }, - { - "accessFlags": 1537, - "name": "Context", - "simpleName": "Context", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function15", - "simpleName": "Function15" - }, - { - "accessFlags": 1537, - "name": "std.core.Function12", - "simpleName": "Function12" - }, - { - "accessFlags": 1537, - "name": "std.core.Function5", - "simpleName": "Function5" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "f64[][].:f64[][];i32;i32;void;" - } - ], - "name": "f64[][]", - "simpleName": "f64[][]" - }, - { - "accessFlags": 1, - "fields": [ - { - "accessFlags": 2, - "name": "context", - "type": "Context" - }, - { - "accessFlags": 2, - "name": "context", - "type": "Context" - } - ], - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v6" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v16", - "opcode": "Constant", - "type": "i32", - "users": [ - "v18" - ], - "value": 1 - }, - { - "id": "v21", - "opcode": "Constant", - "type": "i32", - "users": [ - "v41" - ], - "value": 0 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v2" - ], - "loadedClass": "ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "enclosingClass": "ETSGLOBAL", - "field": "settings", - "id": "v4", - "inputs": [ - "v3" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v11" - ] - }, - { - "id": "v5", - "opcode": "SaveState", - "type": "void", - "users": [ - "v6" - ] - }, - { - "id": "v6", - "inputs": [ - "v0", - "v5" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v7" - ] - }, - { - "enclosingClass": "Setting", - "field": "context", - "id": "v7", - "inputs": [ - "v6" - ], - "opcode": "LoadObject", - "type": "ref", - "users": [ - "v12" - ] - }, - { - "id": "v9", - "opcode": "SaveState", - "type": "void", - "users": [ - "v8" - ] - }, - { - "id": "v8", - "inputs": [ - "v9" - ], - "opcode": "LoadString", - "string": "password", - "type": "ref", - "users": [ - "v12" - ] - }, - { - "id": "v10", - "opcode": "SaveState", - "type": "void", - "users": [ - "v12", - "v11" - ] - }, - { - "id": "v11", - "inputs": [ - "v4", - "v10" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v12" - ] - }, - { - "id": "v12", - "inputs": [ - "v11", - "v7", - "v8", - "v10" - ], - "method": "Settings.getValue:Context;std.core.String;std.core.String;", - "opcode": "CallVirtual", - "type": "ref", - "users": [ - "v34" - ] - }, - { - "id": "v13", - "opcode": "SaveState", - "type": "void", - "users": [ - "v14" - ] - }, - { - "id": "v14", - "inputs": [ - "v13" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v15" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v15", - "inputs": [ - "v14" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v45" - ] - }, - { - "id": "v17", - "opcode": "SaveState", - "type": "void", - "users": [ - "v20", - "v19", - "v18" - ] - }, - { - "id": "v19", - "inputs": [ - "v17" - ], - "loadedClass": "[Lstd/core/Object;", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v20" - ] - }, - { - "id": "v18", - "inputs": [ - "v16", - "v17" - ], - "opcode": "NegativeCheck", - "type": "i32", - "users": [ - "v20" - ] - }, - { - "arrayType": "std.core.Object[]", - "id": "v20", - "inputs": [ - "v19", - "v18", - "v17" - ], - "opcode": "NewArray", - "type": "ref", - "users": [ - "v46", - "v39" - ] - }, - { - "id": "v22", - "opcode": "SaveState", - "type": "void", - "users": [ - "v24", - "v23" - ] - }, - { - "id": "v23", - "inputs": [ - "v22" - ], - "loadedClass": "std.core.StringBuilder", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v24" - ] - }, - { - "id": "v24", - "inputs": [ - "v23", - "v22" - ], - "objectClass": "std.core.StringBuilder", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v36", - "v33", - "v30", - "v25" - ] - }, - { - "id": "v26", - "opcode": "SaveState", - "type": "void", - "users": [ - "v25" - ] - }, - { - "id": "v25", - "inputs": [ - "v24", - "v26" - ], - "method": "std.core.StringBuilder.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v28", - "opcode": "SaveState", - "type": "void", - "users": [ - "v27" - ] - }, - { - "id": "v27", - "inputs": [ - "v28" - ], - "opcode": "LoadString", - "string": "get settings customs data password: ", - "type": "ref", - "users": [ - "v31" - ] - }, - { - "id": "v29", - "opcode": "SaveState", - "type": "void", - "users": [ - "v31", - "v30" - ] - }, - { - "id": "v30", - "inputs": [ - "v24", - "v29" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v31" - ] - }, - { - "id": "v31", - "inputs": [ - "v30", - "v27", - "v29" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v32", - "opcode": "SaveState", - "type": "void", - "users": [ - "v34", - "v33" - ] - }, - { - "id": "v33", - "inputs": [ - "v24", - "v32" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v34" - ] - }, - { - "id": "v34", - "inputs": [ - "v33", - "v12", - "v32" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v35", - "opcode": "SaveState", - "type": "void", - "users": [ - "v37", - "v36" - ] - }, - { - "id": "v36", - "inputs": [ - "v24", - "v35" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v37" - ] - }, - { - "id": "v37", - "inputs": [ - "v36", - "v35" - ], - "method": "std.core.StringBuilder.toString:std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v43" - ] - }, - { - "id": "v38", - "opcode": "SaveState", - "type": "void", - "users": [ - "v43", - "v41", - "v39" - ] - }, - { - "id": "v39", - "inputs": [ - "v20", - "v38" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v42", - "v43", - "v40" - ] - }, - { - "id": "v40", - "inputs": [ - "v39" - ], - "opcode": "LenArray", - "type": "i32", - "users": [ - "v41" - ] - }, - { - "id": "v41", - "inputs": [ - "v40", - "v21", - "v38" - ], - "opcode": "BoundsCheck", - "type": "i32", - "users": [ - "v42" - ] - }, - { - "id": "v43", - "inputs": [ - "v39", - "v37", - "v38" - ], - "opcode": "RefTypeCheck", - "type": "ref", - "users": [ - "v42" - ] - }, - { - "id": "v42", - "inputs": [ - "v39", - "v41", - "v43" - ], - "opcode": "StoreArray", - "type": "ref" - }, - { - "id": "v44", - "opcode": "SaveState", - "type": "void", - "users": [ - "v46", - "v45" - ] - }, - { - "id": "v45", - "inputs": [ - "v15", - "v44" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v46" - ] - }, - { - "id": "v46", - "inputs": [ - "v45", - "v20", - "v44" - ], - "method": "std.core.Console.log:void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v47", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "getData", - "returnType": "void", - "signature": "Setting.getData:void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 8, - "insts": [ - { - "id": "v11", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v58", - "v47" - ] - }, - { - "id": "v12", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v23", - "opcode": "Constant", - "type": "i32", - "users": [ - "v25" - ], - "value": 1 - }, - { - "id": "v28", - "opcode": "Constant", - "type": "i32", - "users": [ - "v34" - ], - "value": 0 - }, - { - "id": "v41", - "opcode": "Constant", - "type": "i64", - "users": [ - "v40" - ], - "value": 0 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v13", - "opcode": "SaveState", - "type": "void", - "users": [ - "v14" - ] - }, - { - "id": "v14", - "inputs": [ - "v13" - ], - "loadedClass": "ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v15" - ] - }, - { - "enclosingClass": "ETSGLOBAL", - "field": "abilityAccessCtrl", - "id": "v15", - "inputs": [ - "v14" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v17" - ] - }, - { - "id": "v16", - "opcode": "SaveState", - "type": "void", - "users": [ - "v18", - "v17" - ] - }, - { - "id": "v17", - "inputs": [ - "v15", - "v16" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v18" - ] - }, - { - "id": "v18", - "inputs": [ - "v17", - "v16" - ], - "method": "AbilityAccessCtrl.createAtManager:AtManager;", - "opcode": "CallVirtual", - "type": "ref" - }, - { - "id": "v20", - "opcode": "SaveState", - "type": "void", - "users": [ - "v19" - ] - }, - { - "id": "v19", - "inputs": [ - "v20" - ], - "opcode": "LoadString", - "string": "helloWorld", - "type": "ref", - "users": [ - "v53" - ] - }, - { - "id": "v22", - "opcode": "SaveState", - "type": "void", - "users": [ - "v21" - ] - }, - { - "id": "v21", - "inputs": [ - "v22" - ], - "opcode": "LoadString", - "string": "Password123", - "type": "ref", - "users": [ - "v64" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 8 - ], - "successors": [ - 4 - ] - }, - { - "id": 4, - "insts": [ - { - "id": "v0", - "opcode": "Try", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": true, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 6, - 10 - ] - }, - { - "id": 6, - "insts": [ - { - "id": "v24", - "opcode": "SaveState", - "type": "void", - "users": [ - "v27", - "v26", - "v25" - ] - }, - { - "catchers": [ - 10 - ], - "id": "v26", - "inputs": [ - "v24" - ], - "loadedClass": "[Lstd/core/String;", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v27" - ] - }, - { - "id": "v25", - "inputs": [ - "v23", - "v24" - ], - "opcode": "NegativeCheck", - "type": "i32", - "users": [ - "v27" - ] - }, - { - "arrayType": "std.core.String[]", - "catchers": [ - 10 - ], - "id": "v27", - "inputs": [ - "v26", - "v25", - "v24" - ], - "opcode": "NewArray", - "type": "ref", - "users": [ - "66p", - "65p", - "v38", - "v32" - ] - }, - { - "id": "v30", - "opcode": "SaveState", - "type": "void", - "users": [ - "v29" - ] - }, - { - "catchers": [ - 10 - ], - "id": "v29", - "inputs": [ - "v30" - ], - "opcode": "LoadString", - "string": "ohos.permission.MANAGE_SECURE_SETTINGS", - "type": "ref", - "users": [ - "v36" - ] - }, - { - "id": "v31", - "opcode": "SaveState", - "type": "void", - "users": [ - "v36", - "v34", - "v32" - ] - }, - { - "id": "v32", - "inputs": [ - "v27", - "v31" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v35", - "v36", - "v33" - ] - }, - { - "id": "v33", - "inputs": [ - "v32" - ], - "opcode": "LenArray", - "type": "i32", - "users": [ - "v34" - ] - }, - { - "id": "v34", - "inputs": [ - "v33", - "v28", - "v31" - ], - "opcode": "BoundsCheck", - "type": "i32", - "users": [ - "v35" - ] - }, - { - "id": "v36", - "inputs": [ - "v32", - "v29", - "v31" - ], - "opcode": "RefTypeCheck", - "type": "ref", - "users": [ - "v35" - ] - }, - { - "catchers": [ - 10 - ], - "id": "v35", - "inputs": [ - "v32", - "v34", - "v36" - ], - "opcode": "StoreArray", - "type": "ref" - }, - { - "id": "v37", - "opcode": "SaveState", - "type": "void", - "users": [ - "v39", - "v38" - ] - }, - { - "catchers": [ - 10 - ], - "id": "v39", - "inputs": [ - "v37" - ], - "opcode": "InitClass", - "type": "void" - }, - { - "catchers": [ - 10 - ], - "id": "v38", - "inputs": [ - "v27", - "v37" - ], - "method": "PermissionUtil.requestPermissionsFromUser:std.core.String[];u1;", - "opcode": "CallStatic", - "type": "u1", - "users": [ - "v40" - ] - }, - { - "id": "v40", - "inputs": [ - "v38", - "v41" - ], - "opcode": "Compare", - "operandsType": "i32", - "operator": "EQ", - "type": "u1", - "users": [ - "v42" - ] - }, - { - "id": "v42", - "immediate": 0, - "inputs": [ - "v40" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "insts": [ - { - "id": "v43", - "opcode": "SaveState", - "type": "void", - "users": [ - "v44" - ] - }, - { - "catchers": [ - 10 - ], - "id": "v44", - "inputs": [ - "v43" - ], - "loadedClass": "ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v45" - ] - }, - { - "catchers": [ - 10 - ], - "enclosingClass": "ETSGLOBAL", - "field": "settings", - "id": "v45", - "inputs": [ - "v44" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v52" - ] - }, - { - "id": "v46", - "opcode": "SaveState", - "type": "void", - "users": [ - "v47" - ] - }, - { - "id": "v47", - "inputs": [ - "v11", - "v46" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v48" - ] - }, - { - "catchers": [ - 10 - ], - "enclosingClass": "Setting", - "field": "context", - "id": "v48", - "inputs": [ - "v47" - ], - "opcode": "LoadObject", - "type": "ref", - "users": [ - "v53" - ] - }, - { - "id": "v50", - "opcode": "SaveState", - "type": "void", - "users": [ - "v49" - ] - }, - { - "catchers": [ - 10 - ], - "id": "v49", - "inputs": [ - "v50" - ], - "opcode": "LoadString", - "string": "message", - "type": "ref", - "users": [ - "v53" - ] - }, - { - "id": "v51", - "opcode": "SaveState", - "type": "void", - "users": [ - "v53", - "v52" - ] - }, - { - "id": "v52", - "inputs": [ - "v45", - "v51" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v53" - ] - }, - { - "catchers": [ - 10 - ], - "id": "v53", - "inputs": [ - "v52", - "v48", - "v49", - "v19", - "v51" - ], - "method": "Settings.setValue:Context;std.core.String;std.core.String;void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v54", - "opcode": "SaveState", - "type": "void", - "users": [ - "v55" - ] - }, - { - "catchers": [ - 10 - ], - "id": "v55", - "inputs": [ - "v54" - ], - "loadedClass": "ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v56" - ] - }, - { - "catchers": [ - 10 - ], - "enclosingClass": "ETSGLOBAL", - "field": "settings", - "id": "v56", - "inputs": [ - "v55" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "65p", - "v63" - ] - }, - { - "id": "v57", - "opcode": "SaveState", - "type": "void", - "users": [ - "v58" - ] - }, - { - "id": "v58", - "inputs": [ - "v11", - "v57" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v59" - ] - }, - { - "catchers": [ - 10 - ], - "enclosingClass": "Setting", - "field": "context", - "id": "v59", - "inputs": [ - "v58" - ], - "opcode": "LoadObject", - "type": "ref", - "users": [ - "66p", - "v64" - ] - }, - { - "id": "v61", - "opcode": "SaveState", - "type": "void", - "users": [ - "v60" - ] - }, - { - "catchers": [ - 10 - ], - "id": "v60", - "inputs": [ - "v61" - ], - "opcode": "LoadString", - "string": "password", - "type": "ref", - "users": [ - "v64" - ] - }, - { - "id": "v62", - "opcode": "SaveState", - "type": "void", - "users": [ - "v64", - "v63" - ] - }, - { - "id": "v63", - "inputs": [ - "v56", - "v62" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v64" - ] - }, - { - "catchers": [ - 10 - ], - "id": "v64", - "inputs": [ - "v63", - "v59", - "v60", - "v21", - "v62" - ], - "method": "Settings.setValue:Context;std.core.String;std.core.String;void;", - "opcode": "CallVirtual", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 6 - ], - "successors": [ - 1 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "65p", - "inputBlocks": [ - 6, - 2 - ], - "inputs": [ - "v27", - "v56" - ], - "opcode": "Phi", - "type": "ref" - }, - { - "id": "66p", - "inputBlocks": [ - 6, - 2 - ], - "inputs": [ - "v27", - "v59" - ], - "opcode": "Phi", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 6, - 2 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": true, - "predecessors": [ - 1 - ], - "successors": [ - 3, - 10 - ] - }, - { - "id": 10, - "isCatchBegin": true, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4, - 5 - ], - "successors": [ - 7 - ] - }, - { - "id": 7, - "insts": [ - { - "id": "v70", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 10 - ], - "successors": [ - 9 - ] - }, - { - "id": 3, - "insts": [ - { - "id": "v71", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 5 - ], - "successors": [ - 9 - ] - }, - { - "id": 9, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 7, - 3 - ] - } - ], - "name": "setData", - "returnType": "void", - "signature": "Setting.setData:void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v9", - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "SaveState", - "type": "void", - "users": [ - "v7", - "v6" - ] - }, - { - "id": "v7", - "inputs": [ - "v5" - ], - "opcode": "InitClass", - "type": "void" - }, - { - "id": "v6", - "inputs": [ - "v5" - ], - "method": "ETSGLOBAL.getContext:Context;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v10" - ] - }, - { - "id": "v8", - "opcode": "SaveState", - "type": "void", - "users": [ - "v9" - ] - }, - { - "id": "v9", - "inputs": [ - "v0", - "v8" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v10" - ] - }, - { - "enclosingClass": "Setting", - "field": "context", - "id": "v10", - "inputs": [ - "v9", - "v6" - ], - "opcode": "StoreObject", - "type": "ref" - }, - { - "id": "v11", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "Setting.:void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v5", - "opcode": "Constant", - "type": "i32", - "users": [ - "v69", - "v34", - "v7" - ], - "value": 1 - }, - { - "id": "v10", - "opcode": "Constant", - "type": "i32", - "users": [ - "v77", - "v56", - "v16" - ], - "value": 0 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v2" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v4", - "inputs": [ - "v3" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v20" - ] - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v9", - "v8", - "v7" - ] - }, - { - "id": "v8", - "inputs": [ - "v6" - ], - "loadedClass": "[Lstd/core/Object;", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v9" - ] - }, - { - "id": "v7", - "inputs": [ - "v5", - "v6" - ], - "opcode": "NegativeCheck", - "type": "i32", - "users": [ - "v9" - ] - }, - { - "arrayType": "std.core.Object[]", - "id": "v9", - "inputs": [ - "v8", - "v7", - "v6" - ], - "opcode": "NewArray", - "type": "ref", - "users": [ - "v21", - "v14" - ] - }, - { - "id": "v12", - "opcode": "SaveState", - "type": "void", - "users": [ - "v11" - ] - }, - { - "id": "v11", - "inputs": [ - "v12" - ], - "opcode": "LoadString", - "string": "Get SystemPasteboard", - "type": "ref", - "users": [ - "v18" - ] - }, - { - "id": "v13", - "opcode": "SaveState", - "type": "void", - "users": [ - "v18", - "v16", - "v14" - ] - }, - { - "id": "v14", - "inputs": [ - "v9", - "v13" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v17", - "v18", - "v15" - ] - }, - { - "id": "v15", - "inputs": [ - "v14" - ], - "opcode": "LenArray", - "type": "i32", - "users": [ - "v16" - ] - }, - { - "id": "v16", - "inputs": [ - "v15", - "v10", - "v13" - ], - "opcode": "BoundsCheck", - "type": "i32", - "users": [ - "v17" - ] - }, - { - "id": "v18", - "inputs": [ - "v14", - "v11", - "v13" - ], - "opcode": "RefTypeCheck", - "type": "ref", - "users": [ - "v17" - ] - }, - { - "id": "v17", - "inputs": [ - "v14", - "v16", - "v18" - ], - "opcode": "StoreArray", - "type": "ref" - }, - { - "id": "v19", - "opcode": "SaveState", - "type": "void", - "users": [ - "v21", - "v20" - ] - }, - { - "id": "v20", - "inputs": [ - "v4", - "v19" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v21" - ] - }, - { - "id": "v21", - "inputs": [ - "v20", - "v9", - "v19" - ], - "method": "std.core.Console.log:void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v22", - "opcode": "SaveState", - "type": "void", - "users": [ - "v24", - "v23" - ] - }, - { - "id": "v24", - "inputs": [ - "v22" - ], - "opcode": "InitClass", - "type": "void" - }, - { - "id": "v23", - "inputs": [ - "v22" - ], - "method": "ETSGLOBAL.getSystemPasteboard:Pasteboard;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v84", - "v26" - ] - }, - { - "id": "v25", - "opcode": "SaveState", - "type": "void", - "users": [ - "v27", - "v26" - ] - }, - { - "id": "v26", - "inputs": [ - "v23", - "v25" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v27" - ] - }, - { - "id": "v27", - "inputs": [ - "v26", - "v25" - ], - "method": "Pasteboard.clear:void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v29", - "opcode": "SaveState", - "type": "void", - "users": [ - "v28" - ] - }, - { - "id": "v28", - "inputs": [ - "v29" - ], - "opcode": "LoadString", - "string": "Password123", - "type": "ref", - "users": [ - "v63", - "v49" - ] - }, - { - "id": "v30", - "opcode": "SaveState", - "type": "void", - "users": [ - "v31" - ] - }, - { - "id": "v31", - "inputs": [ - "v30" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v32" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v32", - "inputs": [ - "v31" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v60" - ] - }, - { - "id": "v33", - "opcode": "SaveState", - "type": "void", - "users": [ - "v36", - "v35", - "v34" - ] - }, - { - "id": "v35", - "inputs": [ - "v33" - ], - "loadedClass": "[Lstd/core/Object;", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v36" - ] - }, - { - "id": "v34", - "inputs": [ - "v5", - "v33" - ], - "opcode": "NegativeCheck", - "type": "i32", - "users": [ - "v36" - ] - }, - { - "arrayType": "std.core.Object[]", - "id": "v36", - "inputs": [ - "v35", - "v34", - "v33" - ], - "opcode": "NewArray", - "type": "ref", - "users": [ - "v61", - "v54" - ] - }, - { - "id": "v37", - "opcode": "SaveState", - "type": "void", - "users": [ - "v39", - "v38" - ] - }, - { - "id": "v38", - "inputs": [ - "v37" - ], - "loadedClass": "std.core.StringBuilder", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v39" - ] - }, - { - "id": "v39", - "inputs": [ - "v38", - "v37" - ], - "objectClass": "std.core.StringBuilder", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v51", - "v48", - "v45", - "v40" - ] - }, - { - "id": "v41", - "opcode": "SaveState", - "type": "void", - "users": [ - "v40" - ] - }, - { - "id": "v40", - "inputs": [ - "v39", - "v41" - ], - "method": "std.core.StringBuilder.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v43", - "opcode": "SaveState", - "type": "void", - "users": [ - "v42" - ] - }, - { - "id": "v42", - "inputs": [ - "v43" - ], - "opcode": "LoadString", - "string": "createPlainTextData = ", - "type": "ref", - "users": [ - "v46" - ] - }, - { - "id": "v44", - "opcode": "SaveState", - "type": "void", - "users": [ - "v46", - "v45" - ] - }, - { - "id": "v45", - "inputs": [ - "v39", - "v44" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v46" - ] - }, - { - "id": "v46", - "inputs": [ - "v45", - "v42", - "v44" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v47", - "opcode": "SaveState", - "type": "void", - "users": [ - "v49", - "v48" - ] - }, - { - "id": "v48", - "inputs": [ - "v39", - "v47" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v49" - ] - }, - { - "id": "v49", - "inputs": [ - "v48", - "v28", - "v47" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v50", - "opcode": "SaveState", - "type": "void", - "users": [ - "v52", - "v51" - ] - }, - { - "id": "v51", - "inputs": [ - "v39", - "v50" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v52" - ] - }, - { - "id": "v52", - "inputs": [ - "v51", - "v50" - ], - "method": "std.core.StringBuilder.toString:std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v58" - ] - }, - { - "id": "v53", - "opcode": "SaveState", - "type": "void", - "users": [ - "v58", - "v56", - "v54" - ] - }, - { - "id": "v54", - "inputs": [ - "v36", - "v53" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v57", - "v58", - "v55" - ] - }, - { - "id": "v55", - "inputs": [ - "v54" - ], - "opcode": "LenArray", - "type": "i32", - "users": [ - "v56" - ] - }, - { - "id": "v56", - "inputs": [ - "v55", - "v10", - "v53" - ], - "opcode": "BoundsCheck", - "type": "i32", - "users": [ - "v57" - ] - }, - { - "id": "v58", - "inputs": [ - "v54", - "v52", - "v53" - ], - "opcode": "RefTypeCheck", - "type": "ref", - "users": [ - "v57" - ] - }, - { - "id": "v57", - "inputs": [ - "v54", - "v56", - "v58" - ], - "opcode": "StoreArray", - "type": "ref" - }, - { - "id": "v59", - "opcode": "SaveState", - "type": "void", - "users": [ - "v61", - "v60" - ] - }, - { - "id": "v60", - "inputs": [ - "v32", - "v59" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v61" - ] - }, - { - "id": "v61", - "inputs": [ - "v60", - "v36", - "v59" - ], - "method": "std.core.Console.log:void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v62", - "opcode": "SaveState", - "type": "void", - "users": [ - "v64", - "v63" - ] - }, - { - "id": "v64", - "inputs": [ - "v62" - ], - "opcode": "InitClass", - "type": "void" - }, - { - "id": "v63", - "inputs": [ - "v28", - "v62" - ], - "method": "ETSGLOBAL.createPlainTextData:std.core.String;std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v85" - ] - }, - { - "id": "v65", - "opcode": "SaveState", - "type": "void", - "users": [ - "v66" - ] - }, - { - "id": "v66", - "inputs": [ - "v65" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v67" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v67", - "inputs": [ - "v66" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v81" - ] - }, - { - "id": "v68", - "opcode": "SaveState", - "type": "void", - "users": [ - "v71", - "v70", - "v69" - ] - }, - { - "id": "v70", - "inputs": [ - "v68" - ], - "loadedClass": "[Lstd/core/Object;", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v71" - ] - }, - { - "id": "v69", - "inputs": [ - "v5", - "v68" - ], - "opcode": "NegativeCheck", - "type": "i32", - "users": [ - "v71" - ] - }, - { - "arrayType": "std.core.Object[]", - "id": "v71", - "inputs": [ - "v70", - "v69", - "v68" - ], - "opcode": "NewArray", - "type": "ref", - "users": [ - "v82", - "v75" - ] - }, - { - "id": "v73", - "opcode": "SaveState", - "type": "void", - "users": [ - "v72" - ] - }, - { - "id": "v72", - "inputs": [ - "v73" - ], - "opcode": "LoadString", - "string": "Writes PasteData to the pasteboard", - "type": "ref", - "users": [ - "v79" - ] - }, - { - "id": "v74", - "opcode": "SaveState", - "type": "void", - "users": [ - "v79", - "v77", - "v75" - ] - }, - { - "id": "v75", - "inputs": [ - "v71", - "v74" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v78", - "v79", - "v76" - ] - }, - { - "id": "v76", - "inputs": [ - "v75" - ], - "opcode": "LenArray", - "type": "i32", - "users": [ - "v77" - ] - }, - { - "id": "v77", - "inputs": [ - "v76", - "v10", - "v74" - ], - "opcode": "BoundsCheck", - "type": "i32", - "users": [ - "v78" - ] - }, - { - "id": "v79", - "inputs": [ - "v75", - "v72", - "v74" - ], - "opcode": "RefTypeCheck", - "type": "ref", - "users": [ - "v78" - ] - }, - { - "id": "v78", - "inputs": [ - "v75", - "v77", - "v79" - ], - "opcode": "StoreArray", - "type": "ref" - }, - { - "id": "v80", - "opcode": "SaveState", - "type": "void", - "users": [ - "v82", - "v81" - ] - }, - { - "id": "v81", - "inputs": [ - "v67", - "v80" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v82" - ] - }, - { - "id": "v82", - "inputs": [ - "v81", - "v71", - "v80" - ], - "method": "std.core.Console.log:void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v83", - "opcode": "SaveState", - "type": "void", - "users": [ - "v85", - "v84" - ] - }, - { - "id": "v84", - "inputs": [ - "v23", - "v83" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v85" - ] - }, - { - "id": "v85", - "inputs": [ - "v84", - "v63", - "v83" - ], - "method": "Pasteboard.setPasteData:std.core.String;void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v86", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "pasteboard", - "returnType": "void", - "signature": "Setting.pasteboard:void;" - } - ], - "name": "Setting", - "simpleName": "Setting", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function14", - "simpleName": "Function14" - }, - { - "accessFlags": 1537, - "name": "std.core.Function13", - "simpleName": "Function13" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i32[][].:i32[][];i32;i32;void;" - } - ], - "name": "i32[][]", - "simpleName": "i32[][]" - }, - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 9, - "name": "settings", - "type": "Settings" - }, - { - "accessFlags": 9, - "name": "abilityAccessCtrl", - "type": "AbilityAccessCtrl" - }, - { - "accessFlags": 9, - "name": "abilityAccessCtrl", - "type": "AbilityAccessCtrl" - }, - { - "accessFlags": 9, - "name": "settings", - "type": "Settings" - } - ], - "methods": [ - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ] - } - ], - "name": "getContext", - "returnType": "Context", - "signature": "ETSGLOBAL.getContext:Context;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "SaveState", - "type": "void", - "users": [ - "v3", - "v2" - ] - }, - { - "id": "v2", - "inputs": [ - "v1" - ], - "loadedClass": "AbilityAccessCtrl", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v2", - "v1" - ], - "objectClass": "AbilityAccessCtrl", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v8", - "v4" - ] - }, - { - "id": "v5", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v5" - ], - "method": "AbilityAccessCtrl.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v7" - ] - }, - { - "id": "v7", - "inputs": [ - "v6" - ], - "loadedClass": "ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v8" - ] - }, - { - "enclosingClass": "ETSGLOBAL", - "field": "abilityAccessCtrl", - "id": "v8", - "inputs": [ - "v7", - "v3" - ], - "opcode": "StoreStatic", - "type": "ref" - }, - { - "id": "v9", - "opcode": "SaveState", - "type": "void", - "users": [ - "v11", - "v10" - ] - }, - { - "id": "v10", - "inputs": [ - "v9" - ], - "loadedClass": "Settings", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v11" - ] - }, - { - "id": "v11", - "inputs": [ - "v10", - "v9" - ], - "objectClass": "Settings", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v16", - "v12" - ] - }, - { - "id": "v13", - "opcode": "SaveState", - "type": "void", - "users": [ - "v12" - ] - }, - { - "id": "v12", - "inputs": [ - "v11", - "v13" - ], - "method": "Settings.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v14", - "opcode": "SaveState", - "type": "void", - "users": [ - "v15" - ] - }, - { - "id": "v15", - "inputs": [ - "v14" - ], - "loadedClass": "ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v16" - ] - }, - { - "enclosingClass": "ETSGLOBAL", - "field": "settings", - "id": "v16", - "inputs": [ - "v15", - "v11" - ], - "opcode": "StoreStatic", - "type": "ref" - }, - { - "id": "v17", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "_$init$_", - "returnType": "void", - "signature": "ETSGLOBAL._$init$_:void;" - }, - { - "accessFlags": 8, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "SaveState", - "type": "void", - "users": [ - "v2" - ] - }, - { - "id": "v2", - "inputs": [ - "v1" - ], - "method": "ETSGLOBAL._$init$_:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v3", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "ETSGLOBAL.:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v2" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "inputs": [ - "v0" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "createPlainTextData", - "parameters": [ - "std.core.String" - ], - "returnType": "std.core.String", - "signature": "ETSGLOBAL.createPlainTextData:std.core.String;std.core.String;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "SaveState", - "type": "void", - "users": [ - "v3", - "v2" - ] - }, - { - "id": "v2", - "inputs": [ - "v1" - ], - "loadedClass": "Pasteboard", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v2", - "v1" - ], - "objectClass": "Pasteboard", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v6", - "v4" - ] - }, - { - "id": "v5", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v5" - ], - "method": "Pasteboard.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v6", - "inputs": [ - "v3" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "getSystemPasteboard", - "returnType": "Pasteboard", - "signature": "ETSGLOBAL.getSystemPasteboard:Pasteboard;" - } - ], - "name": "ETSGLOBAL", - "simpleName": "ETSGLOBAL", - "superClass": "std.core.Object" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "u16[].:u16[];i32;void;" - } - ], - "name": "u16[]", - "simpleName": "u16[]" - }, - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "OBJECT_HAS_OWN_PROPERTY_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "KEY_NOT_FOUND", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "ARRAY_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_LOCALE_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_NAME_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "MAX_CONSOLE_PRINT_DEPTH", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "runtime", - "type": "std.core.Runtime" - }, - { - "accessFlags": 0, - "name": "console", - "type": "std.core.Console" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_UNIT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "TypeKindMask", - "type": "i8" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_POINT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "ObjectTD", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "coroutine", - "type": "std.core.Coroutine" - }, - { - "accessFlags": 0, - "name": "ObjectType", - "type": "std.core.ClassType" - } - ], - "name": "std.core.ETSGLOBAL", - "simpleName": "ETSGLOBAL" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i64[][].:i64[][];i32;i32;void;" - } - ], - "name": "i64[][]", - "simpleName": "i64[][]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "f64[].:f64[];i32;void;" - } - ], - "name": "f64[]", - "simpleName": "f64[]" - }, - { - "accessFlags": 1, - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "AbilityAccessCtrl.:void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v2" - ], - "loadedClass": "AtManager", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "objectClass": "AtManager", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v7", - "v5" - ] - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v5" - ] - }, - { - "id": "v5", - "inputs": [ - "v4", - "v6" - ], - "method": "AtManager.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v7", - "inputs": [ - "v4" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "createAtManager", - "returnType": "AtManager", - "signature": "AbilityAccessCtrl.createAtManager:AtManager;" - } - ], - "name": "AbilityAccessCtrl", - "simpleName": "AbilityAccessCtrl", - "superClass": "std.core.Object" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i16[][].:i16[][];i32;i32;void;" - } - ], - "name": "i16[][]", - "simpleName": "i16[][]" - }, - { - "accessFlags": 1, - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v2", - "index": 2, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v3", - "index": 3, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v4", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "setValue", - "parameters": [ - "Context", - "std.core.String", - "std.core.String" - ], - "returnType": "void", - "signature": "Settings.setValue:Context;std.core.String;std.core.String;void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v2", - "index": 2, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v3", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v5", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v5" - ], - "opcode": "LoadString", - "string": "", - "type": "ref", - "users": [ - "v6" - ] - }, - { - "id": "v6", - "inputs": [ - "v4" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "getValue", - "parameters": [ - "Context", - "std.core.String" - ], - "returnType": "std.core.String", - "signature": "Settings.getValue:Context;std.core.String;std.core.String;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "Settings.:void;" - } - ], - "name": "Settings", - "simpleName": "Settings", - "superClass": "std.core.Object" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "i8[].:i8[];i32;void;" - } - ], - "name": "i8[]", - "simpleName": "i8[]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function9", - "simpleName": "Function9" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "f32[].:f32[];i32;void;" - } - ], - "name": "f32[]", - "simpleName": "f32[]" - }, - { - "accessFlags": 0, - "methods": [ - { - "accessFlags": 0, - "name": "", - "parameters": [ - "i32", - "i32" - ], - "returnType": "void", - "signature": "i8[][].:i8[][];i32;i32;void;" - } - ], - "name": "i8[][]", - "simpleName": "i8[][]" - }, - { - "accessFlags": 1537, - "name": "std.core.Function8", - "simpleName": "Function8" - }, - { - "accessFlags": 1, - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "PermissionUtil.:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v2", - "opcode": "Constant", - "type": "i32", - "users": [ - "v3" - ], - "value": 1 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "inputs": [ - "v2" - ], - "opcode": "Return", - "type": "u1" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "requestPermissionsFromUser", - "parameters": [ - "std.core.String[]" - ], - "returnType": "u1", - "signature": "PermissionUtil.requestPermissionsFromUser:std.core.String[];u1;" - } - ], - "name": "PermissionUtil", - "simpleName": "PermissionUtil", - "superClass": "std.core.Object" - } - ] -} \ No newline at end of file diff --git a/jacodb-panda-static/src/test/resources/sample.abc.ir b/jacodb-panda-static/src/test/resources/sample.abc.ir deleted file mode 100644 index 5530b9a04..000000000 --- a/jacodb-panda-static/src/test/resources/sample.abc.ir +++ /dev/null @@ -1,4788 +0,0 @@ -{ - "classes": [ - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "attrs", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "td", - "type": "std.core.String" - } - ], - "name": "std.core.FunctionType", - "simpleName": "FunctionType" - }, - { - "accessFlags": 1537, - "name": "std.core.Function10", - "simpleName": "Function10" - }, - { - "accessFlags": 1537, - "name": "std.core.Function0", - "simpleName": "Function0" - }, - { - "accessFlags": 1537, - "name": "std.core.Function3", - "simpleName": "Function3" - }, - { - "accessFlags": 1537, - "name": "std.core.Function7", - "simpleName": "Function7" - }, - { - "accessFlags": 1537, - "name": "std.core.Function", - "simpleName": "Function" - }, - { - "accessFlags": 1537, - "name": "std.core.Function14", - "simpleName": "Function14" - }, - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "KEY_NOT_FOUND", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "OBJECT_HAS_OWN_PROPERTY_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "ARRAY_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "MAX_CONSOLE_PRINT_DEPTH", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_LOCALE_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "ObjectTD", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_NAME_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "coroutine", - "type": "std.core.Coroutine" - }, - { - "accessFlags": 0, - "name": "console", - "type": "std.core.Console" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_POINT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_UNIT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "runtime", - "type": "std.core.Runtime" - }, - { - "accessFlags": 0, - "name": "TypeKindMask", - "type": "i8" - }, - { - "accessFlags": 0, - "name": "ObjectType", - "type": "std.core.ClassType" - } - ], - "name": "std.core.ETSGLOBAL", - "simpleName": "ETSGLOBAL" - }, - { - "accessFlags": 1537, - "name": "std.core.Function8", - "simpleName": "Function8" - }, - { - "accessFlags": 1537, - "name": "std.core.Function2", - "simpleName": "Function2" - }, - { - "accessFlags": 1537, - "name": "std.core.Function6", - "simpleName": "Function6" - }, - { - "accessFlags": 1, - "fields": [ - { - "accessFlags": 1, - "name": "kek", - "type": "i32" - }, - { - "accessFlags": 1, - "name": "kek", - "type": "i32" - } - ], - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "ABVGDEJOZH.:void;" - } - ], - "name": "ABVGDEJOZH", - "simpleName": "ABVGDEJOZH", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function16", - "simpleName": "Function16" - }, - { - "accessFlags": 1537, - "name": "std.core.Function4", - "simpleName": "Function4" - }, - { - "accessFlags": 1537, - "name": "std.core.Function13", - "simpleName": "Function13" - }, - { - "accessFlags": 1537, - "name": "std.core.Function1", - "simpleName": "Function1" - }, - { - "accessFlags": 1025, - "methods": [ - { - "accessFlags": 1025, - "name": "greet", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "A0.greet:i32;void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "A0.:void;" - } - ], - "name": "A0", - "simpleName": "A0", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.FunctionN", - "simpleName": "FunctionN" - }, - { - "accessFlags": 1537, - "name": "std.core.Function15", - "simpleName": "Function15" - }, - { - "accessFlags": 1537, - "name": "std.core.Function12", - "simpleName": "Function12" - }, - { - "accessFlags": 1537, - "name": "std.core.Function5", - "simpleName": "Function5" - }, - { - "accessFlags": 1, - "fields": [ - { - "accessFlags": 1, - "name": "t", - "type": "std.core.Object" - }, - { - "accessFlags": 1, - "name": "t", - "type": "std.core.Object" - } - ], - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v7", - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v5", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v8" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "std.core.Object.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v7" - ] - }, - { - "id": "v7", - "inputs": [ - "v0", - "v6" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v8" - ] - }, - { - "enclosingClass": "P", - "field": "t", - "id": "v8", - "inputs": [ - "v7", - "v5" - ], - "opcode": "StoreObject", - "type": "ref" - }, - { - "id": "v9", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "P.:void;" - } - ], - "name": "P", - "simpleName": "P", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1, - "fields": [ - { - "accessFlags": 0, - "name": "a", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "b", - "type": "std.core.String" - }, - { - "accessFlags": 1, - "name": "c", - "type": "std.core.String" - }, - { - "accessFlags": 1, - "name": "c", - "type": "std.core.String" - } - ], - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v7", - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v5", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v8" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "A.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v7" - ] - }, - { - "id": "v7", - "inputs": [ - "v0", - "v6" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v8" - ] - }, - { - "enclosingClass": "A1", - "field": "c", - "id": "v8", - "inputs": [ - "v7", - "v5" - ], - "opcode": "StoreObject", - "type": "ref" - }, - { - "id": "v9", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "A1.:void;" - } - ], - "name": "A1", - "simpleName": "A1", - "superClass": "A" - }, - { - "accessFlags": 1537, - "name": "I2", - "simpleName": "I2", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function11", - "simpleName": "Function11" - }, - { - "accessFlags": 1537, - "name": "std.core.Function9", - "simpleName": "Function9" - }, - { - "accessFlags": 1025, - "methods": [ - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "i32", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "i32", - "users": [ - "v3" - ] - }, - { - "id": "v2", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "inputs": [ - "v0", - "v1" - ], - "opcode": "Add", - "type": "i32", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3" - ], - "opcode": "Return", - "type": "i32" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "aplusb", - "parameters": [ - "i32", - "i32" - ], - "returnType": "i32", - "signature": "ETSGLOBAL.aplusb:i32;i32;i32;" - }, - { - "accessFlags": 8, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "ETSGLOBAL.:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "_$init$_", - "returnType": "void", - "signature": "ETSGLOBAL._$init$_:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 4, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "i32", - "users": [ - "v7", - "v6", - "v4" - ] - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "i32", - "users": [ - "v7" - ] - }, - { - "id": "v2", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v3", - "opcode": "Constant", - "type": "i32", - "users": [ - "v4" - ], - "value": 0 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v4", - "inputs": [ - "v3", - "v0" - ], - "opcode": "Compare", - "operandsType": "i32", - "operator": "NE", - "type": "u1", - "users": [ - "v5" - ] - }, - { - "id": "v5", - "immediate": 0, - "inputs": [ - "v4" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "insts": [ - { - "id": "v6", - "inputs": [ - "v0" - ], - "opcode": "Return", - "type": "i32" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 5 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v7", - "inputs": [ - "v0", - "v1" - ], - "opcode": "Mul", - "type": "i32", - "users": [ - "v8" - ] - }, - { - "id": "v8", - "inputs": [ - "v7" - ], - "opcode": "Return", - "type": "i32" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2, - 1 - ] - } - ], - "name": "aorb", - "parameters": [ - "i32", - "i32" - ], - "returnType": "i32", - "signature": "ETSGLOBAL.aorb:i32;i32;i32;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 6, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v1", - "opcode": "Constant", - "type": "i32", - "users": [ - "10p" - ], - "value": 353 - }, - { - "id": "v2", - "opcode": "Constant", - "type": "i32", - "users": [ - "v26", - "v5" - ], - "value": 2 - }, - { - "id": "v3", - "opcode": "Constant", - "type": "i32", - "users": [ - "v26", - "v5" - ], - "value": 3 - }, - { - "id": "v6", - "opcode": "Constant", - "type": "i32", - "users": [ - "18p", - "v44", - "v7" - ], - "value": 0 - }, - { - "id": "v9", - "opcode": "Constant", - "type": "i32", - "users": [ - "10p" - ], - "value": 11 - }, - { - "id": "v15", - "opcode": "Constant", - "type": "i32", - "users": [ - "18p", - "v44", - "v16" - ], - "value": 1 - }, - { - "id": "v35", - "opcode": "Constant", - "type": "i32", - "users": [ - "v38" - ], - "value": 42 - }, - { - "id": "v39", - "opcode": "Constant", - "type": "i32", - "users": [ - "v42" - ], - "value": 5 - }, - { - "id": "v45", - "opcode": "Constant", - "type": "i32", - "users": [ - "v49" - ], - "value": 4 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v4", - "opcode": "SaveState", - "type": "void", - "users": [ - "v5" - ] - }, - { - "id": "v5", - "inputs": [ - "v2", - "v3", - "v4" - ], - "method": "ETSGLOBAL.aplusb:i32;i32;i32;", - "opcode": "CallStatic", - "type": "i32", - "users": [ - "v7" - ] - }, - { - "id": "v7", - "inputs": [ - "v6", - "v5" - ], - "opcode": "Compare", - "operandsType": "i32", - "operator": "LE", - "type": "u1", - "users": [ - "v8" - ] - }, - { - "id": "v8", - "immediate": 0, - "inputs": [ - "v7" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 6 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 1 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "10p", - "inputBlocks": [ - 0, - 2 - ], - "inputs": [ - "v1", - "v9" - ], - "opcode": "Phi", - "type": "i32", - "users": [ - "v16" - ] - }, - { - "id": "v12", - "opcode": "SaveState", - "type": "void", - "users": [ - "v13" - ] - }, - { - "id": "v13", - "inputs": [ - "v12" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v14" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v14", - "inputs": [ - "v13" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v20" - ] - }, - { - "id": "v16", - "inputs": [ - "v15", - "10p" - ], - "opcode": "Compare", - "operandsType": "i32", - "operator": "NE", - "type": "u1", - "users": [ - "v17" - ] - }, - { - "id": "v17", - "immediate": 0, - "inputs": [ - "v16" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0, - 2 - ], - "successors": [ - 3, - 4 - ] - }, - { - "id": 4, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 5 - ] - }, - { - "id": 3, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "insts": [ - { - "id": "18p", - "inputBlocks": [ - 4, - 3 - ], - "inputs": [ - "v15", - "v6" - ], - "opcode": "Phi", - "type": "u1", - "users": [ - "v21" - ] - }, - { - "id": "v19", - "opcode": "SaveState", - "type": "void", - "users": [ - "v21", - "v20" - ] - }, - { - "id": "v20", - "inputs": [ - "v14", - "v19" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v21" - ] - }, - { - "id": "v21", - "inputs": [ - "v20", - "18p", - "v19" - ], - "method": "std.core.Console.print:u1;void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v22", - "opcode": "SaveState", - "type": "void", - "users": [ - "v23" - ] - }, - { - "id": "v23", - "inputs": [ - "v22" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v24" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v24", - "inputs": [ - "v23" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v28" - ] - }, - { - "id": "v25", - "opcode": "SaveState", - "type": "void", - "users": [ - "v26" - ] - }, - { - "id": "v26", - "inputs": [ - "v2", - "v3", - "v25" - ], - "method": "ETSGLOBAL.aplusb:i32;i32;i32;", - "opcode": "CallStatic", - "type": "i32", - "users": [ - "v29" - ] - }, - { - "id": "v27", - "opcode": "SaveState", - "type": "void", - "users": [ - "v29", - "v28" - ] - }, - { - "id": "v28", - "inputs": [ - "v24", - "v27" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v29" - ] - }, - { - "id": "v29", - "inputs": [ - "v28", - "v26", - "v27" - ], - "method": "std.core.Console.print:i32;void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v30", - "opcode": "SaveState", - "type": "void", - "users": [ - "v32", - "v31" - ] - }, - { - "id": "v31", - "inputs": [ - "v30" - ], - "loadedClass": "A", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v32" - ] - }, - { - "id": "v32", - "inputs": [ - "v31", - "v30" - ], - "objectClass": "A", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v56", - "v41", - "v37", - "v33" - ] - }, - { - "id": "v34", - "opcode": "SaveState", - "type": "void", - "users": [ - "v33" - ] - }, - { - "id": "v33", - "inputs": [ - "v32", - "v34" - ], - "method": "A.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v36", - "opcode": "SaveState", - "type": "void", - "users": [ - "v38", - "v37" - ] - }, - { - "id": "v37", - "inputs": [ - "v32", - "v36" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v38" - ] - }, - { - "id": "v38", - "inputs": [ - "v37", - "v35", - "v36" - ], - "method": "A.greet:i32;void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v40", - "opcode": "SaveState", - "type": "void", - "users": [ - "v42", - "v41" - ] - }, - { - "id": "v41", - "inputs": [ - "v32", - "v40" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v42" - ] - }, - { - "id": "v42", - "inputs": [ - "v41", - "v39", - "v40" - ], - "method": "A.foo:i32;i32;", - "opcode": "CallVirtual", - "type": "i32" - }, - { - "id": "v43", - "opcode": "SaveState", - "type": "void", - "users": [ - "v44" - ] - }, - { - "id": "v44", - "inputs": [ - "v15", - "v6", - "v43" - ], - "method": "ETSGLOBAL.aorb:i32;i32;i32;", - "opcode": "CallStatic", - "type": "i32" - }, - { - "id": "v46", - "opcode": "SaveState", - "type": "void", - "users": [ - "v48", - "v47" - ] - }, - { - "id": "v47", - "inputs": [ - "v46" - ], - "loadedClass": "B", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v48" - ] - }, - { - "id": "v48", - "inputs": [ - "v47", - "v46" - ], - "objectClass": "B", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v55", - "v49" - ] - }, - { - "id": "v50", - "opcode": "SaveState", - "type": "void", - "users": [ - "v49" - ] - }, - { - "id": "v49", - "inputs": [ - "v48", - "v45", - "v50" - ], - "method": "B.:i32;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v51", - "opcode": "SaveState", - "type": "void", - "users": [ - "v52" - ] - }, - { - "id": "v52", - "inputs": [ - "v51" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v53" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v53", - "inputs": [ - "v52" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v58" - ] - }, - { - "id": "v54", - "opcode": "SaveState", - "type": "void", - "users": [ - "v56", - "v55" - ] - }, - { - "id": "v55", - "inputs": [ - "v48", - "v54" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v56" - ] - }, - { - "id": "v56", - "inputs": [ - "v55", - "v32", - "v54" - ], - "method": "B.transform:I1;i32;", - "opcode": "CallVirtual", - "type": "i32", - "users": [ - "v59" - ] - }, - { - "id": "v57", - "opcode": "SaveState", - "type": "void", - "users": [ - "v59", - "v58" - ] - }, - { - "id": "v58", - "inputs": [ - "v53", - "v57" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v59" - ] - }, - { - "id": "v59", - "inputs": [ - "v58", - "v56", - "v57" - ], - "method": "std.core.Console.print:i32;void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v60", - "opcode": "SaveState", - "type": "void", - "users": [ - "v62", - "v61" - ] - }, - { - "id": "v61", - "inputs": [ - "v60" - ], - "loadedClass": "P", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v62" - ] - }, - { - "id": "v62", - "inputs": [ - "v61", - "v60" - ], - "objectClass": "P", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v63" - ] - }, - { - "id": "v64", - "opcode": "SaveState", - "type": "void", - "users": [ - "v63" - ] - }, - { - "id": "v63", - "inputs": [ - "v62", - "v64" - ], - "method": "P.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v65", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4, - 3 - ], - "successors": [ - 7 - ] - }, - { - "id": 7, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 5 - ] - } - ], - "name": "main", - "returnType": "void", - "signature": "ETSGLOBAL.main:void;" - } - ], - "name": "ETSGLOBAL", - "simpleName": "ETSGLOBAL", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1, - "fields": [ - { - "accessFlags": 0, - "name": "kek", - "type": "i32" - } - ], - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v7" - ] - }, - { - "id": "v2", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v0", - "v3" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v5" - ] - }, - { - "enclosingClass": "B", - "field": "kek", - "id": "v5", - "inputs": [ - "v4" - ], - "opcode": "LoadObject", - "type": "i32", - "users": [ - "v8" - ] - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v8", - "v7" - ] - }, - { - "id": "v7", - "inputs": [ - "v1", - "v6" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v8" - ] - }, - { - "id": "v8", - "inputs": [ - "v7", - "v5", - "v6" - ], - "method": "I1.foo:i32;i32;", - "opcode": "CallVirtual", - "type": "i32", - "users": [ - "v9" - ] - }, - { - "id": "v9", - "inputs": [ - "v8" - ], - "opcode": "Return", - "type": "i32" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "transform", - "parameters": [ - "I1" - ], - "returnType": "i32", - "signature": "B.transform:I1;i32;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v7", - "v4" - ] - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "i32", - "users": [ - "v8" - ] - }, - { - "id": "v2", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "opcode": "SaveState", - "type": "void", - "users": [ - "v5", - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v0", - "v3" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v5" - ] - }, - { - "id": "v5", - "inputs": [ - "v4", - "v3" - ], - "method": "ABVGDEJOZH.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v7" - ] - }, - { - "id": "v7", - "inputs": [ - "v0", - "v6" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v8" - ] - }, - { - "enclosingClass": "B", - "field": "kek", - "id": "v8", - "inputs": [ - "v7", - "v1" - ], - "opcode": "StoreObject", - "type": "i32" - }, - { - "id": "v9", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "B.:i32;void;" - } - ], - "name": "B", - "simpleName": "B", - "superClass": "ABVGDEJOZH" - }, - { - "accessFlags": 1537, - "methods": [ - { - "accessFlags": 1025, - "name": "foo", - "parameters": [ - "i32" - ], - "returnType": "i32", - "signature": "I1.foo:i32;i32;" - } - ], - "name": "I1", - "simpleName": "I1", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1, - "fields": [ - { - "accessFlags": 1, - "name": "a", - "type": "i32" - }, - { - "accessFlags": 1, - "name": "b", - "type": "std.core.String" - }, - { - "accessFlags": 1, - "name": "a", - "type": "i32" - }, - { - "accessFlags": 1, - "name": "b", - "type": "std.core.String" - } - ], - "interfaces": [ - "I1", - "I2" - ], - "methods": [ - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 15, - "insts": [ - { - "id": "v26", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v11", - "v47", - "v33" - ] - }, - { - "id": "v27", - "index": 1, - "opcode": "Parameter", - "type": "i32", - "users": [ - "v61", - "v54", - "v36", - "v30" - ] - }, - { - "id": "v28", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v29", - "opcode": "Constant", - "type": "i32", - "users": [ - "71p", - "v158", - "v120", - "v114", - "v92", - "v2", - "v2", - "v2", - "v2", - "v61", - "v2", - "v2", - "v30" - ], - "value": 0 - }, - { - "id": "v82", - "opcode": "Constant", - "type": "i32", - "users": [ - "v150", - "v106", - "v102", - "v84" - ], - "value": 1 - }, - { - "id": "v173", - "opcode": "Constant", - "type": "i32", - "users": [ - "v2", - "v2", - "v2", - "v2", - "v2" - ], - "value": 5 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 15 - ], - "successors": [ - 10 - ] - }, - { - "handledTypes": [ - "finally" - ], - "handlerIds": [ - 18 - ], - "id": 10, - "insts": [ - { - "id": "v0", - "opcode": "Try", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": true, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 8, - 18 - ] - }, - { - "handledTypes": [ - "std.core.Object" - ], - "handlerIds": [ - 17 - ], - "id": 8, - "insts": [ - { - "id": "v1", - "opcode": "Try", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": true, - "isTryEnd": false, - "predecessors": [ - 10 - ], - "successors": [ - 12, - 17 - ] - }, - { - "id": 12, - "insts": [ - { - "id": "v30", - "inputs": [ - "v29", - "v27" - ], - "opcode": "Compare", - "operandsType": "i32", - "operator": "GE", - "type": "u1", - "users": [ - "v31" - ] - }, - { - "id": "v31", - "immediate": 0, - "inputs": [ - "v30" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 8 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "insts": [ - { - "id": "v32", - "opcode": "SaveState", - "type": "void", - "users": [ - "v33" - ] - }, - { - "id": "v33", - "inputs": [ - "v26", - "v32" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v34" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "enclosingClass": "A", - "field": "a", - "id": "v34", - "inputs": [ - "v33" - ], - "opcode": "LoadObject", - "type": "i32", - "users": [ - "v37" - ] - }, - { - "id": "v35", - "opcode": "SaveState", - "type": "void", - "users": [ - "v36" - ] - }, - { - "id": "v36", - "inputs": [ - "v27", - "v35" - ], - "opcode": "ZeroCheck", - "type": "i32", - "users": [ - "v37" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v37", - "inputs": [ - "v34", - "v36" - ], - "opcode": "Div", - "type": "i32", - "users": [ - "71p", - "v2", - "v2", - "v2", - "v2", - "v2", - "v2", - "v2", - "v2", - "v2", - "v2" - ] - }, - { - "id": "v38", - "opcode": "SaveState", - "type": "void", - "users": [ - "v39" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v39", - "inputs": [ - "v38" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v40" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v40", - "inputs": [ - "v39" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "72p", - "v59" - ] - }, - { - "id": "v41", - "opcode": "SaveState", - "type": "void", - "users": [ - "v43", - "v42" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v42", - "inputs": [ - "v41" - ], - "loadedClass": "std.core.StringBuilder", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v43" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v43", - "inputs": [ - "v42", - "v41" - ], - "objectClass": "std.core.StringBuilder", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v56", - "v53", - "v50", - "v44" - ] - }, - { - "id": "v45", - "opcode": "SaveState", - "type": "void", - "users": [ - "v44" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v44", - "inputs": [ - "v43", - "v45" - ], - "method": "std.core.StringBuilder.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v46", - "opcode": "SaveState", - "type": "void", - "users": [ - "v47" - ] - }, - { - "id": "v47", - "inputs": [ - "v26", - "v46" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v48" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "enclosingClass": "A", - "field": "b", - "id": "v48", - "inputs": [ - "v47" - ], - "opcode": "LoadObject", - "type": "ref", - "users": [ - "v51" - ] - }, - { - "id": "v49", - "opcode": "SaveState", - "type": "void", - "users": [ - "v51", - "v50" - ] - }, - { - "id": "v50", - "inputs": [ - "v43", - "v49" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v51" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v51", - "inputs": [ - "v50", - "v48", - "v49" - ], - "method": "std.core.StringBuilder.append:std.core.String;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v52", - "opcode": "SaveState", - "type": "void", - "users": [ - "v54", - "v53" - ] - }, - { - "id": "v53", - "inputs": [ - "v43", - "v52" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v54" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v54", - "inputs": [ - "v53", - "v27", - "v52" - ], - "method": "std.core.StringBuilder.append:i32;std.core.StringBuilder;", - "opcode": "CallStatic", - "type": "ref" - }, - { - "id": "v55", - "opcode": "SaveState", - "type": "void", - "users": [ - "v57", - "v56" - ] - }, - { - "id": "v56", - "inputs": [ - "v43", - "v55" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v57" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v57", - "inputs": [ - "v56", - "v55" - ], - "method": "std.core.StringBuilder.toString:std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "73p", - "v60" - ] - }, - { - "id": "v58", - "opcode": "SaveState", - "type": "void", - "users": [ - "v60", - "v59" - ] - }, - { - "id": "v59", - "inputs": [ - "v40", - "v58" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v60" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v60", - "inputs": [ - "v59", - "v57", - "v58" - ], - "method": "std.core.Console.print:std.core.String;void;", - "opcode": "CallVirtual", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 12 - ], - "successors": [ - 3 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v61", - "inputs": [ - "v29", - "v27" - ], - "opcode": "Compare", - "operandsType": "i32", - "operator": "LE", - "type": "u1", - "users": [ - "v62" - ] - }, - { - "id": "v62", - "immediate": 0, - "inputs": [ - "v61" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 12 - ], - "successors": [ - 4, - 5 - ] - }, - { - "id": 5, - "insts": [ - { - "id": "v63", - "opcode": "SaveState", - "type": "void", - "users": [ - "v64" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v64", - "inputs": [ - "v63" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v65" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v65", - "inputs": [ - "v64" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "72p", - "v69" - ] - }, - { - "id": "v67", - "opcode": "SaveState", - "type": "void", - "users": [ - "v66" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v66", - "inputs": [ - "v67" - ], - "opcode": "LoadString", - "string": "lapki", - "type": "ref", - "users": [ - "73p", - "v70" - ] - }, - { - "id": "v68", - "opcode": "SaveState", - "type": "void", - "users": [ - "v70", - "v69" - ] - }, - { - "id": "v69", - "inputs": [ - "v65", - "v68" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v70" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v70", - "inputs": [ - "v69", - "v66", - "v68" - ], - "method": "std.core.Console.print:std.core.String;void;", - "opcode": "CallVirtual", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "insts": [ - { - "id": "71p", - "inputBlocks": [ - 2, - 5 - ], - "inputs": [ - "v37", - "v29" - ], - "opcode": "Phi", - "type": "i32" - }, - { - "id": "72p", - "inputBlocks": [ - 2, - 5 - ], - "inputs": [ - "v40", - "v65" - ], - "opcode": "Phi", - "type": "ref" - }, - { - "id": "73p", - "inputBlocks": [ - 2, - 5 - ], - "inputs": [ - "v57", - "v66" - ], - "opcode": "Phi", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2, - 5 - ], - "successors": [ - 9 - ] - }, - { - "id": 9, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": true, - "predecessors": [ - 3 - ], - "successors": [ - 6, - 17 - ] - }, - { - "id": 17, - "insts": [ - { - "id": "v2", - "inputs": [ - "v29", - "v29", - "v37", - "v37", - "v37", - "v37", - "v37", - "v37", - "v37", - "v37", - "v37", - "v37", - "v29", - "v29", - "v29", - "v29", - "v173", - "v173", - "v173", - "v173", - "v173" - ], - "opcode": "CatchPhi", - "throwers": [ - "v34", - "v37", - "v39", - "v40", - "v42", - "v43", - "v44", - "v48", - "v51", - "v54", - "v57", - "v60", - "v64", - "v65", - "v66", - "v70", - "v174", - "v177", - "v178", - "v179", - "v182" - ], - "type": "i32", - "users": [ - "v78" - ] - }, - { - "id": "v11", - "inputs": [ - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26", - "v26" - ], - "opcode": "CatchPhi", - "throwers": [ - "v34", - "v37", - "v39", - "v40", - "v42", - "v43", - "v44", - "v48", - "v51", - "v54", - "v57", - "v60", - "v64", - "v65", - "v66", - "v70", - "v174", - "v177", - "v178", - "v179", - "v182" - ], - "type": "ref", - "users": [ - "v77" - ] - } - ], - "isCatchBegin": true, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 8, - 9 - ], - "successors": [ - 13 - ] - }, - { - "id": 13, - "insts": [ - { - "id": "v76", - "opcode": "SaveState", - "type": "void", - "users": [ - "v77" - ] - }, - { - "id": "v77", - "inputs": [ - "v11", - "v76" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v78" - ] - }, - { - "catchers": [ - 18 - ], - "enclosingClass": "A", - "field": "a", - "id": "v78", - "inputs": [ - "v77", - "v2" - ], - "opcode": "StoreObject", - "type": "i32" - }, - { - "id": "v79", - "opcode": "SaveState", - "type": "void", - "users": [ - "v80" - ] - }, - { - "catchers": [ - 18 - ], - "id": "v80", - "inputs": [ - "v79" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v81" - ] - }, - { - "catchers": [ - 18 - ], - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v81", - "inputs": [ - "v80" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v96" - ] - }, - { - "id": "v83", - "opcode": "SaveState", - "type": "void", - "users": [ - "v86", - "v85", - "v84" - ] - }, - { - "catchers": [ - 18 - ], - "id": "v85", - "inputs": [ - "v83" - ], - "loadedClass": "[Lstd/core/Object;", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v86" - ] - }, - { - "id": "v84", - "inputs": [ - "v82", - "v83" - ], - "opcode": "NegativeCheck", - "type": "i32", - "users": [ - "v86" - ] - }, - { - "arrayType": "std.core.Object[]", - "catchers": [ - 18 - ], - "id": "v86", - "inputs": [ - "v85", - "v84", - "v83" - ], - "opcode": "NewArray", - "type": "ref", - "users": [ - "v97", - "v90" - ] - }, - { - "id": "v88", - "opcode": "SaveState", - "type": "void", - "users": [ - "v87" - ] - }, - { - "catchers": [ - 18 - ], - "id": "v87", - "inputs": [ - "v88" - ], - "opcode": "LoadString", - "string": "catch", - "type": "ref", - "users": [ - "v94" - ] - }, - { - "id": "v89", - "opcode": "SaveState", - "type": "void", - "users": [ - "v94", - "v92", - "v90" - ] - }, - { - "id": "v90", - "inputs": [ - "v86", - "v89" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v93", - "v94", - "v91" - ] - }, - { - "id": "v91", - "inputs": [ - "v90" - ], - "opcode": "LenArray", - "type": "i32", - "users": [ - "v92" - ] - }, - { - "id": "v92", - "inputs": [ - "v91", - "v29", - "v89" - ], - "opcode": "BoundsCheck", - "type": "i32", - "users": [ - "v93" - ] - }, - { - "id": "v94", - "inputs": [ - "v90", - "v87", - "v89" - ], - "opcode": "RefTypeCheck", - "type": "ref", - "users": [ - "v93" - ] - }, - { - "catchers": [ - 18 - ], - "id": "v93", - "inputs": [ - "v90", - "v92", - "v94" - ], - "opcode": "StoreArray", - "type": "ref" - }, - { - "id": "v95", - "opcode": "SaveState", - "type": "void", - "users": [ - "v97", - "v96" - ] - }, - { - "id": "v96", - "inputs": [ - "v81", - "v95" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v97" - ] - }, - { - "catchers": [ - 18 - ], - "id": "v97", - "inputs": [ - "v96", - "v86", - "v95" - ], - "method": "std.core.Console.log:void;", - "opcode": "CallVirtual", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 17 - ], - "successors": [ - 11 - ] - }, - { - "id": 11, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": true, - "predecessors": [ - 13 - ], - "successors": [ - 6, - 18 - ] - }, - { - "id": 18, - "isCatchBegin": true, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 10, - 11 - ], - "successors": [ - 14 - ] - }, - { - "id": 14, - "insts": [ - { - "id": "v98", - "opcode": "SaveState", - "type": "void", - "users": [ - "v99" - ] - }, - { - "id": "v99", - "inputs": [ - "v98" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v100" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v100", - "inputs": [ - "v99" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v124" - ] - }, - { - "id": "v101", - "opcode": "SaveState", - "type": "void", - "users": [ - "v104", - "v103", - "v102" - ] - }, - { - "id": "v103", - "inputs": [ - "v101" - ], - "loadedClass": "[Lstd/core/Object;", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v104" - ] - }, - { - "id": "v102", - "inputs": [ - "v82", - "v101" - ], - "opcode": "NegativeCheck", - "type": "i32", - "users": [ - "v104" - ] - }, - { - "arrayType": "std.core.Object[]", - "id": "v104", - "inputs": [ - "v103", - "v102", - "v101" - ], - "opcode": "NewArray", - "type": "ref", - "users": [ - "v125", - "v118" - ] - }, - { - "id": "v105", - "opcode": "SaveState", - "type": "void", - "users": [ - "v108", - "v107", - "v106" - ] - }, - { - "id": "v107", - "inputs": [ - "v105" - ], - "loadedClass": "[Lstd/core/Object;", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v108" - ] - }, - { - "id": "v106", - "inputs": [ - "v82", - "v105" - ], - "opcode": "NegativeCheck", - "type": "i32", - "users": [ - "v108" - ] - }, - { - "arrayType": "std.core.Object[]", - "id": "v108", - "inputs": [ - "v107", - "v106", - "v105" - ], - "opcode": "NewArray", - "type": "ref", - "users": [ - "v122", - "v112" - ] - }, - { - "id": "v110", - "opcode": "SaveState", - "type": "void", - "users": [ - "v109" - ] - }, - { - "id": "v109", - "inputs": [ - "v110" - ], - "opcode": "LoadString", - "string": "and finally", - "type": "ref", - "users": [ - "v116" - ] - }, - { - "id": "v111", - "opcode": "SaveState", - "type": "void", - "users": [ - "v116", - "v114", - "v112" - ] - }, - { - "id": "v112", - "inputs": [ - "v108", - "v111" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v115", - "v116", - "v113" - ] - }, - { - "id": "v113", - "inputs": [ - "v112" - ], - "opcode": "LenArray", - "type": "i32", - "users": [ - "v114" - ] - }, - { - "id": "v114", - "inputs": [ - "v113", - "v29", - "v111" - ], - "opcode": "BoundsCheck", - "type": "i32", - "users": [ - "v115" - ] - }, - { - "id": "v116", - "inputs": [ - "v112", - "v109", - "v111" - ], - "opcode": "RefTypeCheck", - "type": "ref", - "users": [ - "v115" - ] - }, - { - "id": "v115", - "inputs": [ - "v112", - "v114", - "v116" - ], - "opcode": "StoreArray", - "type": "ref" - }, - { - "id": "v117", - "opcode": "SaveState", - "type": "void", - "users": [ - "v122", - "v120", - "v118" - ] - }, - { - "id": "v118", - "inputs": [ - "v104", - "v117" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v121", - "v122", - "v119" - ] - }, - { - "id": "v119", - "inputs": [ - "v118" - ], - "opcode": "LenArray", - "type": "i32", - "users": [ - "v120" - ] - }, - { - "id": "v120", - "inputs": [ - "v119", - "v29", - "v117" - ], - "opcode": "BoundsCheck", - "type": "i32", - "users": [ - "v121" - ] - }, - { - "id": "v122", - "inputs": [ - "v118", - "v108", - "v117" - ], - "opcode": "RefTypeCheck", - "type": "ref", - "users": [ - "v121" - ] - }, - { - "id": "v121", - "inputs": [ - "v118", - "v120", - "v122" - ], - "opcode": "StoreArray", - "type": "ref" - }, - { - "id": "v123", - "opcode": "SaveState", - "type": "void", - "users": [ - "v125", - "v124" - ] - }, - { - "id": "v124", - "inputs": [ - "v100", - "v123" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v125" - ] - }, - { - "id": "v125", - "inputs": [ - "v124", - "v104", - "v123" - ], - "method": "std.core.Console.log:void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v127", - "opcode": "SaveState", - "type": "void", - "users": [ - "v126" - ] - }, - { - "id": "v126", - "inputs": [ - "v127" - ], - "opcode": "LoadString", - "string": "throw error", - "type": "ref", - "users": [ - "v131" - ] - }, - { - "id": "v128", - "opcode": "SaveState", - "type": "void", - "users": [ - "v130", - "v129" - ] - }, - { - "id": "v129", - "inputs": [ - "v128" - ], - "loadedClass": "escompat.Error", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v130" - ] - }, - { - "id": "v130", - "inputs": [ - "v129", - "v128" - ], - "objectClass": "escompat.Error", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v134", - "v131" - ] - }, - { - "id": "v132", - "opcode": "SaveState", - "type": "void", - "users": [ - "v131" - ] - }, - { - "id": "v131", - "inputs": [ - "v130", - "v126", - "v132" - ], - "method": "escompat.Error.:std.core.Object;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v133", - "opcode": "SaveState", - "type": "void", - "users": [ - "v134" - ] - }, - { - "id": "v134", - "inputs": [ - "v130", - "v133" - ], - "opcode": "Throw", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 18 - ], - "successors": [ - 16 - ] - }, - { - "id": 6, - "insts": [ - { - "id": "v146", - "opcode": "SaveState", - "type": "void", - "users": [ - "v147" - ] - }, - { - "id": "v147", - "inputs": [ - "v146" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v148" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v148", - "inputs": [ - "v147" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v162" - ] - }, - { - "id": "v149", - "opcode": "SaveState", - "type": "void", - "users": [ - "v152", - "v151", - "v150" - ] - }, - { - "id": "v151", - "inputs": [ - "v149" - ], - "loadedClass": "[Lstd/core/Object;", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v152" - ] - }, - { - "id": "v150", - "inputs": [ - "v82", - "v149" - ], - "opcode": "NegativeCheck", - "type": "i32", - "users": [ - "v152" - ] - }, - { - "arrayType": "std.core.Object[]", - "id": "v152", - "inputs": [ - "v151", - "v150", - "v149" - ], - "opcode": "NewArray", - "type": "ref", - "users": [ - "v163", - "v156" - ] - }, - { - "id": "v154", - "opcode": "SaveState", - "type": "void", - "users": [ - "v153" - ] - }, - { - "id": "v153", - "inputs": [ - "v154" - ], - "opcode": "LoadString", - "string": "and finally", - "type": "ref", - "users": [ - "v160" - ] - }, - { - "id": "v155", - "opcode": "SaveState", - "type": "void", - "users": [ - "v160", - "v158", - "v156" - ] - }, - { - "id": "v156", - "inputs": [ - "v152", - "v155" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v159", - "v160", - "v157" - ] - }, - { - "id": "v157", - "inputs": [ - "v156" - ], - "opcode": "LenArray", - "type": "i32", - "users": [ - "v158" - ] - }, - { - "id": "v158", - "inputs": [ - "v157", - "v29", - "v155" - ], - "opcode": "BoundsCheck", - "type": "i32", - "users": [ - "v159" - ] - }, - { - "id": "v160", - "inputs": [ - "v156", - "v153", - "v155" - ], - "opcode": "RefTypeCheck", - "type": "ref", - "users": [ - "v159" - ] - }, - { - "id": "v159", - "inputs": [ - "v156", - "v158", - "v160" - ], - "opcode": "StoreArray", - "type": "ref" - }, - { - "id": "v161", - "opcode": "SaveState", - "type": "void", - "users": [ - "v163", - "v162" - ] - }, - { - "id": "v162", - "inputs": [ - "v148", - "v161" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v163" - ] - }, - { - "id": "v163", - "inputs": [ - "v162", - "v152", - "v161" - ], - "method": "std.core.Console.log:void;", - "opcode": "CallVirtual", - "type": "void" - }, - { - "id": "v165", - "opcode": "SaveState", - "type": "void", - "users": [ - "v164" - ] - }, - { - "id": "v164", - "inputs": [ - "v165" - ], - "opcode": "LoadString", - "string": "throw error", - "type": "ref", - "users": [ - "v169" - ] - }, - { - "id": "v166", - "opcode": "SaveState", - "type": "void", - "users": [ - "v168", - "v167" - ] - }, - { - "id": "v167", - "inputs": [ - "v166" - ], - "loadedClass": "escompat.Error", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v168" - ] - }, - { - "id": "v168", - "inputs": [ - "v167", - "v166" - ], - "objectClass": "escompat.Error", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v172", - "v169" - ] - }, - { - "id": "v170", - "opcode": "SaveState", - "type": "void", - "users": [ - "v169" - ] - }, - { - "id": "v169", - "inputs": [ - "v168", - "v164", - "v170" - ], - "method": "escompat.Error.:std.core.Object;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v171", - "opcode": "SaveState", - "type": "void", - "users": [ - "v172" - ] - }, - { - "id": "v172", - "inputs": [ - "v168", - "v171" - ], - "opcode": "Throw", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 9, - 11 - ], - "successors": [ - 16 - ] - }, - { - "id": 4, - "insts": [ - { - "id": "v175", - "opcode": "SaveState", - "type": "void", - "users": [ - "v174" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v174", - "inputs": [ - "v175" - ], - "opcode": "LoadString", - "string": "a gde", - "type": "ref", - "users": [ - "v179" - ] - }, - { - "id": "v176", - "opcode": "SaveState", - "type": "void", - "users": [ - "v178", - "v177" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v177", - "inputs": [ - "v176" - ], - "loadedClass": "std.core.IllegalStateException", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v178" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v178", - "inputs": [ - "v177", - "v176" - ], - "objectClass": "std.core.IllegalStateException", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v182", - "v179" - ] - }, - { - "id": "v180", - "opcode": "SaveState", - "type": "void", - "users": [ - "v179" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v179", - "inputs": [ - "v178", - "v174", - "v180" - ], - "method": "std.core.IllegalStateException.:std.core.String;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v181", - "opcode": "SaveState", - "type": "void", - "users": [ - "v182" - ] - }, - { - "catchers": [ - 17, - 18 - ], - "id": "v182", - "inputs": [ - "v178", - "v181" - ], - "opcode": "Throw", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 16 - ] - }, - { - "id": 16, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4, - 6, - 14 - ] - } - ], - "name": "greet", - "parameters": [ - "i32" - ], - "returnType": "void", - "signature": "A.greet:i32;void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v7", - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v5", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v8" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "opcode": "SaveState", - "type": "void", - "users": [ - "v4", - "v3" - ] - }, - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "inputs": [ - "v3", - "v2" - ], - "method": "A0.:void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v6", - "opcode": "SaveState", - "type": "void", - "users": [ - "v7" - ] - }, - { - "id": "v7", - "inputs": [ - "v0", - "v6" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v8" - ] - }, - { - "enclosingClass": "A", - "field": "b", - "id": "v8", - "inputs": [ - "v7", - "v5" - ], - "opcode": "StoreObject", - "type": "ref" - }, - { - "id": "v9", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "A.:void;" - }, - { - "accessFlags": 1, - "basicBlocks": [ - { - "id": 5, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref" - }, - { - "id": "v1", - "index": 1, - "opcode": "Parameter", - "type": "i32", - "users": [ - "13p", - "v11", - "v7", - "v4" - ] - }, - { - "id": "v2", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v3", - "opcode": "Constant", - "type": "i32", - "users": [ - "13p", - "v4" - ], - "value": 0 - }, - { - "id": "v6", - "opcode": "Constant", - "type": "i32", - "users": [ - "v7" - ], - "value": 1 - }, - { - "id": "v9", - "opcode": "Constant", - "type": "i32", - "users": [ - "v11" - ], - "value": 4 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v4", - "inputs": [ - "v3", - "v1" - ], - "opcode": "Compare", - "operandsType": "i32", - "operator": "GE", - "type": "u1", - "users": [ - "v5" - ] - }, - { - "id": "v5", - "immediate": 0, - "inputs": [ - "v4" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 5 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 3 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v7", - "inputs": [ - "v6", - "v1" - ], - "opcode": "Compare", - "operandsType": "i32", - "operator": "LE", - "type": "u1", - "users": [ - "v8" - ] - }, - { - "id": "v8", - "immediate": 0, - "inputs": [ - "v7" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 3, - 4 - ] - }, - { - "id": 4, - "insts": [ - { - "id": "v10", - "opcode": "SaveState", - "type": "void", - "users": [ - "v12", - "v11" - ] - }, - { - "id": "v12", - "inputs": [ - "v10" - ], - "opcode": "InitClass", - "type": "void" - }, - { - "id": "v11", - "inputs": [ - "v1", - "v9", - "v10" - ], - "method": "ETSGLOBAL.aorb:i32;i32;i32;", - "opcode": "CallStatic", - "type": "i32", - "users": [ - "13p" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "insts": [ - { - "id": "13p", - "inputBlocks": [ - 2, - 1, - 4 - ], - "inputs": [ - "v1", - "v3", - "v11" - ], - "opcode": "Phi", - "type": "i32", - "users": [ - "v18" - ] - }, - { - "id": "v18", - "inputs": [ - "13p" - ], - "opcode": "Return", - "type": "i32" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2, - 1, - 4 - ], - "successors": [ - 6 - ] - }, - { - "id": 6, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 3 - ] - } - ], - "name": "foo", - "parameters": [ - "i32" - ], - "returnType": "i32", - "signature": "A.foo:i32;i32;" - } - ], - "name": "A", - "simpleName": "A", - "superClass": "A0" - } - ] -} \ No newline at end of file diff --git a/jacodb-panda-static/src/test/resources/sample.ets b/jacodb-panda-static/src/test/resources/sample.ets deleted file mode 100644 index 1236485dc..000000000 --- a/jacodb-panda-static/src/test/resources/sample.ets +++ /dev/null @@ -1,94 +0,0 @@ -function aplusb(a: int, b: int) : int { - return a + b; -} - -function aorb(a: int, b: int) : int { - if (a == 0) - return a; - else - return a * b; -} - -interface I1 { - foo(a: int): int -} -interface I2 {} - -abstract class A0 { - abstract greet(c: int): void -} - -class P { - t: T -} - -class A extends A0 implements I1, I2 { - a: int - b: String - - override foo(a: int): int { - let b = 0; - if (a > 0) { - b = a; - } else if (a < 1) { - b = aorb(a, 4); - } - return b; - } - - override greet(c: int): void { - let d = 0; - try { - if (c > 0) { - d = this.a / c; - console.print(this.b + c); - } else if (c < 0) { - console.print("lapki"); - } else { - d = 5; - throw new IllegalStateException("a gde"); - } - } catch (e) { - this.a = d; - console.log("catch"); - } finally { - console.log("and finally"); - throw new Error("throw error"); - } - } -} - -class ABVGDEJOZH { - kek: int -} - -class A1 extends A { - c: String -} - -class B extends ABVGDEJOZH { - constructor(a: int) { - this.kek = a; - } - - transform(obj: I1): int { - return obj.foo(this.kek); - } -} - -function main(): void { - let a: int = 353; - if (aplusb(2, 3) < 0) - a = 11; - console.print(a == 1); - console.print(aplusb(2, 3)); - let obj = new A(); - obj.greet(42); - obj.foo(5); - aorb(1, 0); - - let b = new B(4); - console.print(b.transform(obj)); - - let p = new P(); -} diff --git a/jacodb-panda-static/src/test/resources/simplelogger.properties b/jacodb-panda-static/src/test/resources/simplelogger.properties deleted file mode 100644 index 53f9b1bf8..000000000 --- a/jacodb-panda-static/src/test/resources/simplelogger.properties +++ /dev/null @@ -1,39 +0,0 @@ -# SLF4J's SimpleLogger configuration file -# Simple implementation of Logger that sends all enabled log messages, for all defined loggers, to System.err. - -# Default logging detail level for all instances of SimpleLogger. -# Must be one of ("trace", "debug", "info", "warn", or "error"). -# If not specified, defaults to "info". -org.slf4j.simpleLogger.defaultLogLevel=info - -# Logging detail level for a SimpleLogger instance named "xxxxx". -# Must be one of ("trace", "debug", "info", "warn", or "error"). -# If not specified, the default logging detail level is used. -org.slf4j.simpleLogger.log.org.jacodb.analysis.ifds=debug - -# Logging detail level for a SimpleLogger instance named "xxxxx". -# Must be one of ("trace", "debug", "info", "warn", or "error"). -# If not specified, the default logging detail level is used. -org.slf4j.simpleLogger.log.org.jacodb.analysis.taint=error - -# Set to true if you want the current date and time to be included in output messages. -# Default is false, and will output the number of milliseconds elapsed since startup. -org.slf4j.simpleLogger.showDateTime=true - -# The date and time format to be used in the output messages. -# The pattern describing the date and time format is the same that is used in java.text.SimpleDateFormat. -# If the format is not specified or is invalid, the default format is used. -# The default format is yyyy-MM-dd HH:mm:ss:SSS Z. -org.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss - -# Set to true if you want to output the current thread name. -# Defaults to true. -org.slf4j.simpleLogger.showThreadName=false - -# Set to true if you want the Logger instance name to be included in output messages. -# Defaults to true. -org.slf4j.simpleLogger.showLogName=true - -# Set to true if you want the last component of the name to be included in output messages. -# Defaults to false. -org.slf4j.simpleLogger.showShortLogName=true diff --git a/jacodb-panda-static/src/test/resources/testCatch.ets b/jacodb-panda-static/src/test/resources/testCatch.ets deleted file mode 100644 index 530617a99..000000000 --- a/jacodb-panda-static/src/test/resources/testCatch.ets +++ /dev/null @@ -1,43 +0,0 @@ -type MaybeString = String | null - -function source(): MaybeString { - return null -} - -function getNull(): MaybeString { - return null -} - -function pass(data: MaybeString) { - return data -} - -function validate(data: MaybeString): MaybeString { - if (data == null) return "OK" - return data -} - -function sink(data: MaybeString) { - if (data == null) throw new Error("Error!") -} - -function bad() { - let data = source() - try { - sink("data") - throw new Error("error"); - } catch (e: Error) { - sink(data); - console.log(e); - } -} - -function good() { - let data = source() - try { - sink("data") - throw new Error("error"); - } catch (e: Error) { - sink(validate(data)); - } -} diff --git a/jacodb-panda-static/src/test/resources/testCatch.ir b/jacodb-panda-static/src/test/resources/testCatch.ir deleted file mode 100644 index e742b7247..000000000 --- a/jacodb-panda-static/src/test/resources/testCatch.ir +++ /dev/null @@ -1,1911 +0,0 @@ -{ - "classes": [ - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "attrs", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "td", - "type": "std.core.String" - } - ], - "name": "std.core.FunctionType", - "simpleName": "FunctionType" - }, - { - "accessFlags": 1537, - "name": "std.core.Function10", - "simpleName": "Function10" - }, - { - "accessFlags": 1537, - "name": "std.core.Function0", - "simpleName": "Function0" - }, - { - "accessFlags": 1537, - "name": "std.core.Function3", - "simpleName": "Function3" - }, - { - "accessFlags": 1537, - "name": "std.core.Function7", - "simpleName": "Function7" - }, - { - "accessFlags": 1537, - "name": "std.core.Function6", - "simpleName": "Function6" - }, - { - "accessFlags": 1537, - "name": "std.core.Function", - "simpleName": "Function" - }, - { - "accessFlags": 1537, - "name": "std.core.Function1", - "simpleName": "Function1" - }, - { - "accessFlags": 1537, - "name": "std.core.Function8", - "simpleName": "Function8" - }, - { - "accessFlags": 1537, - "name": "std.core.Function2", - "simpleName": "Function2" - }, - { - "accessFlags": 1537, - "name": "std.core.Function16", - "simpleName": "Function16" - }, - { - "accessFlags": 1537, - "name": "std.core.Function11", - "simpleName": "Function11" - }, - { - "accessFlags": 1537, - "name": "std.core.FunctionN", - "simpleName": "FunctionN" - }, - { - "accessFlags": 1537, - "name": "std.core.Function15", - "simpleName": "Function15" - }, - { - "accessFlags": 1537, - "name": "std.core.Function12", - "simpleName": "Function12" - }, - { - "accessFlags": 1537, - "name": "std.core.Function5", - "simpleName": "Function5" - }, - { - "accessFlags": 1537, - "name": "std.core.Function14", - "simpleName": "Function14" - }, - { - "accessFlags": 1025, - "fields": [ - { - "accessFlags": 0, - "name": "OBJECT_HAS_OWN_PROPERTY_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "KEY_NOT_FOUND", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "ARRAY_LENGTH_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "OBJECT_TO_LOCALE_STRING_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "FUNCTION_NAME_MEMBER_NAME", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "MAX_CONSOLE_PRINT_DEPTH", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "runtime", - "type": "std.core.Runtime" - }, - { - "accessFlags": 0, - "name": "console", - "type": "std.core.Console" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_UNIT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "TypeKindMask", - "type": "i8" - }, - { - "accessFlags": 0, - "name": "MAX_CODE_POINT", - "type": "i32" - }, - { - "accessFlags": 0, - "name": "coroutine", - "type": "std.core.Coroutine" - }, - { - "accessFlags": 0, - "name": "ObjectTD", - "type": "std.core.String" - }, - { - "accessFlags": 0, - "name": "ObjectType", - "type": "std.core.ClassType" - } - ], - "name": "std.core.ETSGLOBAL", - "simpleName": "ETSGLOBAL" - }, - { - "accessFlags": 1537, - "name": "std.core.Function9", - "simpleName": "Function9" - }, - { - "accessFlags": 1025, - "methods": [ - { - "accessFlags": 8, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "", - "returnType": "void", - "signature": "ETSGLOBAL.:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v1", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "_$init$_", - "returnType": "void", - "signature": "ETSGLOBAL._$init$_:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 6, - "insts": [ - { - "id": "v8", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v29", - "opcode": "Constant", - "type": "i32", - "users": [ - "v31" - ], - "value": 1 - }, - { - "id": "v34", - "opcode": "Constant", - "type": "i32", - "users": [ - "v38" - ], - "value": 0 - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v9", - "opcode": "SaveState", - "type": "void", - "users": [ - "v10" - ] - }, - { - "id": "v10", - "inputs": [ - "v9" - ], - "method": "ETSGLOBAL.source:std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v1", - "v1", - "v1", - "v1", - "v1", - "v1", - "v1" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 6 - ], - "successors": [ - 2 - ] - }, - { - "handledTypes": [ - "escompat.Error" - ], - "handlerIds": [ - 8 - ], - "id": 2, - "insts": [ - { - "id": "v0", - "opcode": "Try", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": true, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 4, - 8 - ] - }, - { - "id": 4, - "insts": [ - { - "id": "v12", - "opcode": "SaveState", - "type": "void", - "users": [ - "v11" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v11", - "inputs": [ - "v12" - ], - "opcode": "LoadString", - "string": "data", - "type": "ref", - "users": [ - "v14" - ] - }, - { - "id": "v13", - "opcode": "SaveState", - "type": "void", - "users": [ - "v14" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v14", - "inputs": [ - "v11", - "v13" - ], - "method": "ETSGLOBAL.sink:std.core.String;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v16", - "opcode": "SaveState", - "type": "void", - "users": [ - "v15" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v15", - "inputs": [ - "v16" - ], - "opcode": "LoadString", - "string": "error", - "type": "ref", - "users": [ - "v20" - ] - }, - { - "id": "v17", - "opcode": "SaveState", - "type": "void", - "users": [ - "v19", - "v18" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v18", - "inputs": [ - "v17" - ], - "loadedClass": "escompat.Error", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v19" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v19", - "inputs": [ - "v18", - "v17" - ], - "objectClass": "escompat.Error", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v23", - "v20" - ] - }, - { - "id": "v21", - "opcode": "SaveState", - "type": "void", - "users": [ - "v20" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v20", - "inputs": [ - "v19", - "v15", - "v21" - ], - "method": "escompat.Error.:std.core.Object;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v22", - "opcode": "SaveState", - "type": "void", - "users": [ - "v23" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v23", - "inputs": [ - "v19", - "v22" - ], - "opcode": "Throw", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": true, - "predecessors": [ - 4 - ], - "successors": [ - 7, - 8 - ] - }, - { - "id": 8, - "insts": [ - { - "id": "v1", - "inputs": [ - "v10", - "v10", - "v10", - "v10", - "v10", - "v10", - "v10" - ], - "opcode": "CatchPhi", - "throwers": [ - "v11", - "v14", - "v15", - "v18", - "v19", - "v20", - "v23" - ], - "type": "ref", - "users": [ - "v25" - ] - }, - { - "id": "v7", - "opcode": "CatchPhi", - "type": "ref", - "users": [ - "v40" - ] - } - ], - "isCatchBegin": true, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2, - 3 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "insts": [ - { - "id": "v24", - "opcode": "SaveState", - "type": "void", - "users": [ - "v25" - ] - }, - { - "id": "v25", - "inputs": [ - "v1", - "v24" - ], - "method": "ETSGLOBAL.sink:std.core.String;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v26", - "opcode": "SaveState", - "type": "void", - "users": [ - "v27" - ] - }, - { - "id": "v27", - "inputs": [ - "v26" - ], - "loadedClass": "std.core.ETSGLOBAL", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v28" - ] - }, - { - "enclosingClass": "std.core.ETSGLOBAL", - "field": "console", - "id": "v28", - "inputs": [ - "v27" - ], - "opcode": "LoadStatic", - "type": "ref", - "users": [ - "v42" - ] - }, - { - "id": "v30", - "opcode": "SaveState", - "type": "void", - "users": [ - "v33", - "v32", - "v31" - ] - }, - { - "id": "v32", - "inputs": [ - "v30" - ], - "loadedClass": "[Lstd/core/Object;", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v33" - ] - }, - { - "id": "v31", - "inputs": [ - "v29", - "v30" - ], - "opcode": "NegativeCheck", - "type": "i32", - "users": [ - "v33" - ] - }, - { - "arrayType": "std.core.Object[]", - "id": "v33", - "inputs": [ - "v32", - "v31", - "v30" - ], - "opcode": "NewArray", - "type": "ref", - "users": [ - "v43", - "v36" - ] - }, - { - "id": "v35", - "opcode": "SaveState", - "type": "void", - "users": [ - "v40", - "v38", - "v36" - ] - }, - { - "id": "v36", - "inputs": [ - "v33", - "v35" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v39", - "v40", - "v37" - ] - }, - { - "id": "v37", - "inputs": [ - "v36" - ], - "opcode": "LenArray", - "type": "i32", - "users": [ - "v38" - ] - }, - { - "id": "v38", - "inputs": [ - "v37", - "v34", - "v35" - ], - "opcode": "BoundsCheck", - "type": "i32", - "users": [ - "v39" - ] - }, - { - "id": "v40", - "inputs": [ - "v36", - "v7", - "v35" - ], - "opcode": "RefTypeCheck", - "type": "ref", - "users": [ - "v39" - ] - }, - { - "id": "v39", - "inputs": [ - "v36", - "v38", - "v40" - ], - "opcode": "StoreArray", - "type": "ref" - }, - { - "id": "v41", - "opcode": "SaveState", - "type": "void", - "users": [ - "v43", - "v42" - ] - }, - { - "id": "v42", - "inputs": [ - "v28", - "v41" - ], - "opcode": "NullCheck", - "type": "ref", - "users": [ - "v43" - ] - }, - { - "id": "v43", - "inputs": [ - "v42", - "v33", - "v41" - ], - "method": "std.core.Console.log:void;", - "opcode": "CallVirtual", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 8 - ], - "successors": [ - 1 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v44", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 5 - ], - "successors": [ - 7 - ] - }, - { - "id": 7, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 3, - 1 - ] - } - ], - "name": "bad", - "returnType": "void", - "signature": "ETSGLOBAL.bad:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v2" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "inputs": [ - "v0" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "pass", - "parameters": [ - "std.core.String" - ], - "returnType": "std.core.String", - "signature": "ETSGLOBAL.pass:std.core.String;std.core.String;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 4, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v8", - "v7", - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v2", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v3" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "Compare", - "operandsType": "ref", - "operator": "EQ", - "type": "u1", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "immediate": 0, - "inputs": [ - "v3" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "insts": [ - { - "id": "v5", - "opcode": "SaveState", - "type": "void", - "users": [ - "v7", - "v6" - ] - }, - { - "id": "v6", - "inputs": [ - "v5" - ], - "opcode": "LoadClass", - "type": "ref", - "users": [ - "v7" - ] - }, - { - "candidateType": "std.core.String", - "id": "v7", - "inputs": [ - "v0", - "v6", - "v5" - ], - "opcode": "CheckCast", - "type": "void" - }, - { - "id": "v8", - "inputs": [ - "v0" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2 - ], - "successors": [ - 5 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v10", - "opcode": "SaveState", - "type": "void", - "users": [ - "v9" - ] - }, - { - "id": "v9", - "inputs": [ - "v10" - ], - "opcode": "LoadString", - "string": "OK", - "type": "ref", - "users": [ - "v11" - ] - }, - { - "id": "v11", - "inputs": [ - "v9" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1, - 3 - ] - } - ], - "name": "validate", - "parameters": [ - "std.core.String" - ], - "returnType": "std.core.String", - "signature": "ETSGLOBAL.validate:std.core.String;std.core.String;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v1", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v2" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "inputs": [ - "v1" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "source", - "returnType": "std.core.String", - "signature": "ETSGLOBAL.source:std.core.String;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 6, - "insts": [ - { - "id": "v7", - "opcode": "SafePoint", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v8", - "opcode": "SaveState", - "type": "void", - "users": [ - "v9" - ] - }, - { - "id": "v9", - "inputs": [ - "v8" - ], - "method": "ETSGLOBAL.source:std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v1", - "v1", - "v1", - "v1", - "v1", - "v1", - "v1" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 6 - ], - "successors": [ - 2 - ] - }, - { - "handledTypes": [ - "escompat.Error" - ], - "handlerIds": [ - 8 - ], - "id": 2, - "insts": [ - { - "id": "v0", - "opcode": "Try", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": true, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 4, - 8 - ] - }, - { - "id": 4, - "insts": [ - { - "id": "v11", - "opcode": "SaveState", - "type": "void", - "users": [ - "v10" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v10", - "inputs": [ - "v11" - ], - "opcode": "LoadString", - "string": "data", - "type": "ref", - "users": [ - "v13" - ] - }, - { - "id": "v12", - "opcode": "SaveState", - "type": "void", - "users": [ - "v13" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v13", - "inputs": [ - "v10", - "v12" - ], - "method": "ETSGLOBAL.sink:std.core.String;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v15", - "opcode": "SaveState", - "type": "void", - "users": [ - "v14" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v14", - "inputs": [ - "v15" - ], - "opcode": "LoadString", - "string": "error", - "type": "ref", - "users": [ - "v19" - ] - }, - { - "id": "v16", - "opcode": "SaveState", - "type": "void", - "users": [ - "v18", - "v17" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v17", - "inputs": [ - "v16" - ], - "loadedClass": "escompat.Error", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v18" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v18", - "inputs": [ - "v17", - "v16" - ], - "objectClass": "escompat.Error", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v22", - "v19" - ] - }, - { - "id": "v20", - "opcode": "SaveState", - "type": "void", - "users": [ - "v19" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v19", - "inputs": [ - "v18", - "v14", - "v20" - ], - "method": "escompat.Error.:std.core.Object;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v21", - "opcode": "SaveState", - "type": "void", - "users": [ - "v22" - ] - }, - { - "catchers": [ - 8 - ], - "id": "v22", - "inputs": [ - "v18", - "v21" - ], - "opcode": "Throw", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": true, - "predecessors": [ - 4 - ], - "successors": [ - 7, - 8 - ] - }, - { - "id": 8, - "insts": [ - { - "id": "v1", - "inputs": [ - "v9", - "v9", - "v9", - "v9", - "v9", - "v9", - "v9" - ], - "opcode": "CatchPhi", - "throwers": [ - "v10", - "v13", - "v14", - "v17", - "v18", - "v19", - "v22" - ], - "type": "ref", - "users": [ - "v24" - ] - } - ], - "isCatchBegin": true, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2, - 3 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "insts": [ - { - "id": "v23", - "opcode": "SaveState", - "type": "void", - "users": [ - "v24" - ] - }, - { - "id": "v24", - "inputs": [ - "v1", - "v23" - ], - "method": "ETSGLOBAL.validate:std.core.String;std.core.String;", - "opcode": "CallStatic", - "type": "ref", - "users": [ - "v26" - ] - }, - { - "id": "v25", - "opcode": "SaveState", - "type": "void", - "users": [ - "v26" - ] - }, - { - "id": "v26", - "inputs": [ - "v24", - "v25" - ], - "method": "ETSGLOBAL.sink:std.core.String;void;", - "opcode": "CallStatic", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 8 - ], - "successors": [ - 1 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v27", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 5 - ], - "successors": [ - 7 - ] - }, - { - "id": 7, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 3, - 1 - ] - } - ], - "name": "good", - "returnType": "void", - "signature": "ETSGLOBAL.good:void;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 1, - "insts": [ - { - "id": "v0", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v1", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v2" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v2", - "inputs": [ - "v1" - ], - "opcode": "Return", - "type": "ref" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1 - ], - "successors": [ - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ] - } - ], - "name": "getNull", - "returnType": "std.core.String", - "signature": "ETSGLOBAL.getNull:std.core.String;" - }, - { - "accessFlags": 9, - "basicBlocks": [ - { - "id": 4, - "insts": [ - { - "id": "v0", - "index": 0, - "opcode": "Parameter", - "type": "ref", - "users": [ - "v3" - ] - }, - { - "id": "v1", - "opcode": "SafePoint", - "type": "void" - }, - { - "id": "v2", - "opcode": "NullPtr", - "type": "ref", - "users": [ - "v3" - ] - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "successors": [ - 0 - ] - }, - { - "id": 0, - "insts": [ - { - "id": "v3", - "inputs": [ - "v0", - "v2" - ], - "opcode": "Compare", - "operandsType": "ref", - "operator": "EQ", - "type": "u1", - "users": [ - "v4" - ] - }, - { - "id": "v4", - "immediate": 0, - "inputs": [ - "v3" - ], - "opcode": "IfImm", - "operandsType": "u1", - "operator": "NE", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 4 - ], - "successors": [ - 1, - 2 - ] - }, - { - "id": 2, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 3 - ] - }, - { - "id": 3, - "insts": [ - { - "id": "v5", - "opcode": "ReturnVoid", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 2 - ], - "successors": [ - 5 - ] - }, - { - "id": 1, - "insts": [ - { - "id": "v7", - "opcode": "SaveState", - "type": "void", - "users": [ - "v6" - ] - }, - { - "id": "v6", - "inputs": [ - "v7" - ], - "opcode": "LoadString", - "string": "Error!", - "type": "ref", - "users": [ - "v11" - ] - }, - { - "id": "v8", - "opcode": "SaveState", - "type": "void", - "users": [ - "v10", - "v9" - ] - }, - { - "id": "v9", - "inputs": [ - "v8" - ], - "loadedClass": "escompat.Error", - "opcode": "LoadAndInitClass", - "type": "ref", - "users": [ - "v10" - ] - }, - { - "id": "v10", - "inputs": [ - "v9", - "v8" - ], - "objectClass": "escompat.Error", - "opcode": "NewObject", - "type": "ref", - "users": [ - "v14", - "v11" - ] - }, - { - "id": "v12", - "opcode": "SaveState", - "type": "void", - "users": [ - "v11" - ] - }, - { - "id": "v11", - "inputs": [ - "v10", - "v6", - "v12" - ], - "method": "escompat.Error.:std.core.Object;void;", - "opcode": "CallStatic", - "type": "void" - }, - { - "id": "v13", - "opcode": "SaveState", - "type": "void", - "users": [ - "v14" - ] - }, - { - "id": "v14", - "inputs": [ - "v10", - "v13" - ], - "opcode": "Throw", - "type": "void" - } - ], - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 0 - ], - "successors": [ - 5 - ] - }, - { - "id": 5, - "isCatchBegin": false, - "isTryBegin": false, - "isTryEnd": false, - "predecessors": [ - 1, - 3 - ] - } - ], - "name": "sink", - "parameters": [ - "std.core.String" - ], - "returnType": "void", - "signature": "ETSGLOBAL.sink:std.core.String;void;" - } - ], - "name": "ETSGLOBAL", - "simpleName": "ETSGLOBAL", - "superClass": "std.core.Object" - }, - { - "accessFlags": 1537, - "name": "std.core.Function4", - "simpleName": "Function4" - }, - { - "accessFlags": 1537, - "name": "std.core.Function13", - "simpleName": "Function13" - } - ] -} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 4d681dd07..ab63a105f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -24,11 +24,8 @@ include("jacodb-api-jvm") include("jacodb-api-storage") include("jacodb-core") include("jacodb-storage") -include("jacodb-analysis") include("jacodb-examples") include("jacodb-benchmarks") -include("jacodb-cli") include("jacodb-approximations") include("jacodb-taint-configuration") include("jacodb-ets") -include("jacodb-panda-static")