Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
5c3e88c
switching to develop
lehvolk May 22, 2023
0ce1a3c
make AbstractFullExprSetCollector api be Java friendly
lehvolk May 24, 2023
9631fef
working on caching settings
lehvolk May 24, 2023
4047569
cleanup
lehvolk May 24, 2023
0a089d4
[jacodb-ifds] Fix usage of locals criteria
volivan239 May 22, 2023
d414110
[jacodb-ifds] Add JodaTime tests
volivan239 May 24, 2023
fa8384b
Fix cfg build of virtual calls
volivan239 May 24, 2023
801c1d2
Disabled long-running test
volivan239 May 24, 2023
9c021f3
Fix swapped rhv and lhv in JcRawConditionExprs (#82)
volivan239 May 24, 2023
7178361
[jacodb-ifds] Filter inappropriate candidates in virtual calls devirt…
volivan239 May 24, 2023
91d8f0a
build snapshots from develop branch
lehvolk May 25, 2023
a5f87c8
bring methodRef separation (special, static etc) back
lehvolk May 25, 2023
57a56c1
- review features api
lehvolk May 25, 2023
32ce228
fix tests
lehvolk May 25, 2023
11c889e
tests for caching
lehvolk May 25, 2023
f8be865
fix tests
lehvolk May 25, 2023
d740896
- fix tests
lehvolk May 25, 2023
78e7049
fix too many puts in cache
lehvolk May 26, 2023
5929195
fix missed cfg/instructions caching
lehvolk May 26, 2023
2b84a86
[jacodb-ifds] Improve cli api + test for cli
volivan239 May 25, 2023
24339b0
better equality of JcClassTypes
lehvolk May 26, 2023
fa6f811
Add ability to override real method closes #85
lehvolk May 26, 2023
cca1117
Typo in the JcRawDynamicCallExpr/JcDynamicCallExpr member names and J…
lehvolk May 26, 2023
debf15b
add coverage infrastructure
lehvolk May 29, 2023
d46e4db
fix coverage build
lehvolk May 29, 2023
303e4b1
makes builds faster by adding indexes for cascading deletes of byteco…
lehvolk May 29, 2023
08d0cf4
fix tests
lehvolk May 29, 2023
fbd93dd
get rid of custom serializer
lehvolk May 29, 2023
59f1c40
fix coverage report action
lehvolk May 29, 2023
4dfb582
fix coverage report action
lehvolk May 29, 2023
0dcd436
Autogenerated JaCoCo coverage badges
github-actions[bot] May 29, 2023
741944c
add coverage badge
lehvolk May 29, 2023
ef42c85
Autogenerated JaCoCo coverage badges
github-actions[bot] May 29, 2023
8e19579
fix coverage badge
lehvolk May 29, 2023
d7f9df2
Autogenerated JaCoCo coverage badges
github-actions[bot] May 29, 2023
e9e0e7c
Merge branch 'main' of https://github.com/UnitTestBot/jacodb into dev…
lehvolk May 29, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: Generate coverage report

on:
push:
branches: [ develop, main ]
pull_request:
branches: [ main ]
workflow_dispatch:

jobs:
build:

runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v3

- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
- uses: gradle/gradle-build-action@v2
with:
gradle-version: 7.6.1
- name: Build and run tests
run: |
gradle clean build --no-daemon --info

- name: Generate JaCoCo badge
id: jacoco
uses: cicirello/jacoco-badge-generator@v2
with:
badges-directory: docs/badges
generate-branches-badge: true
generate-summary: true
jacoco-csv-file: >
jacodb-analysis/build/reports/jacoco/test/jacocoTestReport.csv
jacodb-core/build/reports/jacoco/test/jacocoTestReport.csv

- name: Log coverage percentages to workflow output
run: |
echo "coverage = ${{ steps.jacoco.outputs.coverage }}"
echo "branches = ${{ steps.jacoco.outputs.branches }}"
- name: Upload JaCoCo coverage report as a workflow artifact
uses: actions/upload-artifact@v3
with:
name: jacoco-report
path: jacodb-*/build/reports/jacoco/

- name: Commit and push the coverage badges and summary file
if: ${{ github.event_name != 'pull_request' }}
run: |
cd docs/badges
if [[ `git status --porcelain *.svg *.json` ]]; then
git config --global user.name 'github-actions'
git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com'
git add *.svg *.json
git commit -m "Autogenerated JaCoCo coverage badges" *.svg *.json
git push
fi
- name: Comment on PR with coverage percentages
if: ${{ github.event_name == 'pull_request' }}
run: |
REPORT=$(<badges/coverage-summary.json)
COVERAGE=$(jq -r '.coverage' <<< "$REPORT")%
BRANCHES=$(jq -r '.branches' <<< "$REPORT")%
NEWLINE=$'\n'
BODY="## JaCoCo Test Coverage Summary Statistics${NEWLINE}* __Coverage:__ ${COVERAGE}${NEWLINE}* __Branches:__ ${BRANCHES}"
gh pr comment ${{github.event.pull_request.number}} -b "${BODY}"
continue-on-error: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[![ci status](https://github.com/UnitTestBot/jacodb/actions/workflows/build-and-test.yml/badge.svg)](https://github.com/UnitTestBot/jacodb/actions/workflows/build-and-test.yml)
[![Coverage](./docs/badges/jacoco.svg)](https://github.com/UnitTestBot/jacodb/actions/workflows/coverage.yml)

## Overview

Expand Down
13 changes: 13 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ plugins {
kotlin("jvm") version kotlinVersion
kotlin("plugin.allopen") version kotlinVersion
id("org.cadixdev.licenser") version "0.6.1"
jacoco
}

repositories {
Expand All @@ -41,6 +42,7 @@ allprojects {
plugin("kotlin")
plugin("org.jetbrains.kotlin.plugin.allopen")
plugin("org.cadixdev.licenser")
plugin("jacoco")
}

repositories {
Expand Down Expand Up @@ -95,14 +97,25 @@ allprojects {
allWarningsAsErrors = false
}
}

jacocoTestReport {
dependsOn(test) // tests are required to run before generating the report
reports {
csv.required.set(true)
}

}

withType<Test> {
useJUnitPlatform()
jvmArgs = listOf("-Xmx2g", "-XX:+HeapDumpOnOutOfMemoryError", "-XX:HeapDumpPath=heapdump.hprof")
testLogging {
events("passed", "skipped", "failed")
}
finalizedBy(jacocoTestReport) // report is always generated after tests run
}


val sourcesJar by creating(Jar::class) {
archiveClassifier.set("sources")
from(sourceSets.getByName("main").kotlin.srcDirs)
Expand Down
1 change: 1 addition & 0 deletions docs/badges/branches.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/badges/coverage-summary.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"branches": 68.34195614683419, "coverage": 70.38198957259596}
1 change: 1 addition & 0 deletions docs/badges/jacoco.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 5 additions & 5 deletions jacodb-api/src/main/kotlin/org/jacodb/api/cfg/JcInst.kt
Original file line number Diff line number Diff line change
Expand Up @@ -680,14 +680,14 @@ data class JcLambdaExpr(
data class JcDynamicCallExpr(
private val bsmRef: TypedMethodRef,
val bsmArgs: List<BsmArg>,
val callCiteMethodName: String,
val callCiteArgTypes: List<JcType>,
val callCiteReturnType: JcType,
val callCiteArgs: List<JcValue>
val callSiteMethodName: String,
val callSiteArgTypes: List<JcType>,
val callSiteReturnType: JcType,
val callSiteArgs: List<JcValue>
) : JcCallExpr {

override val method get() = bsmRef.method
override val args get() = callCiteArgs
override val args get() = callSiteArgs

override fun <T> accept(visitor: JcExprVisitor<T>): T {
return visitor.visitJcDynamicCallExpr(this)
Expand Down
10 changes: 5 additions & 5 deletions jacodb-api/src/main/kotlin/org/jacodb/api/cfg/JcRawInst.kt
Original file line number Diff line number Diff line change
Expand Up @@ -690,17 +690,17 @@ data class BsmHandle(
data class JcRawDynamicCallExpr(
val bsm: BsmHandle,
val bsmArgs: List<BsmArg>,
val callCiteMethodName: String,
val callCiteArgTypes: List<TypeName>,
val callCiteReturnType: TypeName,
val callCiteArgs: List<JcRawValue>
val callSiteMethodName: String,
val callSiteArgTypes: List<TypeName>,
val callSiteReturnType: TypeName,
val callSiteArgs: List<JcRawValue>
) : JcRawCallExpr {
override val declaringClass get() = bsm.declaringClass
override val methodName get() = bsm.name
override val argumentTypes get() = bsm.argTypes
override val returnType get() = bsm.returnType
override val typeName get() = returnType
override val args get() = callCiteArgs
override val args get() = callSiteArgs

override fun <T> accept(visitor: JcRawExprVisitor<T>): T {
return visitor.visitJcRawDynamicCallExpr(this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ class StringConcatSimplifier(val jcGraph: JcGraph) : DefaultJcInstVisitor<JcInst
val lhv = inst.lhv
val rhv = inst.rhv

if (rhv is JcDynamicCallExpr && rhv.callCiteMethodName == "makeConcatWithConstants") {
if (rhv is JcDynamicCallExpr && rhv.callSiteMethodName == "makeConcatWithConstants") {

val (first, second) = when {
rhv.callCiteArgs.size == 2 -> rhv.callCiteArgs
rhv.callCiteArgs.size == 1 && rhv.bsmArgs.size == 1 && rhv.bsmArgs[0] is BsmStringArg -> listOf(
rhv.callCiteArgs[0],
rhv.callSiteArgs.size == 2 -> rhv.callSiteArgs
rhv.callSiteArgs.size == 1 && rhv.bsmArgs.size == 1 && rhv.bsmArgs[0] is BsmStringArg -> listOf(
rhv.callSiteArgs[0],
JcStringConstant((rhv.bsmArgs[0] as BsmStringArg).value, stringType)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ import org.jacodb.api.cfg.JcFieldRef
import org.jacodb.api.cfg.JcFloat
import org.jacodb.api.cfg.JcGeExpr
import org.jacodb.api.cfg.JcGotoInst
import org.jacodb.api.cfg.JcGraph
import org.jacodb.api.cfg.JcGtExpr
import org.jacodb.api.cfg.JcIfInst
import org.jacodb.api.cfg.JcInst
Expand Down Expand Up @@ -412,9 +411,9 @@ class JcInstListBuilder(val method: JcMethod,val instList: JcInstList<JcRawInst>
return JcDynamicCallExpr(
classpath.methodRef(expr),
expr.bsmArgs,
expr.callCiteMethodName,
expr.callCiteArgTypes.map { it.asType() },
expr.callCiteReturnType.asType(),
expr.callSiteMethodName,
expr.callSiteArgTypes.map { it.asType() },
expr.callSiteReturnType.asType(),
expr.args.map { it.accept(this) as JcValue }
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -660,8 +660,8 @@ class MethodNodeBuilder(
expr.args.forEach { it.accept(this) }
currentInsnList.add(
InvokeDynamicInsnNode(
expr.callCiteMethodName,
"(${expr.callCiteArgTypes.joinToString("") { it.jvmTypeName }})${expr.callCiteReturnType.jvmTypeName}",
expr.callSiteMethodName,
"(${expr.callSiteArgTypes.joinToString("") { it.jvmTypeName }})${expr.callSiteReturnType.jvmTypeName}",
expr.bsm.asAsmHandle,
*expr.bsmArgs.map {
when (it) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,9 +318,9 @@ class ExprMapper(val mapping: Map<JcRawExpr, JcRawExpr>) : JcRawInstVisitor<JcRa
else -> JcRawDynamicCallExpr(
expr.bsm,
expr.bsmArgs,
expr.callCiteMethodName,
expr.callCiteArgTypes,
expr.callCiteReturnType,
expr.callSiteMethodName,
expr.callSiteArgTypes,
expr.callSiteReturnType,
newArgs
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,16 @@ class HierarchyExtensionImpl(private val cp: JcClasspath) : HierarchyExtension {
JOIN Classes ON Classes.id = hierarchy.class_id
JOIN Symbols ON Symbols.id = Classes.name
WHERE location_id in ($locationIds)
ORDER BY Classes.id
""".trimIndent()

private fun directSubClassesQuery(locationIds: String, sinceId: Long?) = """
SELECT Classes.id, Classes.location_id, SymbolsName.name as name_name, Classes.bytecode FROM ClassHierarchies
JOIN Symbols ON Symbols.id = ClassHierarchies.super_id
JOIN Symbols as SymbolsName ON SymbolsName.id = Classes.name
JOIN Classes ON Classes.id = ClassHierarchies.class_id
WHERE Symbols.name = ? and ($sinceId is null or ClassHierarchies.class_id > $sinceId) AND Classes.location_id in ($locationIds)
WHERE Symbols.name = ? and ($sinceId is null or ClassHierarchies.class_id > $sinceId) AND Classes.location_id in ($locationIds)
ORDER BY Classes.id
""".trimIndent()

}
Expand Down
52 changes: 1 addition & 51 deletions jacodb-core/src/main/kotlin/org/jacodb/impl/types/Objects.kt
Original file line number Diff line number Diff line change
Expand Up @@ -108,59 +108,9 @@ sealed class AnnotationValue
@Serializable
open class AnnotationValueList(val annotations: List<AnnotationValue>) : AnnotationValue()

@Serializable(with = PrimitiveValueSerializer::class)
@Serializable
class PrimitiveValue(val dataType: AnnotationValueKind, val value: Any) : AnnotationValue()

object PrimitiveValueSerializer : KSerializer<PrimitiveValue> {
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("PrimitiveValue") {
element("dataType", serialDescriptor<String>())
element("value", buildClassSerialDescriptor("Any"))
}

@Suppress("UNCHECKED_CAST")
private val dataTypeSerializers: Map<AnnotationValueKind, KSerializer<Any>> =
mapOf(
AnnotationValueKind.STRING to serializer<String>(),
AnnotationValueKind.BYTE to serializer<Byte>(),
AnnotationValueKind.SHORT to serializer<Short>(),
AnnotationValueKind.CHAR to serializer<Char>(),
AnnotationValueKind.LONG to serializer<Long>(),
AnnotationValueKind.INT to serializer<Int>(),
AnnotationValueKind.FLOAT to serializer<Float>(),
AnnotationValueKind.DOUBLE to serializer<Double>(),
AnnotationValueKind.BYTE to serializer<Byte>(),
AnnotationValueKind.BOOLEAN to serializer<Boolean>()
//list them all
).mapValues { (_, v) -> v as KSerializer<Any> }

private fun getPayloadSerializer(dataType: AnnotationValueKind): KSerializer<Any> = dataTypeSerializers[dataType]
?: throw SerializationException("Serializer for class $dataType is not registered in PacketSerializer")

override fun serialize(encoder: Encoder, value: PrimitiveValue) {
encoder.encodeStructure(descriptor) {
encodeStringElement(descriptor, 0, value.dataType.name)
encodeSerializableElement(descriptor, 1, getPayloadSerializer(value.dataType), value.value)
}
}

@ExperimentalSerializationApi
override fun deserialize(decoder: Decoder): PrimitiveValue = decoder.decodeStructure(descriptor) {
val dataType = AnnotationValueKind.valueOf(decodeStringElement(descriptor, 0))
if (decodeSequentially()) {
val payload = decodeSerializableElement(descriptor, 1, getPayloadSerializer(dataType))
PrimitiveValue(dataType, payload)
} else {
require(decodeElementIndex(descriptor) == 0) { "dataType field should precede payload field" }
val payload = when (val index = decodeElementIndex(descriptor)) {
1 -> decodeSerializableElement(descriptor, 1, getPayloadSerializer(dataType))
CompositeDecoder.DECODE_DONE -> throw SerializationException("payload field is missing")
else -> error("Unexpected index: $index")
}
PrimitiveValue(dataType, payload)
}
}
}

@Serializable
class ClassRef(val className: String) : AnnotationValue()

Expand Down
20 changes: 20 additions & 0 deletions jacodb-core/src/main/resources/sqlite/add-indexes.sql
Original file line number Diff line number Diff line change
@@ -1,4 +1,24 @@
CREATE INDEX IF NOT EXISTS "Classes_name" ON "Classes" ("name");

CREATE INDEX IF NOT EXISTS "Classes_outerMethodId" ON "Classes" ("outer_method");
CREATE INDEX IF NOT EXISTS "ClassInnerClasses_classId" ON "ClassInnerClasses" ("class_id");
CREATE INDEX IF NOT EXISTS "ClassInnerClasses_classId" ON "ClassInnerClasses" ("class_id");
CREATE INDEX IF NOT EXISTS "ClassInnerClasses_innerClassId" ON "ClassInnerClasses" ("inner_class_id");

CREATE INDEX IF NOT EXISTS "ClassHierarchies_classId" ON "ClassHierarchies" ("class_id");
CREATE INDEX IF NOT EXISTS "ClassHierarchies_superId" ON "ClassHierarchies" ("super_id");

CREATE INDEX IF NOT EXISTS "Annotations_classId" ON "Annotations" ("class_id");
CREATE INDEX IF NOT EXISTS "Annotations_fieldId" ON "Annotations" ("field_id");
CREATE INDEX IF NOT EXISTS "Annotations_methodId" ON "Annotations" ("method_id");
CREATE INDEX IF NOT EXISTS "Annotations_paramsId" ON "Annotations" ("param_id");

CREATE INDEX IF NOT EXISTS "Classes_location" ON "Classes" ("location_id");
CREATE INDEX IF NOT EXISTS "Fields_classId" ON "Fields" ("class_id");
CREATE INDEX IF NOT EXISTS "Methods_classId" ON "Methods" ("class_id");

CREATE INDEX IF NOT EXISTS "MethodParameters_methodId" ON "MethodParameters" ("method_id");

CREATE UNIQUE INDEX IF NOT EXISTS "Symbols_name" ON "Symbols" ("name");
CREATE UNIQUE INDEX IF NOT EXISTS "Bytecodelocations_hash" ON "BytecodeLocations" ("uniqueId");
CREATE UNIQUE INDEX IF NOT EXISTS "Methods_class_id_name_desc" ON "Methods" ("class_id", "name", "desc");
Expand Down