Produce a single Kotlin project in DSL-FAIR/ that:
- Uses FairDSL.kt's design (expression-level handlers, matcher-based dispatch, DomainOperation callbacks, two-phase architecture) as the DSL surface.
- Runs on real SootUp Jimple IR (not the mock
JimpleExprsealed class from FairDSL.kt). - Reuses FAIR's converter infrastructure (AIRMethodConverter, AirTranslationSuite, air.core) for walking Jimple CFGs and producing AIR/FAIR output.
- Incorporates the richer lattice library from DSL (ProductLattice, MapLattice, LiftLattice) into FairDSL.kt's
Lattice<T>interface.
┌──────────────────────────────────────────────────────────────────────┐
│ User-facing DSL (from FairDSL.kt design) │
│ │
│ fairAnalysis("Taint", TaintLattice) { │
│ onInvokeExpr { source(...) { taintsReturnValue() } } │
│ // binop, unary, alloc defaults just work │
│ } │
│ │ │
│ ▼ builds │
│ FairAnalysisDefinition<T> │
│ .processExpression(expr: Expr) → List<FairApply<T>> │
└──────────┬───────────────────────────────────────────────────────────┘
│ called by
┌──────────▼───────────────────────────────────────────────────────────┐
│ FAIR Converter (from FAIR, adapted) │
│ │
│ AIRMethodConverter walks Jimple CFG (Pass 1 + Pass 2) │
│ DefaultAIRStmtSemantics.translateAssign() sees RHS expression: │
│ → calls analysisDefinition.processExpression(rhs) │
│ → if non-empty: emits AIRApplyStmt per FairApply │
│ → if empty: falls through to structural default (copy/load/store)│
└──────────┬───────────────────────────────────────────────────────────┘
│ produces
┌──────────▼───────────────────────────────────────────────────────────┐
│ AIR Instructions (from air.core, kept as-is) │
│ │
│ AIRApplyStmt now carries a DomainOperation<T> reference │
│ (or an OpId that maps to one) so the interpreter can call back │
│ into the DSL's flow function at execution time. │
└──────────────────────────────────────────────────────────────────────┘
DSL-FAIR/
├── build.gradle.kts — single project (no submodules initially)
├── settings.gradle.kts
└── src/main/kotlin/
├── dsl/ — DSL surface (from FairDSL.kt, adapted)
│ ├── Lattice.kt — merged lattice interface + implementations
│ ├── DomainOperation.kt — DomainOperation<T> + five generic ops
│ ├── ExprHandlers.kt — ExprHandler hierarchy (uses real SootUp Expr types)
│ ├── InvokeHandlers.kt — InvokeExprHandler + source/sink/sanitizer builders
│ ├── FairAnalysis.kt — FairAnalysisBuilder, FairAnalysisDefinition, fairAnalysis()
│ ├── Environment.kt — AbstractEnvironment<T>, Finding, FindingReporter
│ └── examples/
│ └── TaintAnalysis.kt — defineTaintAnalysis() example
├── air/ — copied from FAIR/air.core (kept as-is, mostly)
│ ├── AIR.kt
│ ├── AIRStmt.kt
│ ├── AIRAccessPath.kt
│ ├── AIRValue.kt
│ ├── ... (all air.core files)
│ └── model/
│ └── ...
├── converter/ — copied from FAIR/src, adapted
│ ├── AIRMethodConverter.kt — unchanged (delegates to semantics)
│ ├── AIRWholeProgramConverter.kt
│ ├── AirTranslationSuite.kt — extended to accept FairAnalysisDefinition
│ ├── BinaryOpFinder.kt
│ ├── LiftValueHelper.kt
│ └── ...
├── semantics/ — from FAIR/src, with DSL integration point
│ ├── AIRSemantics.kt
│ ├── AIRSemanticsContext.kt — gains reference to FairAnalysisDefinition
│ ├── DslDrivenSemantics.kt — NEW: replaces TaintIFDSSemantics
│ ├── expr/
│ │ └── DslExprSemantics.kt — NEW: delegates to DSL handlers
│ ├── stmt/
│ │ └── DslStmtSemantics.kt — NEW: calls DSL for expression RHS
│ ├── call/
│ │ └── DslCallSemantics.kt — NEW: calls DSL invoke handler
│ ├── heap/
│ │ └── DefaultHeapSemantics.kt — kept
│ └── wholeProgram/
│ └── WholeProgramContext.kt — kept
├── sensitivity/ — copied from FAIR/src as-is
│ ├── AccessPathFactory.kt
│ └── SensitivityType.kt
├── helper/ — copied from FAIR/src as-is
│ ├── CallGraphIndex.kt
│ └── FoldHelper.kt
└── rule/ — from FAIR/src, kept for backward compat
├── MethodRule.kt
└── TaintMethodRule.kt — kept but optional (DSL replaces it)
The AIR instruction set is the target IR. Copy the entire air.core source tree.
No changes needed, except one small extension to AIRApplyStmt (see Section 6).
Files:
AIR.kt,AIRStmt.kt,AIRAccessPath.kt,AIRValue.kt,AIRLocal.kt,AIRField.ktAIRConstant.kt,AIROperator.kt,AIRBody.kt,ComparisonOp.kt,CallType.ktmodel/(AIRCFG, AirBasicBlock, AIRMethod, AIRClass, AIRProgram, signatures, types, lattice, modifiers, ForEachSet, etc.)context/(ContextId, ContextStatementFactory, CallStringsContextFactory, IFDSContextFactory, NoContextFactory, MethodId, MethodIdRegistry, ContextToken, ContextInitSource)
converter/AIRMethodConverter.kt— the two-pass CFG walker. No changes; it already delegates all expression/statement logic toAIRSemantics.converter/AIRWholeProgramConverter.kt— whole-program entry point.converter/AIRClassConverter.kt— class-level conversion.converter/BinaryOpFinder.kt— maps SootUp binop to AIR BinaryOp.converter/LiftValueHelper.kt— lifts SootUp Values to AIRValues.converter/ClassTypeFactory.kt,TypeExtension.kt— type mapping utilities.helper/CallGraphIndex.kt— call graph indexing.helper/FoldHelper.kt,PlaceHolderFieldSignature.kt— fold helpers.sensitivity/AccessPathFactory.kt,SensitivityType.kt,AIRLocalFactory.kt— access path creation.semantics/AIRSemantics.kt— the composed interface (kept as-is).semantics/AIRSemanticsContext.kt— extended (see Section 6).semantics/FrameworkType.kt— enum kept.semantics/stmt/AIRStmtSemantics.kt— interface kept.semantics/stmt/DefaultAIRStmtSemantics.kt— kept, extended (see Section 6).semantics/stmt/AnalysisDirectionSemantics.kt,ForwardDirectionSemantics.kt,BackwardDirectionSemantics.kt— kept.semantics/expr/AIRExprSemantics.kt— interface kept.semantics/call/AIRCallSemantics.kt,AbstractCallSemantics.kt,CallHelper.kt— kept.semantics/call/IFDSCallSemantics.kt,MonotoneCallSemantics.kt— kept for non-DSL paths.semantics/heap/AIRHeapSemantics.kt,DefaultHeapSemantics.kt— kept.semantics/wholeProgram/WholeProgramContext.kt,TaintProgramContext.kt— kept.rule/MethodRule.kt,MethodRulePattern.kt,DefaultJVMRules.kt,StringConcatRule.kt— kept for backward compatibility.rule/TaintMethodRule.kt— kept but the DSL replaces its role.ConversionUtil.kt,SootUpManager.kt,AnalysisType.kt,ContextStrategy.kt,AnalysisDirection.kt,ProgramConfig.kt— kept.Main.kt— adapted for DSL entry point.
Lattice.kt— theFlatLattice<E>,MapLattice<K,V>,LiftLattice<E>,ProductLattice<A,B>implementations are richer than FairDSL.kt's. We merge them into the FairDSL.ktLattice<T>interface (see Section 6).
Models.kt— statement-level Pattern/Effect model. Superseded by FairDSL.kt's expression-level handlers.AnalysisBuilder.kt— top-level DSL builder. Superseded byFairAnalysisBuilder<T>.RulesBuilder.kt,Rules.kt—yieldsinfix operator and pattern helpers. Superseded by handler-based dispatch.Globals.kt— SOURCE/SINK/SANITIZE singletons. Replaced by matcher-based source/sink/sanitizer builders.printAnalysis.kt— pretty-printer for the old model. Will need rewriting for the new model.Main.kt— example using the old DSL. Replaced byTaintAnalysis.ktexample.
The entire file is the design blueprint. We keep:
Lattice<T>interface (withmeetandleq, which DSL's version lacks)DomainOperation<T>fun interface + five generic opsExprHandler<T>hierarchyInvokeExprHandler<T>with source/sink/sanitizer buildersFairAnalysisBuilder<T>,FairAnalysisDefinition<T>,fairAnalysis()entry pointAbstractEnvironment<T>,Finding,FindingReporter
But we replace the mock JimpleExpr sealed class and MethodSignature with real SootUp types.
| File/Concept | Reason |
|---|---|
DSL/src/Models.kt (Pattern, Effect, FlowRule) |
Statement-level model; FairDSL.kt uses expression-level handlers |
DSL/src/AnalysisBuilder.kt |
Replaced by FairAnalysisBuilder<T> |
DSL/src/RulesBuilder.kt, Rules.kt |
yields pattern superseded by handler dispatch |
DSL/src/Globals.kt (SOURCE, SINK, SANITIZE) |
Replaced by matcher-based source(), sink(), sanitizer() builders |
DSL/src/printAnalysis.kt |
Tied to old model |
DSL/src/Main.kt |
Old example |
FairDSL.kt §10 (JimpleExpr sealed class) |
Mock types; replaced by real SootUp Expr subclasses |
FairDSL.kt §10 (MethodSignature data class) |
Mock; replaced by SootUp's sootup.core.signatures.MethodSignature |
FAIR/.../TaintIFDSSemantics.kt |
Hardcoded taint semantics; replaced by DslDrivenSemantics |
FAIR/.../AnalysisPolicyProvider.kt |
Hardcoded policy; replaced by DSL-driven provider |
FAIR/.../IFDSExprSemantics.kt |
Hardcoded IFDS expr handling; replaced by DslExprSemantics |
FAIR/.../IFDSAIRStmtSemantics.kt |
IFDS-specific stmt handling; replaced by DslStmtSemantics |
Problem: FairDSL.kt's Lattice<T> has {bottom, top, join, meet, leq}. DSL's Lattice<E> has {elements, bottom, top, join} but no meet or leq. The DSL has richer implementations (MapLattice, LiftLattice, ProductLattice) that FairDSL.kt lacks.
Solution: Use FairDSL.kt's interface as the canonical one and port DSL's implementations to it:
// dsl/Lattice.kt — merged interface
interface Lattice<T> {
val bottom: T
val top: T
fun join(a: T, b: T): T
fun meet(a: T, b: T): T
fun leq(a: T, b: T): Boolean
}Port from DSL:
FlatLattice<E>— addmeetandleq(straightforward duals ofjoin).MapLattice<K,V>— addmeet(pointwise meet) andleq(pointwise leq).LiftLattice<E>— addmeetandleq.ProductLattice<A,B>— addmeet(component-wise) andleq(component-wise).
Drop elements: Set<E> from the interface (it's impractical for MapLattice etc. — FairDSL.kt correctly omits it).
Keep FairDSL.kt's Flat<E> sealed class (Bottom | Top | Element<E>) and FlatLattice<E> as a separate utility alongside the ported DSL lattices.
Problem: FairDSL.kt's ExprHandler.process() takes JimpleExpr (a mock sealed class). The real SootUp types are sootup.core.jimple.common.expr.Expr and its subclasses.
Solution: Replace JimpleExpr parameter with SootUp Expr (or Value in some cases). The handler hierarchy becomes:
abstract class ExprHandler<T>(
protected val lattice: Lattice<T>,
protected var defaultOp: DomainOperation<T>
) {
// Now takes SootUp Expr + the AIR destination access path + context
abstract fun process(
dest: AIRAccessPath?,
expr: Expr, // real SootUp type
context: AIRSemanticsContext
): List<AIRApplyStmt> // returns AIR statements, not FairApply
}Key change: Instead of returning FairApply<T> (a lightweight data class), handlers now return AIRApplyStmt — the real AIR instruction. The DomainOperation<T> is embedded via a new AIROperator wrapper (see 6.3).
Handler-to-SootUp mapping:
BinaryExprHandler<T>processesAbstractBinopExprUnaryExprHandler<T>/NegExprHandler<T>processesJNegExprLengthExprHandler<T>processesJLengthExprCastExprHandler<T>processesJCastExprInstanceOfExprHandler<T>processesJInstanceOfExprInvokeExprHandler<T>processesAbstractInvokeExprAllocationExprHandler<T>processesJNewExpr,JNewArrayExpr,JNewMultiArrayExpr
Each handler uses LiftValueHelper.liftValue() and LiftValueHelper.liftAccessPath() to convert SootUp values to AIR values/access paths.
Problem: AIR.AIRApplyStmt currently takes AIROperator (an interface with implementations like BinaryOp, TaintOperator). FairDSL.kt's FairApply<T> carries a DomainOperation<T> that the interpreter calls at execution time. We need AIRApplyStmt to also carry a DomainOperation.
Solution: Create a DslOperator<T> that implements AIROperator and wraps a DomainOperation<T>:
// New class bridging DSL operations to AIR's operator model
class DslOperator<T>(
val operation: DomainOperation<T>,
private val label: String = operation.toString()
) : AIROperator {
override fun toString(): String = label
}AIRApplyStmt already accepts any AIROperator, so no change to its data class. The interpreter, when it encounters an AIRApplyStmt whose operator is a DslOperator, calls operation.execute(dest, args, env).
Problem: FairDSL.kt's InvokeExprMatcher takes the mock MethodSignature. We need it to match on SootUp's real sootup.core.signatures.MethodSignature.
Solution:
fun interface InvokeExprMatcher {
fun matches(signature: sootup.core.signatures.MethodSignature): Boolean
}
// Convenience helpers
fun matching(predicate: (sootup.core.signatures.MethodSignature) -> Boolean) =
InvokeExprMatcher(predicate)
// Named matchers for common cases
fun methodNamed(name: String) = matching { it.subSignature.name == name }
fun methodIn(className: String) = matching { it.declClassType.fullyQualifiedName == className }Problem: DefaultAIRStmtSemantics.translateAssign() currently dispatches the RHS of an assignment to specific semantics (expr, call, heap). We need it to first consult the DSL for expression-level rules, and only fall through to structural defaults if the DSL returns nothing.
Solution: Create DslStmtSemantics extending DefaultAIRStmtSemantics:
class DslStmtSemantics<T>(
private val analysisDefinition: FairAnalysisDefinition<T>,
exprSemantics: AIRExprSemantics,
heapSemantics: AIRHeapSemantics,
callSemantics: AIRCallSemantics,
) : DefaultAIRStmtSemantics(exprSemantics, heapSemantics, callSemantics) {
override fun translateAssign(context: AIRSemanticsContext, stmt: JAssignStmt): List<AIRStmt> {
val rhs = stmt.rightOp
// Phase 1 callback: ask DSL for expression-level handling
if (rhs is Expr) {
val dest = liftAccessPath(context.sensitivity, stmt.leftOp, context)
val dslResult = analysisDefinition.processExpression(dest, rhs, context)
if (dslResult.isNotEmpty()) return dslResult
}
// Fall through to structural defaults (copy, load, store, constant)
return super.translateAssign(context, stmt)
}
}This is the key integration point: the converter's existing two-pass CFG walk calls translateAssign, which now calls back into the DSL for expression handling. If the DSL has a rule (e.g., source/sink/sanitizer for an invoke, or a custom binop handler), it returns AIRApplyStmts. Otherwise, the existing structural translation (copy, load, store, constant) kicks in unchanged.
Problem: For JInvokeStmt (void calls, not in an assignment), the DSL's invoke handler also needs to be consulted — e.g., a sink call sqlQuery(x) that has no LHS.
Solution: Create DslCallSemantics<T> wrapping AbstractCallSemantics:
class DslCallSemantics<T>(
private val analysisDefinition: FairAnalysisDefinition<T>,
private val delegate: AbstractCallSemantics
) : AIRCallSemantics {
override fun translateInvokeExpr(
destination: AIRAccessPath?,
context: AIRSemanticsContext,
invokeStmt: Stmt,
): List<AIRStmt> {
// Extract the invoke expression
val invokeExpr = extractInvokeExpr(invokeStmt)
// Ask DSL invoke handler first
val dslResult = analysisDefinition.processInvoke(destination, invokeExpr, context)
if (dslResult.isNotEmpty()) return dslResult
// Fall through to standard call handling (call stmt generation, virtual dispatch)
return delegate.translateInvokeExpr(destination, context, invokeStmt)
}
}The processExpression method dispatches on real SootUp expression types:
class FairAnalysisDefinition<T>(
val name: String,
val lattice: Lattice<T>,
private val invokeHandler: InvokeExprHandler<T>,
private val binopHandler: BinaryExprHandler<T>,
// ... all handlers
) {
fun processExpression(
dest: AIRAccessPath?,
expr: Value, // SootUp Value (rhs of assignment)
context: AIRSemanticsContext
): List<AIRStmt> = when (expr) {
is AbstractInvokeExpr -> invokeHandler.process(dest, expr, context)
is AbstractBinopExpr -> binopHandler.process(dest, expr, context)
is JNegExpr -> negHandler.process(dest, expr, context)
is JLengthExpr -> lengthHandler.process(dest, expr, context)
is JCastExpr -> castHandler.process(dest, expr, context)
is JInstanceOfExpr -> instanceOfHandler.process(dest, expr, context)
is JNewExpr -> newHandler.process(dest, expr, context)
is JNewArrayExpr -> newArrayHandler.process(dest, expr, context)
is JNewMultiArrayExpr -> newMultiArrayHandler.process(dest, expr, context)
else -> emptyList() // not an expression the DSL handles → fall through
}
fun processInvoke(
dest: AIRAccessPath?,
invokeExpr: AbstractInvokeExpr,
context: AIRSemanticsContext
): List<AIRStmt> = invokeHandler.process(dest, invokeExpr, context)
}Extend AirTranslationSuite to accept a FairAnalysisDefinition<T> and wire it into semantics:
class AirTranslationSuite<T>(
val view: View,
val callGraph: CallGraph,
val analysisDefinition: FairAnalysisDefinition<T>, // NEW
val wholeProgramContext: WholeProgramContext,
) {
fun lift(
sootMethod: SootMethod,
frameworkType: FrameworkType,
sensitivityType: SensitivityType,
contextStrategy: ContextStrategy,
): AIRBody {
// Build DSL-driven semantics
val heapSemantics = DefaultHeapSemantics()
val baseCallSemantics = when (frameworkType) {
FrameworkType.IFDS -> IFDSCallSemantics()
FrameworkType.MONOTONE -> MonotoneCallSemantics()
else -> IFDSCallSemantics()
}
val dslCallSemantics = DslCallSemantics(analysisDefinition, baseCallSemantics)
val dslExprSemantics = DslExprSemantics(analysisDefinition)
val dslStmtSemantics = DslStmtSemantics(
analysisDefinition, dslExprSemantics, heapSemantics, dslCallSemantics
)
val semantics = DslDrivenSemantics(
dslStmtSemantics, dslExprSemantics, heapSemantics, dslCallSemantics
)
// ... rest as before (context creation, AIRMethodConverter)
}
}The user-facing API looks like:
fun main() {
// 1. Define analysis via DSL
val analysis = fairAnalysis("TaintAnalysis", TaintLattice) {
onInvokeExpr {
source(matching { it.subSignature.name == "getParam" }) {
taintsReturnValue()
}
sink(matching { it.subSignature.name == "sqlQuery" }) {
checksArgument(0) { finding -> println("FINDING: $finding") }
}
sanitizer(matching { it.subSignature.name == "sanitize" }) {
killsTaintOnReturnValue()
}
}
}
// 2. Set up SootUp
val view = SootUpManager.createView(classPath)
val callGraph = SootUpManager.createCallGraph(view, entryPoints)
// 3. Convert to FAIR
val suite = AirTranslationSuite(view, callGraph, analysis, WholeProgramContext())
val airBody = suite.lift(method, FrameworkType.IFDS, SensitivityType.FIELDSENS, ContextStrategy.NONE)
}- Create
DSL-FAIR/withbuild.gradle.kts(single module, SootUp dependencies from FAIR's build file). - Copy
air.coresource tree verbatim intosrc/main/kotlin/air/.
- Create
dsl/Lattice.ktwith FairDSL.kt'sLattice<T>interface (bottom, top, join, meet, leq). - Port DSL's
FlatLattice,MapLattice,LiftLattice,ProductLatticeto the new interface (addmeet/leq). - Keep FairDSL.kt's
Flat<E>sealed class andFlatLattice<E>as well (different use case — three-element flat). - Copy
TaintLatticefrom FairDSL.kt.
- Copy from FairDSL.kt:
DomainOperation<T>,IdentityOp,JoinOp,SetTopOp,SetBottomOp,CheckTopOp. - Copy
AbstractEnvironment<T>,Finding,FindingReporter. - Create
DslOperator<T>wrapper implementingAIROperator.
- Port FairDSL.kt's
ExprHandler<T>hierarchy, replacing mock types with SootUp types. - Each handler's
process()now takes(AIRAccessPath?, Expr/Value, AIRSemanticsContext)and returnsList<AIRStmt>. - Handlers use
LiftValueHelperto convert SootUp values to AIR values. InvokeExprHandlermatchers operate on realsootup.core.signatures.MethodSignature.- Source/sink/sanitizer effect builders unchanged (they produce
DomainOperation<T>instances).
- Copy all
converter/,semantics/,sensitivity/,helper/,rule/files. - Adjust package declarations as needed.
- Create
DslStmtSemantics<T>(extendsDefaultAIRStmtSemantics, overridestranslateAssign). - Create
DslCallSemantics<T>(wraps existing call semantics, intercepts invoke for DSL rules). - Create
DslExprSemantics<T>(implementsAIRExprSemantics, delegates to DSL binop handler). - Create
DslDrivenSemantics<T>(replacesTaintIFDSSemantics, composes the DSL-driven pieces).
- Modify
AirTranslationSuiteto acceptFairAnalysisDefinition<T>and constructDslDrivenSemantics. - Remove
AnalysisPolicyProviderdependency (or keep as fallback for non-DSL usage).
- Create
Main.ktwithdefineTaintAnalysis()example connected to real SootUp. - Add example for constant propagation or typestate to validate genericity.
- Port or create tests.
| Source | File | Action |
|---|---|---|
FAIR/air.core/** |
All files | Copy as-is |
FAIR/src/**/AIRMethodConverter.kt |
Copy as-is | |
FAIR/src/**/AIRWholeProgramConverter.kt |
Copy as-is | |
FAIR/src/**/AirTranslationSuite.kt |
Copy + extend (accept FairAnalysisDefinition) | |
FAIR/src/**/DefaultAIRStmtSemantics.kt |
Copy as-is (DslStmtSemantics extends it) | |
FAIR/src/**/AbstractCallSemantics.kt |
Copy as-is (DslCallSemantics wraps it) | |
FAIR/src/**/IFDSCallSemantics.kt |
Copy as-is (used as delegate) | |
FAIR/src/**/MonotoneCallSemantics.kt |
Copy as-is (used as delegate) | |
FAIR/src/**/IFDSExprSemantics.kt |
Copy as-is (fallback for non-DSL) | |
FAIR/src/**/IFDSAIRStmtSemantics.kt |
Copy as-is (fallback for non-DSL) | |
FAIR/src/**/TaintIFDSSemantics.kt |
Drop (replaced by DslDrivenSemantics) | |
FAIR/src/**/AnalysisPolicyProvider.kt |
Drop (replaced by DSL-driven wiring) | |
FAIR/src/**/AIRSemanticsContext.kt |
Copy as-is (no change needed) | |
FAIR/src/**/AIRSemantics.kt |
Copy as-is | |
FAIR/src/**/BinaryOpFinder.kt |
Copy as-is | |
FAIR/src/**/LiftValueHelper.kt |
Copy as-is | |
FAIR/src/**/AccessPathFactory.kt |
Copy as-is | |
FAIR/src/**/CallGraphIndex.kt |
Copy as-is | |
FAIR/src/**/FoldHelper.kt |
Copy as-is | |
FAIR/src/**/ConversionUtil.kt |
Copy as-is | |
FAIR/src/**/SootUpManager.kt |
Copy as-is | |
FAIR/src/**/WholeProgramContext.kt |
Copy as-is | |
FAIR/src/**/TaintMethodRule.kt |
Copy as-is (kept for compat, DSL replaces) | |
FAIR/src/**/MethodRule.kt |
Copy as-is | |
All other FAIR/src/** utils |
Copy as-is | |
FairDSL.kt §1-9, §11-15 |
Lattice, Ops, Handlers, Builder | Adapt (replace mock types with SootUp) |
FairDSL.kt §10 |
JimpleExpr, MethodSignature | Drop (replaced by real SootUp types) |
FairDSL.kt §16 |
main() demo | Adapt (use real SootUp setup) |
DSL/src/Lattice.kt |
FlatLattice, MapLattice, etc. | Port (add meet/leq to match new interface) |
DSL/src/Models.kt |
Pattern, Effect, FlowRule | Drop |
DSL/src/AnalysisBuilder.kt |
Drop | |
DSL/src/RulesBuilder.kt |
Drop | |
DSL/src/Rules.kt |
Drop (lattice constructors subsumed) | |
DSL/src/Globals.kt |
Drop | |
DSL/src/printAnalysis.kt |
Drop | |
DSL/src/Main.kt |
Drop | |
| — | DslStmtSemantics.kt |
New |
| — | DslCallSemantics.kt |
New |
| — | DslExprSemantics.kt |
New |
| — | DslDrivenSemantics.kt |
New |
| — | DslOperator.kt |
New |
-
Expression-level, not statement-level: The DSL handles expressions. The converter handles statements (copy, load, store, assume, goto). DslStmtSemantics is the bridge.
-
Two-phase callback: At conversion time, the DSL selects DomainOperations and embeds them in AIRApplyStmt. At interpretation time, the interpreter executes those operations against the abstract environment.
-
Generic defaults: If the DSL user doesn't configure a handler, the generic default fires (IdentityOp for unary, JoinOp for binary, SetTopOp for allocation). This makes simple analyses like taint analysis very concise.
-
First-match wins: InvokeExprHandler tries matcher rules sequentially; first match wins. No match → default propagation. This mirrors FairDSL.kt's design.
-
Backward compatibility: Existing FAIR infrastructure (call semantics, heap semantics, fold statements, context handling) is preserved. The DSL adds an expression-level layer on top; it does not replace the structural CFG conversion or context sensitivity mechanisms.