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 class LocalImportCheck : BaseAnalyzer
20 {
21 	alias visit = BaseAnalyzer.visit;
22 
23 	/**
24 	 * Construct with the given file name.
25 	 */
26 	this(string fileName, const(Scope)* sc, bool skipTests = false)
27 	{
28 		super(fileName, sc, skipTests);
29 	}
30 
31 	mixin visitThing!StructBody;
32 	mixin visitThing!BlockStatement;
33 
34 	override void visit(const Declaration dec)
35 	{
36 		if (dec.importDeclaration is null)
37 		{
38 			dec.accept(this);
39 			return;
40 		}
41 		foreach (attr; dec.attributes)
42 		{
43 			if (attr.attribute == tok!"static")
44 				isStatic = true;
45 		}
46 		dec.accept(this);
47 		isStatic = false;
48 	}
49 
50 	override void visit(const ImportDeclaration id)
51 	{
52 		if ((!isStatic && interesting) && (id.importBindings is null
53 				|| id.importBindings.importBinds.length == 0))
54 		{
55 			foreach (singleImport; id.singleImports)
56 			{
57 				if (singleImport.rename.text.length == 0)
58 				{
59 					addErrorMessage(singleImport.identifierChain.identifiers[0].line,
60 							singleImport.identifierChain.identifiers[0].column,
61 							"dscanner.suspicious.local_imports", "Local imports should specify"
62 							~ " the symbols being imported to avoid hiding local symbols.");
63 				}
64 			}
65 		}
66 	}
67 
68 private:
69 
70 	mixin template visitThing(T)
71 	{
72 		override void visit(const T thing)
73 		{
74 			const b = interesting;
75 			interesting = true;
76 			thing.accept(this);
77 			interesting = b;
78 		}
79 	}
80 
81 	bool interesting;
82 	bool isStatic;
83 }
84 
85 unittest
86 {
87 	import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
88 
89 	StaticAnalysisConfig sac = disabledConfig();
90 	sac.local_import_check = Check.enabled;
91 	assertAnalyzerWarnings(q{
92 		void testLocalImport()
93 		{
94 			import std.stdio; // [warn]: Local imports should specify the symbols being imported to avoid hiding local symbols.
95 			import std.fish : scales, head;
96 			import DAGRON = std.experimental.dragon;
97 		}
98 	}}, sac);
99 
100 	stderr.writeln("Unittest for LocalImportCheck passed.");
101 }