1 //          Copyright Brian Schott (Hackerpilot) 2014-2015.
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 module dscanner.analysis.unused_variable;
6 
7 import dparse.ast;
8 import dscanner.analysis.base;
9 import dscanner.analysis.unused;
10 import dsymbol.scope_ : Scope;
11 import std.algorithm.iteration : map;
12 
13 /**
14  * Checks for unused variables.
15  */
16 final class UnusedVariableCheck : UnusedIdentifierCheck
17 {
18 	alias visit = UnusedIdentifierCheck.visit;
19 
20 	mixin AnalyzerInfo!"unused_variable_check";
21 
22 	/**
23 	 * Params:
24 	 *     fileName = the name of the file being analyzed
25 	 */
26 	this(string fileName, const(Scope)* sc, bool skipTests = false)
27 	{
28 		super(fileName, sc, skipTests);
29 	}
30 
31 	override void visit(const VariableDeclaration variableDeclaration)
32 	{
33 		foreach (d; variableDeclaration.declarators)
34 			this.variableDeclared(d.name.text, d.name.line, d.name.column, false);
35 		variableDeclaration.accept(this);
36 	}
37 
38 	override void visit(const AutoDeclaration autoDeclaration)
39 	{
40 		foreach (t; autoDeclaration.parts.map!(a => a.identifier))
41 			this.variableDeclared(t.text, t.line, t.column, false);
42 		autoDeclaration.accept(this);
43 	}
44 
45 	override protected void popScope()
46 	{
47 		foreach (uu; tree[$ - 1])
48 		{
49 			if (!uu.isRef && tree.length > 1)
50 			{
51 				if (uu.uncertain)
52 					continue;
53 				immutable string errorMessage = "Variable " ~ uu.name ~ " is never used.";
54 				addErrorMessage(uu.line, uu.column, 
55 						"dscanner.suspicious.unused_variable", errorMessage);
56 			}
57 		}
58 		tree = tree[0 .. $ - 1];
59 	}
60 }
61 
62 @system unittest
63 {
64 	import std.stdio : stderr;
65 	import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
66 	import dscanner.analysis.helpers : assertAnalyzerWarnings;
67 
68 	StaticAnalysisConfig sac = disabledConfig();
69 	sac.unused_variable_check = Check.enabled;
70 	assertAnalyzerWarnings(q{
71 
72 	// Issue 274
73 	unittest
74 	{
75 		size_t byteIndex = 0;
76 		*(cast(FieldType*)(retVal.ptr + byteIndex)) = item;
77 	}
78 
79 	unittest
80 	{
81 		int a; // [warn]: Variable a is never used.
82 	}
83 
84 	// Issue 380
85 	int templatedEnum()
86 	{
87 		enum a(T) = T.init;
88 		return a!int;
89 	}
90 
91 	// Issue 380
92 	int otherTemplatedEnum()
93 	{
94 		auto a(T) = T.init; // [warn]: Variable a is never used.
95 		return 0;
96 	}
97 
98 	// Issue 364
99 	void test364_1()
100 	{
101 		enum s = 8;
102 		immutable t = 2;
103 		int[s][t] a;
104 		a[0][0] = 1;
105 	}
106 
107 	void test364_2()
108 	{
109 		enum s = 8;
110 		alias a = e!s;
111 		a = 1;
112 	}
113 
114 	void oops ()
115 	{
116 		class Identity { int val; }
117 		Identity v;
118 		v.val = 0;
119 	}
120 
121 	void main()
122 	{
123 		const int testValue;
124 		testValue.writeln;
125 	}
126 
127 	}}, sac);
128 	stderr.writeln("Unittest for UnusedVariableCheck passed.");
129 }