diff --git a/src/analysis/imports_sortedness.d b/src/analysis/imports_sortedness.d index a663fdc..5470e6b 100644 --- a/src/analysis/imports_sortedness.d +++ b/src/analysis/imports_sortedness.d @@ -4,9 +4,9 @@ module analysis.imports_sortedness; +import analysis.base : BaseAnalyzer; import dparse.lexer; import dparse.ast; -import analysis.base : BaseAnalyzer; import std.stdio; @@ -26,10 +26,32 @@ class ImportSortednessCheck : BaseAnalyzer override void visit(const Module mod) { - globalImports = []; + level = 0; + imports[level] = []; mod.accept(this); } + override void visit(const Statement decl) + { + imports[++level] = []; + decl.accept(this); + level--; + } + + override void visit(const BlockStatement decl) + { + imports[++level] = []; + decl.accept(this); + level--; + } + + override void visit(const StructBody decl) + { + imports[++level] = []; + decl.accept(this); + level--; + } + override void visit(const ImportDeclaration id) { import std.algorithm.iteration : map; @@ -59,20 +81,21 @@ class ImportSortednessCheck : BaseAnalyzer private: - string[] globalImports; + int level = 0; + string[][int] imports; void addImport(string importModuleName, const SingleImport singleImport) { import std.uni : sicmp; - if (globalImports.length > 0 && globalImports[$ -1].sicmp(importModuleName) > 0) + if (imports[level].length > 0 && imports[level][$ -1].sicmp(importModuleName) > 0) { addErrorMessage(singleImport.identifierChain.identifiers[0].line, singleImport.identifierChain.identifiers[0].column, KEY, MESSAGE); } else { - globalImports ~= importModuleName; + imports[level] ~= importModuleName; } } } @@ -187,5 +210,136 @@ unittest ImportSortednessCheck.MESSAGE, ), sac); + // local imports in functions + assertAnalyzerWarnings(q{ + import t2; + import t1; // [warn]: %s + void foo() + { + import f2; + import f1; // [warn]: %s + import f3; + } + void bar() + { + import f1; + import f2; + } + }c.format( + ImportSortednessCheck.MESSAGE, + ImportSortednessCheck.MESSAGE, + ), sac); + + // local imports in scopes + assertAnalyzerWarnings(q{ + import t2; + import t1; // [warn]: %s + void foo() + { + import f2; + import f1; // [warn]: %s + import f3; + { + import f2; + import f1; // [warn]: %s + import f3; + } + { + import f1; + import f2; + import f3; + } + } + }c.format( + ImportSortednessCheck.MESSAGE, + ImportSortednessCheck.MESSAGE, + ImportSortednessCheck.MESSAGE, + ), sac); + + // local imports in functions + assertAnalyzerWarnings(q{ + import t2; + import t1; // [warn]: %s + void foo() + { + import f2; + import f1; // [warn]: %s + import f3; + while (true) { + import f2; + import f1; // [warn]: %s + import f3; + } + for (;;) { + import f1; + import f2; + import f3; + } + foreach (el; arr) { + import f2; + import f1; // [warn]: %s + import f3; + } + } + }c.format( + ImportSortednessCheck.MESSAGE, + ImportSortednessCheck.MESSAGE, + ImportSortednessCheck.MESSAGE, + ImportSortednessCheck.MESSAGE, + ), sac); + + // nested scopes + assertAnalyzerWarnings(q{ + import t2; + import t1; // [warn]: %s + void foo() + { + import f2; + import f1; // [warn]: %s + import f3; + { + import f2; + import f1; // [warn]: %s + import f3; + { + import f2; + import f1; // [warn]: %s + import f3; + { + import f2; + import f1; // [warn]: %s + import f3; + } + } + } + } + }c.format( + ImportSortednessCheck.MESSAGE, + ImportSortednessCheck.MESSAGE, + ImportSortednessCheck.MESSAGE, + ImportSortednessCheck.MESSAGE, + ImportSortednessCheck.MESSAGE, + ), sac); + + // local imports in functions + assertAnalyzerWarnings(q{ + import t2; + import t1; // [warn]: %s + struct foo() + { + import f2; + import f1; // [warn]: %s + import f3; + } + class bar() + { + import f1; + import f2; + } + }c.format( + ImportSortednessCheck.MESSAGE, + ImportSortednessCheck.MESSAGE, + ), sac); + stderr.writeln("Unittest for ImportSortednessCheck passed."); }