From e48a20506812fc6161444fa2555901a04ef6b090 Mon Sep 17 00:00:00 2001 From: AlexHaxe Date: Fri, 27 May 2016 01:41:31 +0200 Subject: [PATCH] unused imports now checks string interpolation for types (#274) prevent stacktrace when calling checkstyle with an invalid config file --- src/checkstyle/Main.hx | 4 +- .../checks/imports/UnusedImportCheck.hx | 41 +++++++++++++++++-- test/checks/imports/UnusedImportCheckTest.hx | 20 +++++++++ 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/checkstyle/Main.hx b/src/checkstyle/Main.hx index c79138f2..da1e13f9 100644 --- a/src/checkstyle/Main.hx +++ b/src/checkstyle/Main.hx @@ -109,8 +109,8 @@ class Main { excludePath = DEFAULT_EXCLUDE_CONFIG; } - if (configPath == null) addAllChecks(); - else loadConfig(configPath); + if (configPath != null && FileSystem.exists(configPath) && !FileSystem.isDirectory(configPath)) loadConfig(configPath); + else addAllChecks(); if (excludePath != null) loadExcludeConfig(excludePath); else start(); diff --git a/src/checkstyle/checks/imports/UnusedImportCheck.hx b/src/checkstyle/checks/imports/UnusedImportCheck.hx index e24d8062..06dc2082 100644 --- a/src/checkstyle/checks/imports/UnusedImportCheck.hx +++ b/src/checkstyle/checks/imports/UnusedImportCheck.hx @@ -32,13 +32,22 @@ class UnusedImportCheck extends Check { var imports:Array = root.filter([Kwd(KwdImport)], ALL); var idents:Array = root.filterCallback(function(token:TokenTree, depth:Int):FilterResult { switch (token.tok) { - case Const(CIdent(name)): + case Const(CIdent(_)): if (TokenTreeCheckUtils.isImport(token)) return GO_DEEPER; return FOUND_GO_DEEPER; default: } return GO_DEEPER; }); + var stringLiterals:Array = root.filterCallback(function(token:TokenTree, depth:Int):FilterResult { + switch (token.tok) { + case Const(CString(text)): + if (checker.file.content.substr(token.pos.min, 1) != "'") return GO_DEEPER; + if (~/\$\{[^\}]+\.[^\}]+\}/.match (text)) return FOUND_GO_DEEPER; + default: + } + return GO_DEEPER; + }); for (imp in imports) { var typeName:String = detectTypeName(imp); var moduleName:String = detectModuleName(imp); @@ -60,7 +69,7 @@ class UnusedImportCheck extends Check { continue; } seenModules.push(moduleName); - checkUsage(typeName, moduleName, imp, idents); + checkUsage(typeName, moduleName, imp, idents, stringLiterals); } } @@ -119,7 +128,7 @@ class UnusedImportCheck extends Check { return null; } - function checkUsage(typeName:String, moduleName:String, importTok:TokenTree, idents:Array) { + function checkUsage(typeName:String, moduleName:String, importTok:TokenTree, idents:Array, stringLiterals:Array) { for (ident in idents) { var name:String = TokenDefPrinter.print(ident.tok); if (!checkName(typeName, moduleName, name)) continue; @@ -129,9 +138,35 @@ class UnusedImportCheck extends Check { default: return; } } + for (literal in stringLiterals) { + var names : Array = extractLiteralNames(TokenDefPrinter.print (literal.tok)); + for (name in names) { + if (checkName(typeName, moduleName, name)) return; + } + } logPos('Unused import "$moduleName" detected', importTok.pos); } + function extractLiteralNames(text : String):Array { + var names : Array = []; + var interpols : Array = []; + var interpolRegEx : EReg = ~/\$\{([^\}]+)\}/g; + while (true) { + if (!interpolRegEx.match(text)) break; + interpols.push(interpolRegEx.matched(1)); + text = interpolRegEx.matchedRight(); + } + var namesRegEx : EReg = ~/([A-Z][A-Za-z0-9_]*)/g; + for (interpol in interpols) { + while (true) { + if (!namesRegEx.match(interpol)) break; + names.push(namesRegEx.matched(1)); + interpol = namesRegEx.matchedRight(); + } + } + return names; + } + function hasMapping(moduleName:String):Bool { var mappedTypes:Array = Reflect.field(moduleTypeMap, moduleName); return ((mappedTypes != null) && (mappedTypes.length > 0)); diff --git a/test/checks/imports/UnusedImportCheckTest.hx b/test/checks/imports/UnusedImportCheckTest.hx index c5cfd460..68b82b7e 100644 --- a/test/checks/imports/UnusedImportCheckTest.hx +++ b/test/checks/imports/UnusedImportCheckTest.hx @@ -69,6 +69,11 @@ class UnusedImportCheckTest extends CheckTestCase { assertNoMsg(check, IMPORT_TYPE_MAP, "import.hx"); assertNoMsg(check, UNUSED_IMPORT_TYPE_MAP, "import.hx"); } + + public function testStringInterpolation() { + var check = new UnusedImportCheck(); + assertMsg(check, STRING_INTERPOL, MSG_UNUSED); + } } @:enum @@ -79,6 +84,7 @@ abstract UnusedImportCheckTests(String) to String { import haxe.checkstyle.Check; import haxe.checkstyle.Check2; import haxe.checkstyle.Check3; + import haxe.checkstyle.Check5; import haxe.checkstyle.sub.*; abstractAndClass Test { @@ -88,6 +94,7 @@ abstract UnusedImportCheckTests(String) to String { new Check2(); Check3.test(); new Check4(); + trace ('${Check5.debug()} ${blah.xxx}'); } }"; @@ -255,4 +262,17 @@ abstract UnusedImportCheckTests(String) to String { return new OtherCheck (); } }"; + + var STRING_INTERPOL = " + package checkstyle.test; + + import haxe.checkstyle.Check3; + + abstractAndClass Test { + + public function new() { + trace ('${Check3}'); + } + }"; + } \ No newline at end of file