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_parameter; 6 7 import dparse.ast; 8 import dparse.lexer; 9 import dscanner.analysis.base; 10 import dscanner.analysis.unused; 11 import dsymbol.scope_ : Scope; 12 13 /** 14 * Checks for unused variables. 15 */ 16 final class UnusedParameterCheck : UnusedIdentifierCheck 17 { 18 alias visit = UnusedIdentifierCheck.visit; 19 20 mixin AnalyzerInfo!"unused_parameter_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 Parameter parameter) 32 { 33 import std.algorithm : among; 34 import std.algorithm.iteration : filter; 35 import std.range : empty; 36 37 if (parameter.name != tok!"") 38 { 39 immutable bool isRef = !parameter.parameterAttributes 40 .filter!(a => a.idType.among(tok!"ref", tok!"out")).empty; 41 immutable bool isPtr = parameter.type && !parameter.type 42 .typeSuffixes.filter!(a => a.star != tok!"").empty; 43 44 variableDeclared(parameter.name.text, parameter.name.line, 45 parameter.name.column, isRef | isPtr); 46 47 if (parameter.default_ !is null) 48 { 49 interestDepth++; 50 parameter.default_.accept(this); 51 interestDepth--; 52 } 53 } 54 } 55 56 override protected void popScope() 57 { 58 foreach (uu; tree[$ - 1]) 59 { 60 if (!uu.isRef && tree.length > 1) 61 { 62 if (uu.uncertain) 63 continue; 64 immutable string errorMessage = "Parameter " ~ uu.name ~ " is never used."; 65 addErrorMessage(uu.line, uu.column, 66 "dscanner.suspicious.unused_parameter", errorMessage); 67 } 68 } 69 tree = tree[0 .. $ - 1]; 70 } 71 } 72 73 @system unittest 74 { 75 import std.stdio : stderr; 76 import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; 77 import dscanner.analysis.helpers : assertAnalyzerWarnings; 78 79 StaticAnalysisConfig sac = disabledConfig(); 80 sac.unused_parameter_check = Check.enabled; 81 assertAnalyzerWarnings(q{ 82 83 // bug encountered after correct DIP 1009 impl in dparse 84 version (StdDdoc) 85 { 86 bool isAbsolute(R)(R path) pure nothrow @safe 87 if (isRandomAccessRange!R && isSomeChar!(ElementType!R) || 88 is(StringTypeOf!R)); 89 } 90 91 void inPSC(in int a){} // [warn]: Parameter a is never used. 92 93 void doStuff(int a, int b) // [warn]: Parameter b is never used. 94 { 95 return a; 96 } 97 98 // Issue 352 99 void test352_1() 100 { 101 void f(int *x) {*x = 1;} 102 } 103 104 void test352_2() 105 { 106 void f(Bat** bat) {*bat = bats.ptr + 8;} 107 } 108 109 // Issue 490 110 void test490() 111 { 112 auto cb1 = delegate(size_t _) {}; 113 cb1(3); 114 auto cb2 = delegate(size_t a) {}; // [warn]: Parameter a is never used. 115 cb2(3); 116 } 117 118 bool hasDittos(int decl) 119 { 120 mixin("decl++;"); 121 } 122 123 }}, sac); 124 stderr.writeln("Unittest for UnusedParameterCheck passed."); 125 }