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 }