1 // Copyright Brian Schott (Hackerpilot) 2014. 2 // Distributed under the Boost Software License, Version 1.0. 3 // (See accompanying file LICENSE_1_0.txt or copy at 4 // http://www.boost.org/LICENSE_1_0.txt) 5 6 module dscanner.analysis.local_imports; 7 8 import std.stdio; 9 import dparse.ast; 10 import dparse.lexer; 11 import dscanner.analysis.base; 12 import dscanner.analysis.helpers; 13 import dsymbol.scope_; 14 15 /** 16 * Checks for local imports that import all symbols. 17 * See_also: $(LINK https://issues.dlang.org/show_bug.cgi?id=10378) 18 */ 19 final class LocalImportCheck : BaseAnalyzer 20 { 21 alias visit = BaseAnalyzer.visit; 22 23 mixin AnalyzerInfo!"local_import_check"; 24 25 /** 26 * Construct with the given file name. 27 */ 28 this(string fileName, const(Scope)* sc, bool skipTests = false) 29 { 30 super(fileName, sc, skipTests); 31 } 32 33 mixin visitThing!StructBody; 34 mixin visitThing!BlockStatement; 35 36 override void visit(const Declaration dec) 37 { 38 if (dec.importDeclaration is null) 39 { 40 dec.accept(this); 41 return; 42 } 43 foreach (attr; dec.attributes) 44 { 45 if (attr.attribute == tok!"static") 46 isStatic = true; 47 } 48 dec.accept(this); 49 isStatic = false; 50 } 51 52 override void visit(const ImportDeclaration id) 53 { 54 if ((!isStatic && interesting) && (id.importBindings is null 55 || id.importBindings.importBinds.length == 0)) 56 { 57 foreach (singleImport; id.singleImports) 58 { 59 if (singleImport.rename.text.length == 0) 60 { 61 addErrorMessage(singleImport.identifierChain.identifiers[0].line, 62 singleImport.identifierChain.identifiers[0].column, 63 "dscanner.suspicious.local_imports", "Local imports should specify" 64 ~ " the symbols being imported to avoid hiding local symbols."); 65 } 66 } 67 } 68 } 69 70 private: 71 72 mixin template visitThing(T) 73 { 74 override void visit(const T thing) 75 { 76 const b = interesting; 77 interesting = true; 78 thing.accept(this); 79 interesting = b; 80 } 81 } 82 83 bool interesting; 84 bool isStatic; 85 } 86 87 unittest 88 { 89 import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; 90 91 StaticAnalysisConfig sac = disabledConfig(); 92 sac.local_import_check = Check.enabled; 93 assertAnalyzerWarnings(q{ 94 void testLocalImport() 95 { 96 import std.stdio; // [warn]: Local imports should specify the symbols being imported to avoid hiding local symbols. 97 import std.fish : scales, head; 98 import DAGRON = std.experimental.dragon; 99 } 100 }}, sac); 101 102 stderr.writeln("Unittest for LocalImportCheck passed."); 103 }