Skip to content

Commit 027311c

Browse files
authored
added UnusedLocalVarCheck, fixes #231 (#307)
1 parent 4662a4a commit 027311c

File tree

5 files changed

+195
-2
lines changed

5 files changed

+195
-2
lines changed

checkstyle.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,9 @@
462462
},
463463
"type": "UnusedImport"
464464
},
465+
{
466+
"type": "UnusedLocalVar"
467+
},
465468
{
466469
"type": "VariableInitialisation"
467470
},

resources/default-config.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,10 @@
512512
},
513513
"type": "UnusedImport"
514514
},
515+
{
516+
"props": {},
517+
"type": "UnusedLocalVar"
518+
},
515519
{
516520
"props": {},
517521
"type": "VariableInitialisation"
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
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+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package checks.coding;
2+
3+
import checkstyle.checks.coding.UnusedLocalVarCheck;
4+
5+
class UnusedLocalVarCheckTest extends CheckTestCase<UnusedLocalVarCheckTests> {
6+
7+
static inline var MSG_UNUSED_VAR_INDEX:String = "Unused local variable index";
8+
9+
public function testLocalVar() {
10+
var check = new UnusedLocalVarCheck();
11+
assertNoMsg(check, USED_INDEX);
12+
assertNoMsg(check, STRING_INTERPOLATION);
13+
}
14+
15+
public function testUnusedLocalVar() {
16+
var check = new UnusedLocalVarCheck();
17+
assertMsg(check, UNUSED_INDEX, MSG_UNUSED_VAR_INDEX);
18+
assertMsg(check, UNUSED_INDEX2, MSG_UNUSED_VAR_INDEX);
19+
assertMsg(check, STRING_INTERPOLATION_UNUSED, MSG_UNUSED_VAR_INDEX);
20+
}
21+
}
22+
23+
@:enum
24+
abstract UnusedLocalVarCheckTests(String) to String {
25+
var USED_INDEX = "
26+
abstractAndClass Test {
27+
function a() {
28+
var index:Int;
29+
index++;
30+
}
31+
@SuppressWarnings('checkstyle:UnusedLocalVar')
32+
function b() {
33+
var index:Int;
34+
}
35+
36+
function c() {
37+
var index:Int;
38+
call(function() {
39+
index++;
40+
});
41+
}
42+
}";
43+
44+
var UNUSED_INDEX = "
45+
abstractAndClass Test {
46+
// index
47+
@index
48+
public function a(index:String) {
49+
var index:Int;
50+
}
51+
}";
52+
53+
var UNUSED_INDEX2 = "
54+
abstractAndClass Test {
55+
public function a() {
56+
call(function() {
57+
var index:Int;
58+
});
59+
}
60+
}";
61+
62+
var STRING_INTERPOLATION = "
63+
abstractAndClass Test {
64+
function a() {
65+
var index:Int;
66+
var index2:Array<Int>;
67+
var index3:String;
68+
69+
trace ('$index');
70+
trace ('${index2.toString()}');
71+
trace ('${Std.parseInt(index3)}');
72+
}
73+
}";
74+
75+
var STRING_INTERPOLATION_UNUSED = "
76+
abstractAndClass Test {
77+
function a() {
78+
var index:Int;
79+
80+
trace ('index');
81+
trace ('$index2');
82+
trace ('${index2.toString()}');
83+
trace ('${Std.parseInt(index3)}');
84+
}
85+
}";
86+
}

test/checks/size/LineLengthCheckTest.hx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import checkstyle.checks.size.LineLengthCheck;
55
class LineLengthCheckTest extends CheckTestCase<LineLengthCheckTests> {
66

77
public function testDefaultLineLength() {
8-
var check = new LineLengthCheck();
98
assertMsg(new LineLengthCheck(), TEST1, "Line is longer than 160 characters (found 178)");
109
}
1110

@@ -51,4 +50,4 @@ abstract LineLengthCheckTests(String) to String {
5150
var s = 'LONG LINE TEST LONG LINE TEST LONG LINE TEST LONG LINE TEST';
5251
}
5352
}";
54-
}
53+
}

0 commit comments

Comments
 (0)