/** Ċ Ġ* ĠBSD - style Ġlicense ; Ġfor Ġmore Ġinfo Ġsee Ġhttp :// pmd . sourceforge . net / license . html Ċ Ġ*/ Ċ package Ġcom . alibaba . p 3 c . idea . pmd Ċ Ċ import Ġcom . alibaba . p 3 c . idea . config . P 3 c Config Ċ import Ġcom . google . common . cache . Cache Ċ import Ġcom . google . common . cache . Cache Builder Ċ import Ġcom . intellij . openapi . components . Service Manager Ċ import Ġnet . sourceforge . pmd . PMD Ċ import Ġnet . sourceforge . pmd . PMD Configuration Ċ import Ġnet . sourceforge . pmd . PMD Exception Ċ import Ġnet . sourceforge . pmd . RuleContext Ċ import Ġnet . sourceforge . pmd . Rule Sets Ċ import Ġnet . sourceforge . pmd . benchmark . Time Tracker Ċ import Ġnet . sourceforge . pmd . benchmark . Timed Operation Category Ċ import Ġnet . sourceforge . pmd . lang . Language Ċ import Ġnet . sourceforge . pmd . lang . Language Version Ċ import Ġnet . sourceforge . pmd . lang . Language Version Handler Ċ import Ġnet . sourceforge . pmd . lang . Parser Ċ import Ġnet . sourceforge . pmd . lang . ast . Node Ċ import Ġnet . sourceforge . pmd . lang . ast . ParseException Ċ import Ġnet . sourceforge . pmd . lang . xpath . Initializer Ċ import Ġjava . io . IOException Ċ import Ġjava . io . InputStream Ċ import Ġjava . io . InputStream Reader Ċ import Ġjava . io . Reader Ċ import Ġjava . util . concurrent . TimeUnit Ċ Ċ class ĠSource Code Processor ( private Ġval Ġconfiguration : ĠP MD Configuration ) Ġ{ ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠPro cesses Ġthe Ġinput Ġstream Ġagainst Ġa Ġrule Ġset Ġusing Ġthe Ġgiven Ġinput ĊĠĠĠĠ Ġ* Ġencoding . ĊĠĠĠĠ Ġ* ĊĠĠĠĠ Ġ* Ġ@ param Ġsource Code ĊĠĠĠĠ Ġ* ĠThe ĠInputStream Ġto Ġanalyze . ĊĠĠĠĠ Ġ* Ġ@ param Ġrule Sets ĊĠĠĠĠ Ġ* ĠThe Ġcollection Ġof Ġrules Ġto Ġprocess Ġagainst Ġthe Ġfile . ĊĠĠĠĠ Ġ* Ġ@ param Ġctx ĊĠĠĠĠ Ġ* ĠThe Ġcontext Ġin Ġwhich ĠP MD Ġis Ġoperating . ĊĠĠĠĠ Ġ* Ġ@ throws ĠP MD Exception ĊĠĠĠĠ Ġ* Ġif Ġthe Ġinput Ġencoding Ġis Ġunsupported , Ġthe Ġinput Ġstream Ġcould ĊĠĠĠĠ Ġ* Ġnot Ġbe Ġparsed , Ġor Ġother Ġerror Ġis Ġencountered . ĊĠĠĠĠ Ġ* Ġ@ see Ġ. process Source Code ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġ@ Throws ( PMD Exception :: class ) ĊĠĠĠ Ġfun Ġprocess Source Code ( sourceCode : ĠInputStream , Ġrule Sets : ĠRule Sets , Ġctx : ĠRule Context ) Ġ{ ĊĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠInputStreamReader ( sourceCode , Ġconfiguration . source Encoding ). use Ġ{ Ġstream Reader Ġ-> Ġprocess Source Code ( stream Reader , Ġrule Sets , Ġctx ) Ġ} ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠIOException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠP MD Exception (" IO Ġexception : Ġ" Ġ+ Ġe . message , Ġe ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠPro cesses Ġthe Ġinput Ġstream Ġagainst Ġa Ġrule Ġset Ġusing Ġthe Ġgiven Ġinput ĊĠĠĠĠ Ġ* Ġencoding . ĠIf Ġthe ĠLanguage Version Ġis Ġ` null ` Ġon Ġthe ĠRule Context , ĊĠĠĠĠ Ġ* Ġit Ġwill Ġbe Ġautomatically Ġdetermined . ĠAny Ġcode Ġwhich Ġw ishes Ġto Ġprocess ĊĠĠĠĠ Ġ* Ġfiles Ġfor Ġdifferent ĠLanguage s , Ġwill Ġneed Ġto Ġbe Ġsure Ġto Ġeither Ġproperly ĊĠĠĠĠ Ġ* Ġset Ġthe ĠLanguage Ġon Ġthe ĠRule Context , Ġor Ġset Ġit Ġto Ġ` null ` ĊĠĠĠĠ Ġ* Ġfirst . ĊĠĠĠĠ Ġ* ĊĠĠĠĠ Ġ* Ġ@ see ĠRule Context . set Language Version ĊĠĠĠĠ Ġ* Ġ@ see ĠP MD Configuration . get Language Version Of File ĊĠĠĠĠ Ġ* Ġ@ param Ġsource Code ĊĠĠĠĠ Ġ* ĠThe ĠReader Ġto Ġanalyze . ĊĠĠĠĠ Ġ* Ġ@ param Ġrule Sets ĊĠĠĠĠ Ġ* ĠThe Ġcollection Ġof Ġrules Ġto Ġprocess Ġagainst Ġthe Ġfile . ĊĠĠĠĠ Ġ* Ġ@ param Ġctx ĊĠĠĠĠ Ġ* ĠThe Ġcontext Ġin Ġwhich ĠP MD Ġis Ġoperating . ĊĠĠĠĠ Ġ* Ġ@ throws ĠP MD Exception ĊĠĠĠĠ Ġ* Ġif Ġthe Ġinput Ġencoding Ġis Ġunsupported , Ġthe Ġinput Ġstream Ġcould ĊĠĠĠĠ Ġ* Ġnot Ġbe Ġparsed , Ġor Ġother Ġerror Ġis Ġencountered . ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġ@ Throws ( PMD Exception :: class ) ĊĠĠĠ Ġfun Ġprocess Source Code ( sourceCode : ĠReader , Ġrule Sets : ĠRule Sets , Ġctx : ĠRule Context ) Ġ{ ĊĠĠĠĠĠĠĠ Ġdetermine Language ( ctx ) ĊĊĠĠĠĠĠĠĠ Ġ// Ġmake Ġsure Ġcustom ĠXPath Ġfunctions Ġare Ġinitialized ĊĠĠĠĠĠĠĠ ĠInitial izer . initialize () ĊĊĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġrule Sets . start ( ctx ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġprocess Source ( sourceCode , Ġrule Sets , Ġctx ) ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( pe : ĠParseException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġconfiguration . analysis Cache . analysis Failed ( ctx . sourceCode File ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠP MD Exception (" Error Ġwhile Ġparsing Ġ" Ġ+ Ġctx . sourceCode Filename , Ġpe ) ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġconfiguration . analysis Cache . analysis Failed ( ctx . sourceCode File ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠP MD Exception (" Error Ġwhile Ġprocessing Ġ" Ġ+ Ġctx . sourceCode Filename , Ġe ) ĊĠĠĠĠĠĠĠ Ġ} Ġfinally Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġrule Sets . end ( ctx ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġparse ( ctx : ĠRule Context , Ġsource Code : ĠReader , Ġparser : ĠParser ): ĠNode Ġ{ ĊĠĠĠĠĠĠĠ ĠTime Tracker . start Operation ( Timed Operation Category . PARSER ). use Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġroot Node Ġ= Ġparser . parse ( ctx . sourceCode Filename , Ġsource Code ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġctx . report . suppress ( parser . suppress Map ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġroot Node ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġget Root Node ( sourceCode : ĠReader , Ġrule Sets : ĠRule Sets , Ġctx : ĠRule Context ): ĠNode Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ(! smart F ox Config . ast Cache Enable ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġparse Node ( ctx , Ġrule Sets , Ġsource Code ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġval Ġnode Ġ= Ġnode Cache . get If Present ( ctx . sourceCode Filename ) ĊĠĠĠĠĠĠĠ Ġif Ġ( node Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġnode ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġreturn Ġparse Node ( ctx , Ġrule Sets , Ġsource Code ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġparse Node ( ctx : ĠRule Context , Ġrule Sets : ĠRule Sets , Ġsource Code : ĠReader ): ĠNode Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġlanguage Version Ġ= Ġctx . language Version ĊĠĠĠĠĠĠĠ Ġval Ġlanguage Version Handler Ġ= Ġlanguage Version . language Version Handler ĊĠĠĠĠĠĠĠ Ġval Ġparser Ġ= ĠP MD . parser For ( language Version , Ġconfiguration ) ĊĠĠĠĠĠĠĠ Ġval Ġroot Node Ġ= Ġparse ( ctx , Ġsource Code , Ġparser ) ĊĠĠĠĠĠĠĠ Ġsymbol Facade ( root Node , Ġlanguage Version Handler ) ĊĠĠĠĠĠĠĠ Ġval Ġlanguage Ġ= Ġlanguage Version . language ĊĠĠĠĠĠĠĠ Ġuses D FA ( language Version , Ġroot Node , Ġrule Sets , Ġlanguage ) ĊĠĠĠĠĠĠĠ Ġuses Type Resolution ( language Version , Ġroot Node , Ġrule Sets , Ġlanguage ) ĊĠĠĠĠĠĠĠ Ġnode Cache . put ( ctx . sourceCode Filename , Ġroot Node ) ĊĠĠĠĠĠĠĠ Ġreturn Ġroot Node ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġsymbol Facade ( root Node : ĠNode , Ġlanguage Version Handler : ĠLanguage Version Handler ) Ġ{ ĊĠĠĠĠĠĠĠ ĠTime Tracker . start Operation ( Timed Operation Category . SYMBOL _ TABLE ). use Ġ{ Ġto Ġ-> Ġlanguage Version Handler . get Symbol Facade ( configuration . class Loader ). start ( root Node ) Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġresolve Qualified Names ( root Node : ĠNode , Ġhandler : ĠLanguage Version Handler ) Ġ{ ĊĠĠĠĠĠĠĠ ĠTime Tracker . start Operation ( Timed Operation Category . QUAL IFI ED _ NAME _ RESOL UTION ). use Ġ{ Ġto Ġ-> Ġhandler . get QualifiedName Resolution Facade ( configuration . class Loader ). start ( root Node ) Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ// Ġprivate ĠParser Options Ġget Parser Options ( final ĠLanguage Version Handler ĊĠĠĠ Ġ// Ġlanguage Version Handler ) Ġ{ ĊĠĠĠ Ġ// Ġ// ĠTODO ĠHandle ĠRules Ġhaving Ġdifferent Ġparser Ġoptions . ĊĠĠĠ Ġ// ĠParser Options Ġparser Options Ġ= ĊĠĠĠ Ġ// Ġlanguage Version Handler . getDefault Parser Options (); ĊĠĠĠ Ġ// Ġparser Options . set Suppress Marker ( configuration . get Suppress Marker ()); ĊĠĠĠ Ġ// Ġreturn Ġparser Options ; ĊĠĠĠ Ġ// Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġuses D FA ( language Version : ĠLanguage Version , Ġroot Node : ĠNode , Ġrule Sets : ĠRule Sets , Ġlanguage : ĠLanguage ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( rule Sets . uses D FA ( language )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠTime Tracker . start Operation ( Timed Operation Category . D FA ). use Ġ{ Ġto Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġdata Flow Facade Ġ= Ġlanguage Version . language Version Handler . data Flow Facade ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdata Flow Facade . start ( root Node ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġuses Type Resolution ( language Version : ĠLanguage Version , Ġroot Node : ĠNode , Ġrule Sets : ĠRule Sets , ĊĠĠĠĠĠĠĠ Ġlanguage : ĠLanguage ) Ġ{ ĊĊĠĠĠĠĠĠĠ Ġif Ġ( rule Sets . uses Type Resolution ( language )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠTime Tracker . start Operation ( Timed Operation Category . TYPE _ RESOL UTION ). use Ġ{ Ġto Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlanguage Version . language Version Handler . getType Resolution Facade ( configuration . class Loader ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. start ( root Node ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĊĠĠĠ Ġprivate Ġfun Ġuses Mult if ile ( root Node : ĠNode , Ġlanguage Version Handler : ĠLanguage Version Handler , Ġrule Sets : ĠRule Sets , ĊĠĠĠĠĠĠĠ Ġlanguage : ĠLanguage ) Ġ{ ĊĊĠĠĠĠĠĠĠ Ġif Ġ( rule Sets . uses Mult if ile ( language )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠTime Tracker . start Operation ( Timed Operation Category . MULTI FILE _ ANAL YS IS ). use Ġ{ Ġto Ġ-> Ġlanguage Version Handler . mult if ile Facade . start ( root Node ) Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĊĠĠĠ Ġprivate Ġfun Ġprocess Source ( sourceCode : ĠReader , Ġrule Sets : ĠRule Sets , Ġctx : ĠRule Context ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġlanguage Version Ġ= Ġctx . language Version ĊĠĠĠĠĠĠĠ Ġval Ġlanguage Version Handler Ġ= Ġlanguage Version . language Version Handler ĊĊĠĠĠĠĠĠĠ Ġval Ġroot Node Ġ= Ġget Root Node ( sourceCode , Ġrule Sets , Ġctx ) ĊĠĠĠĠĠĠĠ Ġresolve Qualified Names ( root Node , Ġlanguage Version Handler ) ĊĠĠĠĠĠĠĠ Ġsymbol Facade ( root Node , Ġlanguage Version Handler ) ĊĠĠĠĠĠĠĠ Ġval Ġlanguage Ġ= Ġlanguage Version . language ĊĠĠĠĠĠĠĠ Ġuses D FA ( language Version , Ġroot Node , Ġrule Sets , Ġlanguage ) ĊĠĠĠĠĠĠĠ Ġuses Type Resolution ( language Version , Ġroot Node , Ġrule Sets , Ġlanguage ) ĊĠĠĠĠĠĠĠ Ġuses Mult if ile ( root Node , Ġlanguage Version Handler , Ġrule Sets , Ġlanguage ) ĊĊĠĠĠĠĠĠĠ Ġval Ġac us Ġ= ĠlistOf ( root Node ) ĊĠĠĠĠĠĠĠ Ġrule Sets . apply ( ac us , Ġctx , Ġlanguage ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġdetermine Language ( ctx : ĠRule Context ) Ġ{ ĊĠĠĠĠĠĠĠ Ġ// ĠIf ĠLanguage Version Ġof Ġthe Ġsource Ġfile Ġis Ġnot Ġknown , Ġmake Ġa ĊĠĠĠĠĠĠĠ Ġ// Ġdetermin ation ĊĠĠĠĠĠĠĠ Ġif Ġ( ctx . language Version Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġlanguage Version Ġ= Ġconfiguration . get Language Version Of File ( ctx . sourceCode Filename ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġctx . language Version Ġ= Ġlanguage Version ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġsmart F ox Config Ġ= ĠService Manager . getService ( P 3 c Config :: class . java ) !! ĊĠĠĠĠĠĠĠ Ġprivate Ġlateinit Ġvar Ġnode Cache : ĠCache < String , ĠNode > ĊĊĠĠĠĠĠĠĠ Ġinit Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġre Init Node Cache ( smart F ox Config . ast Cache Time ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġfun Ġre Init Node Cache ( expire Time : ĠLong ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġnode Cache Ġ= ĠCache Builder . newBuilder (). concurrency Level ( 1 6 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. expire After Write ( expire Time , ĠTimeUnit . MILLISECONDS ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. maximum Size ( 1 0 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. build < String , ĠNode >() !! ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġfun Ġinvalidate Cache ( file : ĠString ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġnode Cache . invalidate ( file ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ