/* Ċ Ġ* ĠCopyright Ġ( C ) Ġ 2 0 1 6 ĠThe ĠAndroid ĠOpen ĠSource ĠProject Ċ Ġ* Ċ Ġ* Ġ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 Ġcom . android . tools . lint . checks Ċ Ċ import Ġcom . android . Sdk Constants . CLASS _ APPLICATION Ċ import Ġcom . android . Sdk Constants . CLASS _ CONTEXT Ċ import Ġcom . android . Sdk Constants . CLASS _ FRAGMENT Ċ import Ġcom . android . Sdk Constants . CLASS _ VIEW Ċ import Ġcom . android . tools . lint . client . api . Java Evaluator Ċ import Ġcom . android . tools . lint . client . api . U Element Handler Ċ import Ġcom . android . tools . lint . detector . api . Category Ċ import Ġcom . android . tools . lint . detector . api . Detector Ċ import Ġcom . android . tools . lint . detector . api . Implementation Ċ import Ġcom . android . tools . lint . detector . api . Issue Ċ import Ġcom . android . tools . lint . detector . api . Java Context Ċ import Ġcom . android . tools . lint . detector . api . Location Ċ import Ġcom . android . tools . lint . detector . api . Scope Ċ import Ġcom . android . tools . lint . detector . api . Severity Ċ import Ġcom . android . tools . lint . detector . api . Source Code Scanner Ċ import Ġcom . android . tools . lint . detector . api . get MethodName Ċ import Ġcom . intellij . openapi . util . Ref Ċ import Ġcom . intellij . psi . Psi Class Ċ import Ġcom . intellij . psi . Psi ClassType Ċ import Ġcom . intellij . psi . Psi Element Ċ import Ġcom . intellij . psi . Psi Field Ċ import Ġcom . intellij . psi . Psi Keyword Ċ import Ġcom . intellij . psi . Psi Modifier Ċ import Ġcom . intellij . psi . Psi Modifier List Ċ import Ġorg . jetbrains . u ast . U Anonymous Class Ċ import Ġorg . jetbrains . u ast . UB inary Expression Ċ import Ġorg . jetbrains . u ast . U Call Expression Ċ import Ġorg . jetbrains . u ast . U Class Ċ import Ġorg . jetbrains . u ast . U Element Ċ import Ġorg . jetbrains . u ast . U Field Ċ import Ġorg . jetbrains . u ast . U Method Ċ import Ġorg . jetbrains . u ast . U Object Literal Expression Ċ import Ġorg . jetbrains . u ast . U Qualified Reference Expression Ċ import Ġorg . jetbrains . u ast . U Res olvable Ċ import Ġorg . jetbrains . u ast . get Containing U Class Ċ import Ġorg . jetbrains . u ast . getParent OfType Ċ import Ġorg . jetbrains . u ast . to U Element Ċ import Ġorg . jetbrains . u ast . util . is Assignment Ċ import Ġorg . jetbrains . u ast . visitor . Abstract U ast Visitor Ċ import Ġjava . util . Locale Ċ Ċ /** ĠLooks Ġfor Ġle aks Ġvia Ġstatic Ġfields . Ġ*/ Ċ class ĠLe ak Detector Ġ: ĠDetector (), ĠSource Code Scanner Ġ{ ĊĊĠĠĠ Ġoverride Ġfun Ġapplicable Super Classes (): ĠList < String > Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn ĠSUP ER _ CLASSES ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠW arn Ġabout Ġinner Ġclasses Ġthat Ġaren 't Ġstatic : Ġthese Ġend Ġup ĊĠĠĠĠ Ġ* Ġret aining Ġthe Ġouter Ġclass . ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġoverride Ġfun Ġvisit Class ( context : ĠJava Context , Ġdeclaration : ĠU Class ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġcontaining Class Ġ= Ġdeclaration . get Containing U Class () ĊĠĠĠĠĠĠĠ Ġval Ġis Anonymous Ġ= Ġdeclaration Ġis ĠU Anonymous Class ĊĊĠĠĠĠĠĠĠ Ġ// ĠOnly Ġconsider Ġstatic Ġinner Ġclasses ĊĠĠĠĠĠĠĠ Ġval Ġevaluator Ġ= Ġcontext . evaluator ĊĠĠĠĠĠĠĠ Ġval Ġis Static Ġ= Ġevaluator . is Static ( declaration ) Ġ|| Ġcontaining Class Ġ== Ġnull ĊĠĠĠĠĠĠĠ Ġif Ġ( is Static Ġ|| Ġis Anonymous ) Ġ{ Ġ// Ġcontaining Class Ġ== Ġnull : Ġimplicitly Ġstatic ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠBut Ġlook Ġfor Ġfields Ġthat Ġstore Ġcontexts ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfor Ġ( field Ġin Ġdeclaration . fields ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcheck Instance Field ( context , Ġfield ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(! is Anonymous ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġvar ĠsuperClass : ĠString ? Ġ= Ġnull ĊĠĠĠĠĠĠĠ Ġfor Ġ( cls Ġin ĠSUP ER _ CLASSES ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( evaluator . inherits From ( declaration , Ġcls , Ġfalse )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠsuperClass Ġ= Ġcls ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġbreak ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ ĠsuperClass Ġ?: Ġreturn ĊĊĠĠĠĠĠĠĠ Ġval Ġu ast Parent Ġ= Ġdeclaration . u ast Parent ĊĠĠĠĠĠĠĠ Ġif Ġ( u ast Parent Ġ!= Ġnull ) Ġ{ ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġmethod Ġ= Ġu ast Parent . getParent OfType < U Method >( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠU Method :: class . java , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtrue , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠU Class :: class . java , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠU Object Literal Expression :: class . java ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( method Ġ!= Ġnull Ġ&& Ġevaluator . is Static ( method )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġval Ġinvocation Ġ= Ġdeclaration . getParent OfType < U Call Expression >( ĊĠĠĠĠĠĠĠĠĠĠĠ ĠU Object Literal Expression :: class . java , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtrue , ĊĠĠĠĠĠĠĠĠĠĠĠ ĠU Method :: class . java ĊĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ Ġval Ġlocation : ĠLocation ĊĠĠĠĠĠĠĠ Ġlocation Ġ= Ġif Ġ( is Anonymous Ġ&& Ġinvocation Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcontext . get Call Location ( invocation , Ġfalse , Ġfalse ) ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcontext . getName Location ( declaration ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġvar Ġname : ĠString ? ĊĠĠĠĠĠĠĠ Ġif Ġ( is Anonymous ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġname Ġ= Ġ" anonymous Ġ" Ġ+ Ġ( declaration Ġas ĠU Anonymous Class ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. base Class Reference ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. qualified Name ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġname Ġ= Ġdeclaration . qualified Name ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( name Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġname Ġ= Ġdeclaration . name ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġval Ġsuper ClassName Ġ= ĠsuperClass . substring ( super Class . lastIndexOf ('.') Ġ+ Ġ 1 ) ĊĠĠĠĠĠĠĠ Ġcontext . report ( ĊĠĠĠĠĠĠĠĠĠĠĠ ĠISS UE , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdeclaration , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlocation , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ" This Ġ`$ super ClassName ` Ġclass Ġshould Ġbe Ġstatic Ġor Ġle aks Ġmight Ġoccur Ġ($ name )" ĊĠĠĠĠĠĠĠ Ġ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġget Applicable U ast Types (): ĠList < Class < out ĠU Element >> Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn ĠlistOf < Class < out ĠU Element >>( U Field :: class . java ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġcreate U ast Handler ( context : ĠJava Context ): ĠU Element Handler Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn ĠField Checker ( context ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġclass ĠField Checker ( private Ġval Ġcontext : ĠJava Context ) Ġ: ĠU Element Handler () Ġ{ ĊĊĠĠĠĠĠĠĠ Ġoverride Ġfun Ġvisit Field ( node : ĠU Field ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġmodifier List Ġ= Ġnode . modifier List ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( modifier List Ġ== Ġnull Ġ|| Ġ! modifier List . has Modifier Property ( Psi Modifier . STATIC )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġtype Ġ= Ġnode . type Ġas ? ĠPsi ClassType Ġ?: Ġreturn ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġf qn Ġ= Ġtype . canonical Text ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( fq n . startsWith (" java .")) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcls Ġ= Ġtype . resolve () Ġ?: Ġreturn ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( fq n . startsWith (" android .")) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( is Leak Candidate ( cls , Ġcontext . evaluator ) Ġ&& ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ! is AppContext Name ( cls , Ġnode ) Ġ&& ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ! isInitialized To AppContext ( node , Ġcls ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġmessage Ġ= ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" Do Ġnot Ġplace ĠAndroid Ġcontext Ġclasses Ġin Ġstatic Ġfields ; Ġ" Ġ+ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" this Ġis Ġa Ġmemory Ġleak " ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreport ( node , Ġmodifier List , Ġmessage ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠUser Ġapplication Ġobject Ġ-- Ġlook Ġto Ġsee Ġif Ġthat Ġone Ġitself Ġhas ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġstatic Ġfields ? ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠWe Ġonly Ġcheck Ġ* one * Ġlevel Ġof Ġind irection Ġhere ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfor Ġ(( count , Ġreferenced ) Ġin Ġcls . all Fields . with Index ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠOnly Ġcheck Ġa Ġfew ; Ġavoid Ġgetting Ġb og ged Ġdown Ġon Ġlarge Ġclasses ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( count Ġ== Ġ 2 0 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġbreak ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġinner Type Ġ= Ġreferenced . type Ġas ? ĠPsi ClassType Ġ?: Ġcontinue ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcanonical Ġ= Ġinner Type . canonical Text ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( canonical . startsWith (" java .")) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontinue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġinner Cls Ġ= Ġinner Type . resolve () Ġ?: Ġcontinue ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( canonical . startsWith (" android .")) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( is Leak Candidate ( inner Cls , Ġcontext . evaluator ) Ġ&& ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ! is AppContext Name ( inner Cls , Ġreferenced ) Ġ&& ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ! isInitialized To AppContext ( context , Ġreferenced , Ġinner Cls ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġmessage Ġ= Ġ" Do Ġnot Ġplace ĠAndroid Ġcontext Ġclasses Ġin Ġstatic Ġ" Ġ+ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" fields Ġ( static Ġreference Ġto Ġ`${ cls . name }` Ġwhich Ġhas Ġfield Ġ" Ġ+ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ"` ${ referenced . name }` Ġpointing Ġto Ġ`${ inner Cls . name }`); Ġthis Ġ" Ġ+ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" is Ġa Ġmemory Ġleak " ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreport ( node , Ġmodifier List , Ġmessage ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġbreak ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġprivate Ġfun Ġis Initialized To AppContext ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcontext : ĠJava Context , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfield : ĠPsi Field , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtype Class : ĠPsi Class ĊĠĠĠĠĠĠĠ Ġ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(! context . evaluator . extends Class ( type Class , ĠCLASS _ CONTEXT , Ġfalse )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġu Field Ġ= Ġfield . to U Element ( U Field :: class . java ) Ġ?: Ġreturn Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġis Initialized To AppContext ( u Field , Ġtype Class ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġ/** ĊĠĠĠĠĠĠĠĠ Ġ* ĠIf Ġit 's Ġa Ġstatic Ġfield Ġsee Ġif Ġit 's Ġinitialized Ġto Ġan Ġapp ĊĠĠĠĠĠĠĠĠ Ġ* Ġcontext Ġin Ġone Ġof Ġthe Ġconstructors . ĊĠĠĠĠĠĠĠĠ Ġ*/ ĊĠĠĠĠĠĠĠ Ġprivate Ġfun Ġis Initialized To AppContext ( field : ĠU Field , Ġtype Class : ĠPsi Class ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcontaining Class Ġ= Ġfield . get Containing U Class () Ġ?: Ġreturn Ġfalse ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠOnly Ġcheck Ġfor Ġapp Ġcontext Ġif Ġwe 're Ġdealing Ġwith Ġa ĠContext Ġfield Ġ-- Ġthere 's ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġno Ġchance ĠF rag ments , ĠViews Ġetc Ġwill Ġbe Ġthe Ġapp Ġcontext . ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(! context . evaluator . extends Class ( type Class , ĠCLASS _ CONTEXT , Ġfalse )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġfor Ġ( method Ġin Ġcontaining Class . u ast Declarations ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( method Ġ! is ĠU Method Ġ|| Ġ! method . is Constructor ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontinue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġmethod Body Ġ= Ġmethod . u ast Body Ġ?: Ġcontinue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġassigned To AppContext Ġ= ĠRef ( false ) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmethod Body . accept ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġobject Ġ: ĠAbstract U ast Visitor () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġvisit Binary Expression ( node : ĠU Binary Expression ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( node . is Assignment () Ġ&& ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnode . left Operand Ġis ĠU Res olvable Ġ&& ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfield . source Psi Ġ== Ġ( node . left Operand Ġas ĠU Res olvable ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. resolve () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠYes , Ġassigning Ġto Ġthis Ġfield ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠSee Ġif Ġthe Ġright Ġhand Ġside Ġlooks Ġlike Ġan Ġapp Ġcontext ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġrhs : ĠU Element Ġ= Ġnode . right Operand ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhile Ġ( rhs Ġis ĠU Qualified Reference Expression ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrhs Ġ= Ġrhs . selector ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( rhs Ġis ĠU Call Expression ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(" getApplicationContext " Ġ== Ġget MethodName ( rhs )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġassigned To AppContext . set ( true ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġsuper . visit Binary Expression ( node ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( assigned To AppContext . get ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġfalse ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġprivate Ġfun Ġreport ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfield : ĠPsi Field , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġmodifier List : ĠPsi Modifier List , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġmessage : ĠString ĊĠĠĠĠĠĠĠ Ġ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġlocation Node : ĠPsi Element Ġ= Ġfield ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠTry Ġto Ġfind Ġthe Ġstatic Ġmodifier Ġitself ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( modifier List . has Explicit Modifier ( Psi Modifier . STATIC )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġchild : ĠPsi Element ? Ġ= Ġmodifier List . firstChild ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhile Ġ( child Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( child Ġis ĠPsi Keyword Ġ&& ĠPsi Keyword . STATIC Ġ== Ġchild . text ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlocation Node Ġ= Ġchild ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġbreak ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġchild Ġ= Ġchild . next Sibling ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġlocation Ġ= Ġcontext . getLocation ( location Node ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcontext . report ( ISSUE , Ġfield , Ġlocation , Ġmessage ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġcheck Instance Field ( context : ĠJava Context , Ġfield : ĠU Field ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġtype Ġ= Ġfield . type Ġas ? ĠPsi ClassType Ġ?: Ġreturn ĊĠĠĠĠĠĠĠ Ġval Ġf qn Ġ= Ġtype . canonical Text ĊĠĠĠĠĠĠĠ Ġif Ġ( fq n . startsWith (" java .")) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġval Ġcls Ġ= Ġtype . resolve () Ġ?: Ġreturn ĊĊĠĠĠĠĠĠĠ Ġif Ġ( is Leak Candidate ( cls , Ġcontext . evaluator )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcontext . report ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLe ak Detector . ISSUE , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfield , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontext . getLocation ( field ), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" This Ġfield Ġle aks Ġa Ġcontext Ġobject " ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠĠĠĠĠ Ġ/** ĠLe aking Ġdata Ġvia Ġstatic Ġfields . Ġ*/ ĊĠĠĠĠĠĠĠ Ġ@ Jvm Field ĊĠĠĠĠĠĠĠ Ġval ĠISS UE Ġ= ĠIssue . create ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġid Ġ= Ġ" Static Field Leak ", ĊĠĠĠĠĠĠĠĠĠĠĠ Ġbrief Description Ġ= Ġ" Static ĠField ĠLe aks ", ĊĠĠĠĠĠĠĠĠĠĠĠ Ġexplanation Ġ= Ġ""" ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠA Ġstatic Ġfield Ġwill Ġleak Ġcontexts . ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠNon - static Ġinner Ġclasses Ġhave Ġan Ġimplicit Ġreference Ġto Ġtheir Ġouter Ġclass . Ġ\ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠIf Ġthat Ġouter Ġclass Ġis Ġfor Ġexample Ġa Ġ` Fragment ` Ġor Ġ` Activity `, Ġthen Ġthis Ġ\ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreference Ġmeans Ġthat Ġthe Ġlong - running Ġhandler / loader / task Ġwill Ġhold Ġa Ġ\ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreference Ġto Ġthe Ġactivity Ġwhich Ġprevents Ġit Ġfrom Ġgetting Ġgarbage Ġcollected . ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠSimilar ly , Ġdirect Ġfield Ġreferences Ġto Ġactivities Ġand Ġfragments Ġfrom Ġthese Ġ\ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlonger Ġrunning Ġinstances Ġcan Ġcause Ġle aks . ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠViewModel Ġclasses Ġshould Ġnever Ġpoint Ġto ĠViews Ġor Ġnon - application ĠContext s . ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ"" ", ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcategory Ġ= ĠCategory . PER FORMANCE , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġandroid Specific Ġ= Ġtrue , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġpriority Ġ= Ġ 6 , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġseverity Ġ= ĠSeverity . WARNING , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġimplementation Ġ= ĠImplementation ( Leak Detector :: class . java , ĠScope . JAVA _ FILE _ SCOPE ) ĊĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ Ġprivate Ġval ĠSUP ER _ CLASSES Ġ= ĠlistOf ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ" android . content . Loader ", ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ" android . support . v 4 . content . Loader ", ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ" android . os . AsyncTask ", ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ" android . arch . lifecycle . ViewModel ", ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ" android x . lifecycle . ViewModel " ĊĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠCLASS _ LI FE CYCLE Ġ= Ġ" android x . lifecycle . Lifecycle " ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠCLASS _ LI FE CYCLE _ OLD Ġ= Ġ" android . arch . lifecycle . Lifecycle " ĊĊĠĠĠĠĠĠĠ Ġprivate Ġfun Ġis AppContext Name ( cls : ĠPsi Class , Ġfield : ĠPsi Field ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠDon 't Ġflag Ġnames Ġlike Ġ" s AppContext " Ġor Ġ" application Context ". ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġname Ġ= Ġfield . name ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġlower Ġ= Ġname . toLowerCase ( Locale . US ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( lower . contains (" app context ") Ġ|| Ġlower . contains (" application ")) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( CLASS _ CONTEXT Ġ== Ġcls . qualified Name ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġfalse ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġprivate Ġfun Ġis Leak Candidate ( cls : ĠPsi Class , Ġevaluator : ĠJava Evaluator ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġevaluator . extends Class ( cls , ĠCLASS _ CONTEXT , Ġfalse ) Ġ&& ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ! evaluator . extends Class ( cls , ĠCLASS _ APPLICATION , Ġfalse ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) Ġ|| ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġevaluator . extends Class ( cls , ĠCLASS _ VIEW , Ġfalse ) Ġ|| ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġevaluator . extends Class ( cls , ĠCLASS _ FRAGMENT , Ġfalse ) Ġ|| ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠFrom Ġhttps :// developer . android . com / topic / libraries / architecture / view model : ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠCa ution : ĠA ĠViewModel Ġmust Ġnever Ġreference Ġa Ġview , ĠLifecycle , Ġor Ġany ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġclass Ġthat Ġmay Ġhold Ġa Ġreference Ġto Ġthe Ġactivity Ġcontext ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġevaluator . extends Class ( cls , ĠCLASS _ LI FE CYCLE , Ġfalse ) Ġ|| ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġevaluator . extends Class ( cls , ĠCLASS _ LI FE CYCLE _ OLD , Ġfalse ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ