1+ package checkstyle .checks .coding ;
2+
3+ import checkstyle .token .TokenTree ;
4+ import checkstyle .utils .StringUtils ;
5+
6+ @name (" UnusedLocalVar" )
7+ @desc (" Checks for unused local variables." )
8+ class UnusedLocalVarCheck extends Check {
9+
10+ public function new () {
11+ super (TOKEN );
12+ }
13+
14+ override function actualRun () {
15+ var root : TokenTree = checker .getTokenTree ();
16+ var functions : Array <TokenTree > = root .filter ([Kwd (KwdFunction )], ALL );
17+
18+ for (f in functions ) {
19+ if (isPosSuppressed (f .pos )) continue ;
20+ var skipFirstFunction : Bool = true ;
21+ var localVars : Array <TokenTree > = f .filterCallback (function (tok : TokenTree , depth : Int ): FilterResult {
22+ return switch (tok .tok ) {
23+ case Kwd (KwdVar ): FOUND_SKIP_SUBTREE ;
24+ case Kwd (KwdFunction ):
25+ if (skipFirstFunction ) {
26+ skipFirstFunction = false ;
27+ GO_DEEPER ;
28+ }
29+ else SKIP_SUBTREE ;
30+ default : GO_DEEPER ;
31+ }
32+ });
33+ checkLocalVars (f , localVars );
34+ }
35+ }
36+
37+ function checkLocalVars (f : TokenTree , localVars : Array <TokenTree >) {
38+ for (localVar in localVars ) {
39+ for (child in localVar .childs ) {
40+ switch (child .tok ) {
41+ case Const (CIdent (name )):
42+ checkLocalVar (f , child , name );
43+ default :
44+ }
45+ }
46+ }
47+ }
48+
49+ function checkLocalVar (f : TokenTree , v : TokenTree , name : String ) {
50+ var ignoreFunctionSignature : Bool = true ;
51+ var nameList : Array <TokenTree > = f .filterCallback (function (tok : TokenTree , depth : Int ): FilterResult {
52+ if (ignoreFunctionSignature ) {
53+ switch (tok .tok ) {
54+ case Kwd (KwdPublic ), Kwd (KwdPrivate ):
55+ return SKIP_SUBTREE ;
56+ case At :
57+ return SKIP_SUBTREE ;
58+ case Comment (_ ), CommentLine (_ ):
59+ return SKIP_SUBTREE ;
60+ case POpen :
61+ ignoreFunctionSignature = false ;
62+ return SKIP_SUBTREE ;
63+ default :
64+ return GO_DEEPER ;
65+ }
66+ }
67+ return switch (tok .tok ) {
68+ case Const (CIdent (n )):
69+ if (n == name ) FOUND_GO_DEEPER ;
70+ else GO_DEEPER ;
71+ case Const (CString (s )):
72+ checkStringInterpolation (tok , name , s );
73+ default : GO_DEEPER ;
74+ }
75+ });
76+ if (nameList .length > 1 ) return ;
77+
78+ logPos (' Unused local variable $name ' , v .pos );
79+ }
80+
81+ function checkStringInterpolation (tok : TokenTree , name : String , s : String ): FilterResult {
82+ if (! StringUtils .isStringInterpolation (s , checker .file .content , tok .pos )) {
83+ return GO_DEEPER ;
84+ }
85+
86+ // $name
87+ var format : String = " \\ $" + name + " ([^_0-9a-zA-Z]|$)" ;
88+ var r : EReg = new EReg (format , " " );
89+ if (r .match (s )) {
90+ return FOUND_GO_DEEPER ;
91+ }
92+
93+ // '${name.doSomething()} or ${doSomething(name)}
94+ format = " \\ $\\ {(|.*[^_0-9a-zA-Z])" + name + " ([^_0-9a-zA-Z].*)\\ }" ;
95+ r = new EReg (format , " " );
96+ if (r .match (s )) {
97+ return FOUND_GO_DEEPER ;
98+ }
99+ return GO_DEEPER ;
100+ }
101+ }
0 commit comments