package Ġsa ar land . cis pa . frontmatter Ċ Ċ import Ġmu . K Logging Ċ import Ġsa ar land . cis pa . frontmatter . Utils . implements Ċ import Ġsa ar land . cis pa . frontmatter . Utils . is Android Method Ċ import Ġsa ar land . cis pa . frontmatter . Utils . is Dummy Ċ import Ġsa ar land . cis pa . frontmatter . data . Dialog Ċ import Ġsa ar land . cis pa . frontmatter . data . Menu Ċ import Ġsa ar land . cis pa . frontmatter . data . Stmt Site Ċ import Ġsa ar land . cis pa . frontmatter . data . UIElement Ċ import Ġsa ar land . cis pa . frontmatter . data . UI View Element Ċ import Ġsa ar land . cis pa . frontmatter . resolvers . Value Resolver Ċ import Ġsa ar land . cis pa . frontmatter . resolvers . View Id Ċ import Ġso ot . Body Ċ import Ġso ot . Kind Ċ import Ġso ot . Local Ċ import Ġso ot . Ref Type Ċ import Ġso ot . Scene Ċ import Ġso ot . S oot Class Ċ import Ġso ot . S oot Method Ċ import Ġso ot . Unit Ċ import Ġso ot . Value Ċ import Ġso ot . j imple . Assign Stmt Ċ import Ġso ot . j imple . Bin op Expr Ċ import Ġso ot . j imple . Condition Expr Ċ import Ġso ot . j imple . Eq Expr Ċ import Ġso ot . j imple . If Stmt Ċ import Ġso ot . j imple . Int Constant Ċ import Ġso ot . j imple . Invoke Stmt Ċ import Ġso ot . j imple . Lookup Switch Stmt Ċ import Ġso ot . j imple . Ne Expr Ċ import Ġso ot . j imple . New Expr Ċ import Ġso ot . j imple . Stmt Ċ import Ġso ot . j imple . tool k its . call graph . Edge Ċ import Ġso ot . tool k its . graph . Block Ċ import Ġso ot . tool k its . graph . Exception al Block Graph Ċ import Ġso ot . tool k its . graph . Exception al Unit Graph Ċ import Ġso ot . tool k its . graph . Unit Graph Ċ import Ġso ot . tool k its . scalar . Simple Local Defs Ċ import Ġso ot . tool k its . scalar . Simple Local Defs No SS A Ċ import Ġso ot . util . Hash Multi Map Ċ import Ġso ot . util . Multi Map Ċ Ċ data Ġclass ĠBlock Edge ( val Ġsrc : ĠBlock , Ġval Ġtgt : ĠBlock ) Ċ data Ġclass ĠUI Element WithContext ( val Ġview : ĠUI Element , Ġval Ġcontext : ĠActivity Or Fragment Class ) Ċ class ĠCall chain Walker ( val Ġscene V : ĠScene , Ġval Ġapp Model : ĠApp Model , Ġval Ġvalue Resolver : ĠValue Resolver ) Ġ{ ĊĠĠĠ Ġcompanion Ġobject Ġ: ĠK Logging () ĊĊĠĠĠ Ġval Ġic fg Ġ= Ġvalue Resolver . ic fg ĊĠĠĠ Ġval Ġcall graph Ġ= Ġic fg . call Graph ĊĠĠĠ Ġprivate Ġval Ġview Class Ġ= Ġscene V . getS oot Class (" android . view . View ") ĊĠĠĠ Ġprivate Ġval Ġmenu Class Ġ= Ġscene V . getS oot Class (" android . view . MenuItem ") ĊĠĠĠ Ġprivate Ġval Ġui Callback Methods : ĠMulti Map < String , ĠS oot Method > ĊĊĠĠĠ Ġprivate Ġval Ġlisteners To UI : ĠMulti Map < S oot Method , ĠUI Element WithContext > Ġ= ĠHash Multi Map () ĊĊĠĠĠ Ġinit Ġ{ ĊĠĠĠĠĠĠĠ Ġfor Ġ(( activity , Ġlayout ) Ġin Ġapp Model . activity Layouts ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcollect Layout Listeners ( layout . ui View Element , Ġactivity ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġfor Ġ(( activity , Ġlayout ) Ġin Ġapp Model . orphan ed Fragment Layouts ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcollect Layout Listeners ( layout , Ġactivity ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġfor Ġ(( activity , Ġmenu ) Ġin Ġapp Model . activity Menus ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcollect Menu Listeners ( menu , Ġactivity ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġfor Ġ(( activity , Ġdialog ) Ġin Ġapp Model . activity Dialog s ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcollect Dialog Listeners ( dialog , Ġactivity ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġui Callback Methods Ġ= Ġlisteners To UI . keySet (). map Ġ{ Ġit . sub Signature Ġto Ġit Ġ}. to Multi Map () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġcollect Layout Listeners ( layout : ĠUIView Element , Ġactivity : ĠActivity Class ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġui Elements Ġ= Ġlayout . getAll Children Flatten () ĊĠĠĠĠĠĠĠ Ġfor Ġ( ui Element Ġin Ġui Elements ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġui Element . listeners . forEach Ġ{ Ġlisteners To UI . put ( it , ĠUI Element WithContext ( ui Element , Ġactivity )) Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġcollect Menu Listeners ( menu : ĠMenu , Ġactivity : ĠActivity Class ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġmenu Items Ġ= Ġmenu . getAll Items () ĊĠĠĠĠĠĠĠ Ġfor Ġ( menuItem Ġin Ġmenu Items ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( menu . listener Ġ!= Ġnull ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlisteners To UI . put ( menu . listener , ĠUI Element WithContext ( menuItem , Ġactivity )) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġcollect Dialog Listeners ( dialog : ĠDialog , Ġactivity : ĠActivity Class ) Ġ{ ĊĊĠĠĠĠĠĠĠ Ġval Ġbuttons Ġ= Ġdialog . buttons ĊĠĠĠĠĠĠĠ Ġfor Ġ( button Ġin Ġbuttons ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġbutton . listener . forEach Ġ{ Ġlisteners To UI . put ( it , ĠUI Element WithContext ( button , Ġactivity )) Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* Ġresolve ĠUI Ġview Ġwhich Ġtriggers Ġstmt Site Ġcall ĊĠĠĠĠ Ġ* Ġ*/ ĊĠĠĠ Ġfun Ġget UIT rigger Of Call ( stmt Site : ĠStmt Site ): ĠSet < UIElement WithContext > Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġcallbacks Ġ= Ġtrace To Callback ( stmt Site ) Ġ// Ġget Ġa Ġcallback ĊĠĠĠĠĠĠĠ Ġreturn Ġcallbacks . flatMap Ġ{ Ġresolve View For Callback ( it ) Ġ}. toSet () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* Ġidentify Ġthe Ġview Ġto Ġwhich Ġthis Ġcallback Ġbelongs ĊĠĠĠĠ Ġ* Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġresolve View For Callback ( callback Site : ĠStmt Site ): ĠList < UIElement WithContext > Ġ{ ĊĠĠĠĠĠĠĠ Ġ// Ġ 2 ) Ġcheck Ġif Ġthere Ġis Ġcondition Ġor Ġlookup Ġtable Ġwith Ġview Id ĊĠĠĠĠĠĠĠ Ġval Ġ( target View Id , Ġexcluded Ids ) Ġ= Ġfind View Ids In Conditions ( callback Site ) ĊĠĠĠĠĠĠĠ Ġ// Ġ 3 ) Ġbind Ġcallback Ġwith ĠUI ĊĠĠĠĠĠĠĠ Ġval Ġcallback Method Ġ= Ġcallback Site . method Ġ// TODO : Ġinterfaces Ġand Ġinheritance ĊĠĠĠĠĠĠĠ Ġval Ġui Elements Ġ= Ġlisteners To UI [ callback Method ] ĊĠĠĠĠĠĠĠ Ġif Ġ( ui Elements . isEmpty ()) Ġlogger . warn (" Missing Ġui Ġelement Ġfor Ġ$ callback Method ") ĊĠĠĠĠĠĠĠ Ġreturn Ġif Ġ( target View Id Ġ== Ġ 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġui Elements . filter Not Ġ{ Ġit . view . id Ġin Ġexcluded Ids Ġ} ĊĠĠĠĠĠĠĠ Ġelse ĊĠĠĠĠĠĠĠĠĠĠĠ Ġui Elements . filter Ġ{ Ġit . view . id Ġ== Ġtarget View Id Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġfind View Ids In Conditions ( callback Site : ĠStmt Site ): ĠPair < Int , ĠSet < Int >> Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġunit Graph Ġ= Ġic fg . get OrCreate Unit Graph ( callback Site . method ) Ġas ĠException al Unit Graph ĊĠĠĠĠĠĠĠ Ġval Ġdefs Ġ= ĠSimple Local Defs No SS A ( unit Graph ) ĊĠĠĠĠĠĠĠ Ġval Ġblock Graph Ġ= ĠException al Block Graph ( unit Graph ) ĊĠĠĠĠĠĠĠ Ġval Ġblock Ġ= Ġget Target Block ( block Graph , Ġcallback Site . stmt ) ĊĠĠĠĠĠĠĠ Ġreturn Ġgo Around Block Graph ( block , Ġdefs ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* Ġidentify Ġthe Ġcallback Ġmethod Ġfrom Ġwhich Ġthe Ġstmt Site Ġcall Ġoccured ĊĠĠĠĠ Ġ* Ġtraverse Ġthe Ġcall graph Ġfrom Ġstmt Site Ġcall Ġtill Ġthe Ġcallback Ġmethod ĊĠĠĠĠ Ġ* Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġtrace To Callback ( stmt Site : ĠStmt Site ): ĠSet < Stmt Site > Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġmethod Ġ= Ġstmt Site . method ĊĠĠĠĠĠĠĠ Ġif Ġ( is Callback ( method )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġset Of ( stmt Site ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġval Ġwork List Ġ= Ġmutable ListOf < S oot Method >() ĊĠĠĠĠĠĠĠ Ġval Ġvisited Nodes Ġ= Ġmutable Set Of ( method ) ĊĠĠĠĠĠĠĠ Ġval Ġcallback Nodes Ġ= Ġmutable Set Of < Stmt Site >() ĊĠĠĠĠĠĠĠ Ġwork List . add ( method ) ĊĠĠĠĠĠĠĠ Ġvisited Nodes . add ( method ) ĊĠĠĠĠĠĠĠ Ġwhile Ġ( work List . isNotEmpty ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġnode Ġ= Ġwork List . remove At ( 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvisited Nodes . add ( node ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġedges Ġ= Ġcall graph . edges Into ( node ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. as Sequence () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Not Ġ{ Ġit . src (). is Android Method () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Not Ġ{ Ġit . src (). is Dummy () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Not Ġ{ Ġit . src () Ġin Ġvisited Nodes Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Not Ġ{ Ġit . src () Ġin Ġwork List Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. toSet () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġedges . forEach Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( is Callback ( it . src ())) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcallback Nodes . add ( Stmt Site ( it . src Stmt (), Ġit . src ())) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwork List . add ( it . src ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġreturn Ġcallback Nodes ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġis Callback ( method : ĠS oot Method ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġmethod . sub Signature Ġin Ġui Callback Methods ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* Ġreturn Ġblocks Ġthat Ġcontain Ġthe Ġcal lee ĊĠĠĠĠ Ġ* Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġget Target Blocks ( block Graph : ĠException al Block Graph , Ġcal lee : ĠS oot Method ): ĠList < Block > Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġblock Graph . blocks . filter Ġ{ ĠisIn Block ( it , Ġcal lee ) Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* Ġreturn Ġblock Ġthat Ġcontain Ġthe Ġstmt ĊĠĠĠĠ Ġ* Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġget Target Block ( block Graph : ĠException al Block Graph , Ġstmt : ĠStmt ): ĠBlock Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġblock Graph . blocks . first Ġ{ ĠisIn Block ( it , Ġstmt ) Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* Ġcheck Ġif Ġthe Ġstatement Ġis Ġin Ġthe Ġbody Ġof Ġa Ġblock ĊĠĠĠĠ Ġ* Ġ*/ ĊĠĠĠ Ġprivate Ġfun ĠisIn Block ( block : ĠBlock , Ġstmt : ĠUnit ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġblock . iterator (). as Sequence () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. any Ġ{ Ġit Ġ== Ġstmt Ġ} ĊĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* Ġcheck Ġif Ġthe Ġcal lee Ġis Ġin Ġthe Ġbody Ġof Ġa Ġblock ĊĠĠĠĠ Ġ* Ġ*/ ĊĠĠĠ Ġprivate Ġfun ĠisIn Block ( block : ĠBlock , Ġcal lee : ĠS oot Method ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġblock . iterator (). as Sequence () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Is Instance < Stmt >() ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Ġ{ Ġit . contains Invoke Expr () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. any Ġ{ Ġit . invoke Expr . method Ġ== Ġcal lee Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠFIXME : Ġcheck Ġthe Ġpurpose ĊĠĠĠĠ Ġ* Ġcallback Ġcan Ġbe Ġassign et Ġto Ġmultiple Ġviews ĊĠĠĠĠ Ġ* Ġexpect Ġview Ġresolution Ġby Ġview Ġid ĊĠĠĠĠ Ġ* Ġcheck Ġif Ġview Id Ġis Ġencountered Ġin Ġif Ġconditions ĊĠĠĠĠ Ġ* ĠXXX : Ġrefactor , Ġit Ġcan Ġover approx imate ĊĠĠĠĠ Ġ* Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġis Multi Callback ( callback : ĠS oot Method ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġbody Ġ= Ġcallback . active Body ĊĠĠĠĠĠĠĠ Ġval Ġview Id St mts Ġ= Ġget View Id Stmt ( body ) ĊĠĠĠĠĠĠĠ Ġval Ġview Id Vars Ġ= Ġview Id St mts . map Ġ{ Ġit . left Op Ġ} Ċ // ĠĠĠĠĠĠĠ Ġif Ġ( view Id Is Arg ( body )) Ġreturn Ġfalse Ġ// ĠTODO : Ġpropagate Ġone Ġlevel Ġdown ĊĠĠĠĠĠĠĠ Ġreturn Ġbody . units . as Sequence () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Is Instance < If Stmt >() Ġ// ĠTODO : Ġadd Ġlookup Ġswitch ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. map Ġ{ Ġit . condition Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Is Instance < Bin op Expr >() ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Ġ{ Ġit Ġis ĠEq Expr Ġ|| Ġit Ġis ĠNe Expr Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. flatMap Ġ{ Ġsequence Of ( it . op 1 , Ġit . op 2 ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. any Ġ{ Ġit Ġin Ġview Id Vars Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ// FIX ME : Ġcheck ĊĠĠĠ Ġfun Ġtrace To View Id ( callback : ĠS oot Method , Ġmethod : ĠS oot Method ): ĠSet < Int > Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ(! is Multi Callback ( callback )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġset Of ( 0 ) ĊĠĠĠĠĠĠĠ Ġval Ġunit Graph Ġ= Ġic fg . get OrCreate Unit Graph ( callback ) Ġas ĠException al Unit Graph ĊĠĠĠĠĠĠĠ Ġval Ġdefs Ġ= ĠSimple Local Defs No SS A ( unit Graph ) ĊĠĠĠĠĠĠĠ Ġval Ġblock Graph Ġ= ĠException al Block Graph ( unit Graph ) ĊĠĠĠĠĠĠĠ Ġval Ġblocks Ġ= Ġget Target Blocks ( block Graph , Ġmethod ) ĊĠĠĠĠĠĠĠ Ġreturn Ġblocks . map Ġ{ Ġgo Around Block Graph ( it , Ġdefs ). first Ġ}. toSet () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* Ġidentify Ġview Id Ġfrom Ġfind view ById Ġby Ġtracing Ġback Ġfrom Ġset ### Listener ĊĠĠĠĠ Ġ* Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġfind View Id ( edge To Assign Listener Site : ĠEdge , Ġcallback Class : ĠS oot Class ): ĠList < View Id > Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġclick Stmt Ġ= Ġedge To Assign Listener Site . src Stmt () ĊĠĠĠĠĠĠĠ Ġval Ġclick Method Ġ= Ġedge To Assign Listener Site . src () ĊĠĠĠĠĠĠĠ Ġif Ġ( edge To Assign Listener Site . kind (). is Interface ()) Ġ{ Ġ// XXX : Ġspecial Invoke Ġmay Ġbe Ġrequired Ġas Ġwell ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġresolve Ġby Ġtype Ġif Ġpossible ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcalling Context Sites Ġ= Ġvalue Resolver . resolve Invoker Base ( Stmt Site ( click Stmt , Ġclick Method ), Ġnull ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcalling Context Ġ= Ġcalling Context Sites ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Ġ{ Ġ((( it . stmt Ġas ? ĠAssign Stmt )?. right Op Ġas ? ĠNew Expr )?. type Ġas ? ĠRef Type )?. so ot Class Ġ== Ġcallback Class Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. toSet () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . info ("${ calling Context . size }") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// TODO : Ġcomplete ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġval Ġinvoke Expr Ġ= Ġclick Stmt . invoke Expr ĊĠĠĠĠĠĠĠ Ġval Ġview Ġ= Ġinvoke Expr . args ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Ġ{ Ġit . type Ġis ĠRef Type Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. first OrNull () Ġ{ Ġscene V . implements (( it . type Ġas ĠRef Type ). so ot Class , Ġview Class ) Ġ} Ġ?: Ġreturn Ġempty List () ĊĠĠĠĠĠĠĠ Ġval Ġview Allocation Ġ= Ġvalue Resolver . resolve Var ( view , ĠStmt Site ( click Stmt , Ġclick Method ), Ġnull ) ĊĠĠĠĠĠĠĠ Ġval Ġview New Expr Ġ= Ġview Allocation . filter Ġ{ Ġit . stmt Ġis ĠAssign Stmt Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. first OrNull Ġ{ Ġ( it . stmt Ġas ĠAssign Stmt ). right Op Ġis ĠNew Expr Ġ} Ġ// XXX : Ġwe Ġassume Ġthere Ġis Ġonly Ġone Ġnew Expression Ġ( there Ġmay Ġbe Ġno Ġnew ĠExpr ) ĊĠĠĠĠĠĠĠ Ġif Ġ( view New Expr Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . warn (" Bind Callback : ĠMissing Ġnew Expr Ġfor Ġ${ view Allocation . join ToString ("; Ġ" )} ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġempty List () ĊĠĠĠĠĠĠĠ Ġ} Ċ // ĠĠĠĠĠĠĠ Ġval Ġfind View Stmt Ġ= Ġic fg . get Pred s Of ( view New Expr . stmt ). first () Ġ// ĠXXX : Ġis Ġit Ġsafe Ġto Ġuse Ġbody Ġinstead Ġof Ġcontrol Ġflow Ġgraph ĊĠĠĠĠĠĠĠ Ġval Ġfind View Stmt Ġ= Ġview New Expr . method . active Body . units . get Pred Of ( view New Expr . stmt ) Ġas ĠStmt Ġ// ĠfindViewById Ġshould Ġbe Ġright Ġbefore Ġnew Expr ĊĠĠĠĠĠĠĠ Ġif Ġ(!( find View Stmt . contains Invoke Expr () Ġ&& Ġfind View Stmt . invoke Expr . method . name Ġ== ĠF IND _ VIEW _ METHOD _ NAME )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . warn (" Bind Callback : ĠCould Ġnot Ġfind ĠfindViewById Ġcall Ġfor Ġ$ view New Expr , Ġfound : Ġ${ find View Stmt }") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġempty List () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ ĠTODO (" remove ") ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ// XXX : ĠNo Ġwe Ġconsider Ġonly Ġcases Ġwhen Ġa ĠView . getId Ġis Ġcalled Ġdirectly ĊĠĠĠ Ġ// Ġwe Ġfail Ġif Ġview Id Ġis Ġa Ġmethod Ġparameter ĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* Ġwalk Ġback Ġthe Ġblock Ġgraph Ġfrom Ġtarget Block Ġto Ġthe Ġentry Ġpoint Ġof Ġthe Ġmethod , Ġcollect Ġconditions Ġwhich Ġcontain Ġview Ids ĊĠĠĠĠ Ġ* Ġ@ return Ġa Ġpair Ġof Ġ< view Id , Ġset Ġof Ġids Ġwhich Ġshould Ġbe Ġexcluded > ĊĠĠĠĠ Ġ* Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġgo Around Block Graph ( target Block : ĠBlock , Ġlocal Defs : ĠSimple Local Defs No SS A ): ĠPair < Int , ĠSet < Int >> Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġwork List Ġ= Ġmutable ListOf < Block Edge >() ĊĠĠĠĠĠĠĠ Ġval Ġvisit edList Ġ= Ġmutable ListOf ( target Block ) ĊĠĠĠĠĠĠĠ Ġval Ġexcluded Ids Ġ= Ġmutable Set Of < Int >() ĊĠĠĠĠĠĠĠ Ġwork List . addAll ( target Block . preds . map Ġ{ ĠBlock Edge ( it , Ġtarget Block ) Ġ}) ĊĠĠĠĠĠĠĠ Ġwhile Ġ( work List . isNotEmpty ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcurrent Block Edge Ġ= Ġwork List . remove At ( 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcurrent Block Ġ= Ġcurrent Block Edge . src ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvisit edList . add ( current Block ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ( val Ġtail Ġ= Ġcurrent Block . tail ) Ġ{ Ġ// look Ġat Ġthe Ġlast Ġstmt Ġof Ġa Ġblock ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠIf Stmt Ġ-> Ġ{// check Ġif Ġcondition Ġcontains Ġview Id Ġreference ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcondition Ġ= Ġtail . condition ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( condition Ġis ĠCondition Expr ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġleft Side Is View Id Ġ= Ġis View Id ( condition . op 1 , Ġtail , Ġlocal Defs ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġright Side Is View Id Ġ= Ġis View Id ( condition . op 2 , Ġtail , Ġlocal Defs ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( left Side Is View Id Ġ|| Ġright Side Is View Id ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġ(_, Ġview Id ) Ġ= Ġget View Id From Condition ( tail . condition ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( is Eq Branch Block ( tail , Ġcurrent Block Edge . tgt ) Ġ&& Ġview Id Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠPair ( view Id , Ġexcluded Ids ) Ġ// XXX : Ġwe Ġassume Ġthis Ġis Ġa Ġhit Ġand Ġdon 't Ġpropagate Ġfurther ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġview Id ?. let Ġ{ Ġexcluded Ids . add ( it ) Ġ} Ġ// Ġupdate Ġlist Ġof ĠView Ids Ġthat Ġdon 't Ġtrigger Ġthat Ġblock ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġelse Ġpropagate Ġfurther ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwork List . addAll ( current Block . preds . filter Ġ{ Ġit Ġ! in Ġvisit edList Ġ}. map Ġ{ ĠBlock Edge ( it , Ġcurrent Block ) Ġ}) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠLookup Switch Stmt Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( is View Id ( tail . key , Ġtail , Ġlocal Defs )) Ġ{ ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġview Id Ġ= Ġtail . targets . with Index () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Ġ{ Ġ(_, Ġtarget ) Ġ-> Ġtarget Ġ== Ġcurrent Block Edge . tgt . head Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. map Ġ{ Ġ( index , Ġ_) Ġ-> Ġtail . get Lookup Value ( index ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. first OrNull () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġlookup Values Ġ= Ġtail . lookup Values . map Ġ{ Ġit . value Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexcluded Ids . addAll ( lookup Values ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexcluded Ids . remove ( view Id ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( view Id Ġ!= Ġnull ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠPair ( view Id , Ġexcluded Ids ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġelse Ġwe Ġhit Ġdefault Ġbranch Ġof Ġlookup Stmt ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwork List . addAll ( current Block . preds . filter Ġ{ Ġit Ġ! in Ġvisit edList Ġ}. map Ġ{ ĠBlock Edge ( it , Ġcurrent Block ) Ġ}) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġ// Ġtake Ġall Ġblocks , Ġpropagate Ġup ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwork List . addAll ( current Block . preds . filter Ġ{ Ġit Ġ! in Ġvisit edList Ġ}. map Ġ{ ĠBlock Edge ( it , Ġcurrent Block ) Ġ}) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġreturn ĠPair ( 0 , Ġexcluded Ids ) ĊĠĠĠ Ġ} ĊĊĊĠĠĠ Ġprivate Ġfun Ġis De cid ing Condition ( condition : ĠValue , Ġview Id Vars : ĠList < Value >): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġ( condition Ġis ĠEq Expr Ġ|| Ġcondition Ġis ĠNe Expr ) Ġ&& Ġ( condition Ġis ĠBin op Expr ) Ġ&& Ġ( condition . op 1 Ġin Ġview Id Vars Ġ|| Ġcondition . op 2 Ġin Ġview Id Vars ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* Ġcheck Ġif Ġthe Ġvalue Ġis Ġinitialized Ġwith ĠView . getId Ġmethod ĊĠĠĠĠ Ġ* Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġis View Id ( value : ĠValue , Ġunit : ĠUnit , Ġlocal Defs : ĠSimple Local Defs ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( value Ġ! is ĠLocal ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġfalse ĊĠĠĠĠĠĠĠ Ġval Ġdefs Of Condition Ġ= Ġlocal Defs . get Defs Of At ( value , Ġunit ) ĊĠĠĠĠĠĠĠ Ġreturn Ġdefs Of Condition . filter Is Instance < Assign Stmt >() ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Ġ{ Ġit . contains Invoke Expr () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. any Ġ{ Ġit . invoke Expr . method . signature Ġin ĠgetId Signatures Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* Ġwe Ġassume Ġthat Ġthere Ġis Ġjust Ġone ĠgetId Ġcall Ġinside ĠonClick ( View ) ĊĠĠĠĠ Ġ* Ġwhich Ġis Ġreasonable Ġbut Ġmay Ġnot Ġhold ĠTODO : Ġsupport Ġfor Ġmultiple ĠgetId () ĊĠĠĠĠ Ġ* Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġget View Id Stmt ( body : ĠBody ): ĠList < Assign Stmt > Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġbody . units . as Sequence () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Is Instance < Assign Stmt >() ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Ġ{ Ġit . contains Invoke Expr () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Ġ{ Ġit . invoke Expr . method . signature Ġin ĠgetId Signatures Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. toList () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Deprecated (" unused ") ĊĠĠĠ Ġfun Ġresolve Callback Units ById ( callback : ĠS oot Method , Ġview Id : ĠInt ): ĠList < Unit > Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġbody Ġ= Ġcallback . active Body ĊĠĠĠĠĠĠĠ Ġvar Ġview Var Ġ= Ġget View Param ( body ) ĊĠĠĠĠĠĠĠ Ġif Ġ( view Var Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . warn (" No Ġappropriate Ġparam Ġfound Ġin Ġ$ callback ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġempty List () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġval Ġview Id Val Ġ= ĠInt Constant . v ( view Id ) ĊĠĠĠĠĠĠĠ Ġval Ġunit Graph Ġ= Ġic fg . get OrCreate Unit Graph ( callback ) Ġas ĠUnit Graph ĊĠĠĠĠĠĠĠ Ġval Ġentry Units Ġ= Ġmutable ListOf < Unit >() ĊĠĠĠĠĠĠĠ Ġval Ġvisited Units Ġ= Ġmutable Set Of < Unit >() ĊĠĠĠĠĠĠĠ Ġval Ġwalk List Ġ= Ġmutable ListOf < Unit >( unit Graph . heads . single ()) ĊĊĠĠĠĠĠĠĠ Ġwhile Ġ( walk List . isNotEmpty ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġunit Ġ= Ġwalk List . remove At ( 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( unit Ġin Ġvisited Units ) Ġcontinue ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvisited Units . add ( unit ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( unit Ġis ĠAssign Stmt Ġ&& Ġunit . contains Invoke Expr ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( unit . invoke Expr . method . signature Ġin ĠgetId Signatures ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġview Var Ġ= Ġunit . left Op Ġas ĠLocal ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġentry Units . add ( unit ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( unit Ġis ĠInvoke Stmt ) Ġentry Units . add ( unit ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsuc cs Ġ= Ġunit Graph . get Suc cs Of ( unit ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( unit Ġis ĠIf Stmt ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcondition Ġ= Ġunit . condition ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġif Target Ġ= Ġunit . target ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( condition Ġis ĠEq Expr Ġ&& Ġ( condition . op 1 Ġ== Ġview Var Ġ|| Ġcondition . op 2 Ġ== Ġview Var )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( condition . op 1 Ġ== Ġview Id Val Ġ|| Ġcondition . op 2 Ġ== Ġview Id Val ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwalk List . add ( if Target ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontinue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( condition . op 1 Ġis ĠInt Constant Ġ|| Ġcondition . op 2 Ġis ĠInt Constant ) Ġ{ Ġ// exclude Ġonly Ġbranches Ġwhich Ġfor Ġsure Ġare Ġfor Ġother Ġviews , Ġotherwise Ġover approx imate ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsuc cs . filter Not To ( walk List ) Ġ{ Ġit Ġ== Ġif Target Ġ} Ġ// add Ġto Ġwalk list ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontinue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwalk List . addAll ( suc cs ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġreturn Ġentry Units ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġget Reach able Android Methods ( root : ĠUnit ): ĠSet < S oot Method > Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġroot Method Ġ= Ġcall graph . edges OutOf ( root ). as Sequence (). single (). tgt () ĊĠĠĠĠĠĠĠ Ġval Ġvisited Methods Ġ= Ġmutable Set Of < S oot Method >() ĊĠĠĠĠĠĠĠ Ġval Ġreachable Android Methods Ġ= Ġmutable Set Of < S oot Method >() ĊĠĠĠĠĠĠĠ Ġval Ġwalk List Ġ= Ġmutable ListOf < S oot Method >( root Method ) ĊĠĠĠĠĠĠĠ Ġwhile Ġ( walk List . isNotEmpty ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġmethod Ġ= Ġwalk List . remove At ( 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvisited Methods . add ( method ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcal le es Ġ= Ġcall graph . edges OutOf ( method ). as Sequence () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. map Ġ{ Ġit . tgt () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Not Ġ{ Ġit Ġin Ġvisited Methods Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcal le es . filter Not To ( walk List ) Ġ{ Ġit . is Android Method () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcal le es . filter To ( reachable Android Methods ) Ġ{ Ġit . is Android Method () Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġreturn Ġreachable Android Methods ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠEntry Ġmethod Ġcan Ġbe : ĊĠĠĠĠ Ġ* Ġ- Ġa Ġcallback ĊĠĠĠĠ Ġ* Ġ- Ġa Ġcall Ġmethod Ġof ĠRunnable Ġ( or Ġsimilar Ġasync Ġclass , Ġlike Ġdo In Background ) Ġ( unless Ġwe Ġpatched Ġthem ) ĊĠĠĠĠ Ġ* Ġ*/ ĊĠĠĠ Ġ@ Deprecated (" unused ") ĊĠĠĠ Ġfun Ġget Entry Methods ( stmt Site : ĠStmt Site ): ĠList < S oot Method > Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġmethod Ġ= Ġstmt Site . method ĊĠĠĠĠĠĠĠ Ġif Ġ( is Entry ( method )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠlistOf ( method ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġval Ġentry Methods Ġ= Ġmutable ListOf < S oot Method >() ĊĠĠĠĠĠĠĠ Ġval Ġvisited Methods Ġ= Ġmutable Set Of < S oot Method >() Ġ// prevent Ġrecursion ĊĠĠĠĠĠĠĠ Ġval Ġwalk List Ġ= Ġmutable ListOf < S oot Method >( method ) ĊĠĠĠĠĠĠĠ Ġwhile Ġ( walk List . isNotEmpty ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġtgt Ġ= Ġwalk List . remove At ( 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvisited Methods . add ( tgt ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcall ers Ġ= Ġcall graph . edges Into ( tgt ). as Sequence () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. map Ġ{ Ġit . src () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Not Ġ{ Ġit . is Dummy () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Not Ġ{ Ġit . is Android Method () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Not Ġ{ Ġit Ġin Ġvisited Methods Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. toList () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcall ers . filter To ( entry Methods ) Ġ{ Ġis Entry ( it ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwalk List . addAll ( call ers ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġreturn Ġentry Methods ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠEntry Ġmethod Ġcan Ġbe : ĊĠĠĠĠ Ġ* Ġ- Ġa Ġcallback ĊĠĠĠĠ Ġ* Ġ- Ġa Ġcall Ġmethod Ġof ĠRunnable Ġ( or Ġsimilar Ġasync Ġclass , Ġlike Ġdo In Background ) Ġ( unless Ġwe Ġpatched Ġthem ) ĊĠĠĠĠ Ġ* Ġ*/ ĊĠĠĠ Ġfun Ġget Call ers Al ong Call chain ( stmt Site : ĠStmt Site , Ġis Target : Ġ( S oot Class ) Ġ-> ĠBoolean ): ĠList < S oot Class > Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġmethod Ġ= Ġstmt Site . method ĊĠĠĠĠĠĠĠ Ġif Ġ( is Target ( method . decl aring Class ) Ġ&& Ġ! method . is Static ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠlistOf ( method . decl aring Class ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġval Ġentry Methods Ġ= Ġmutable ListOf < S oot Method >() ĊĠĠĠĠĠĠĠ Ġval Ġvisited Methods Ġ= Ġmutable Set Of < S oot Method >() Ġ// prevent Ġrecursion ĊĠĠĠĠĠĠĠ Ġval Ġwalk List Ġ= Ġmutable ListOf < S oot Method >( method ) ĊĠĠĠĠĠĠĠ Ġwhile Ġ( walk List . isNotEmpty ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġtgt Ġ= Ġwalk List . remove At ( 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvisited Methods . add ( tgt ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcall ers Ġ= Ġcall graph . edges Into ( tgt ). as Sequence () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. map Ġ{ Ġit . src () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Not Ġ{ Ġit . is Dummy () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Not Ġ{ Ġit . is Android Method () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Not Ġ{ Ġit Ġin Ġvisited Methods Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. toList () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġtarget Call ers Ġ= Ġcall ers . filter Ġ{ Ġis Target ( it . decl aring Class ) Ġ}. map Ġ{ Ġit . decl aring Class Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( target Call ers . isNotEmpty ()) Ġreturn Ġtarget Call ers Ġ// FIX ME ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcall ers . filter To ( entry Methods ) Ġ{ Ġis Entry ( it ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcall ers . filter Not To ( walk List ) Ġ{ Ġit . is Dummy () Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġreturn Ġempty List () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġis Entry ( m : ĠS oot Method ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġcall graph . edges Into ( m ). as Sequence () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. map Ġ{ Ġit . src () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Not Ġ{ Ġit . is Dummy () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. none () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* Ġget Ġlocal Ġassociated Ġwith ĠView Ġparam Ġof Ġthe Ġmethod ĊĠĠĠĠ Ġ* Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġget View Param ( body : ĠBody ): ĠLocal ? Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġbody . parameter Local s ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. first OrNull Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġtype Ġ= Ġit . type Ġas ? ĠRef Type ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( type Ġ!= Ġnull ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġscene V . implements ( type . so ot Class , Ġview Class ) Ġ|| Ġscene V . implements ( type . so ot Class , Ġmenu Class ) Ġelse Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġis Eq Branch Block ( if Stmt : ĠIf Stmt , Ġnext Block : ĠBlock ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġcondition Ġ= Ġif Stmt . condition ĊĠĠĠĠĠĠĠ Ġif Ġ( condition Ġ! is ĠEq Expr Ġ&& Ġcondition Ġ! is ĠNe Expr ) Ġreturn Ġfalse ĊĠĠĠĠĠĠĠ Ġval Ġtarget Ġ= Ġif Stmt . target ĊĠĠĠĠĠĠĠ Ġreturn Ġtarget Ġ== Ġnext Block . head ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġget Block Branches ( block : ĠBlock ): ĠPair < Block , ĠBlock > Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġtail Ġ= Ġblock . tail ĊĠĠĠĠĠĠĠ Ġrequire ( tail Ġis ĠIf Stmt ) ĊĠĠĠĠĠĠĠ Ġval Ġcondition Ġ= Ġtail . condition ĊĠĠĠĠĠĠĠ Ġrequire ( condition Ġis ĠEq Expr Ġ|| Ġcondition Ġis ĠNe Expr ) ĊĠĠĠĠĠĠĠ Ġval Ġnext Blocks Ġ= Ġblock . suc cs ĊĠĠĠĠĠĠĠ Ġval Ġtarget Ġ= Ġtail . target ĊĠĠĠĠĠĠĠ Ġreturn Ġwhen Ġ( condition ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠEq Expr Ġ-> ĠPair ( next Blocks . first Ġ{ Ġit . head Ġ== Ġtarget Ġ}, Ġnext Blocks . first Ġ{ Ġit . head Ġ!= Ġtarget Ġ}) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠNe Expr Ġ-> ĠPair ( next Blocks . first Ġ{ Ġit . head Ġ!= Ġtarget Ġ}, Ġnext Blocks . first Ġ{ Ġit . head Ġ== Ġtarget Ġ}) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġerror (" Un reachable Ġstate ") ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* Ġparse Ġcondition Ġand Ġreturn Ġ< view Id Variable , Ġint Ġvalue > Ġpair ĊĠĠĠĠ Ġ* Ġcurrently Ġsupporting Ġconstant Ġintegers Ġonly ĊĠĠĠĠ Ġ* Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġget View Id From Condition ( condition : ĠValue ): ĠPair < Value ?, ĠInt ?> Ġ{ ĊĠĠĠĠĠĠĠ Ġrequire ( condition Ġis ĠCondition Expr ) ĊĠĠĠĠĠĠĠ Ġval Ġop 1 Ġ= Ġcondition . op 1 ĊĠĠĠĠĠĠĠ Ġval Ġop 2 Ġ= Ġcondition . op 2 ĊĠĠĠĠĠĠĠ Ġif Ġ( op 1 Ġis ĠInt Constant ) Ġ// FIX ME : Ġadd Ġstatic Field Ref ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠPair ( op 2 , Ġop 1 . value ) ĊĠĠĠĠĠĠĠ Ġif Ġ( op 2 Ġis ĠInt Constant ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠPair ( op 1 , Ġop 2 . value ) ĊĠĠĠĠĠĠĠ Ġreturn ĠPair ( null , Ġnull ) ĊĊĠĠĠ Ġ} Ċ } Ċ Ċ private Ġfun ĠKind . is Interface (): ĠBoolean Ġ= Ġthis Ġ== ĠKind . INTERFACE Ċ