import org.checkerframework.checker.tainting.qual.Untainted open class MethodPropagation { fun test1(dirty: String?, clean: @Untainted String?) { sink(dirty) //warn sink(clean) } private fun recursive(dirty: String?, clean: @Untainted String?): String { if (clean === "") { val a = recursive(dirty, clean) sink(a) //warn return recursive(dirty, clean) } return recursive(clean, clean) } fun test2(dirty: String?, clean: @Untainted String?) { sink(next(dirty)) //warn sink(next(clean)) sink(nextPublic(dirty)) //warn sink(nextPublic(clean)) //warn (public) sink(alwaysClean(dirty)) sink(alwaysClean(clean)) sink(staticNext(dirty)) //warn sink(staticNext(clean)) sink(next(next(clean))) sink(next(next(next(next(next(clean)))))) sink(next(next(next(next(dirty))))) //warn sink(alwaysClean(next(next(next(next(clean)))))) sink(alwaysClean(next(next(next(next(dirty)))))) sink(next(next(next(next(alwaysClean(clean)))))) sink(next(next(next(next(alwaysClean(dirty)))))) sink(next(alwaysClean(clean))) sink(next(alwaysClean(dirty))) val alwaysClean = alwaysClean(next(next(next(clean)))) sink(alwaysClean) val alwaysClean2 = alwaysClean(next(next(next(dirty)))) sink(alwaysClean2) } private fun next(next: String?): String? { return next } private fun alwaysClean(next: String?): String { return "next" } open fun nextPublic(next: String?): String? { return next } companion object { fun staticNext(next: String?): String? { return next } fun sink(string: @Untainted String?) {} } }