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 : UnusedStorageCheck
17 {
18 	alias visit = UnusedStorageCheck.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, "Parameter", "unused_parameter");
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 
57 @system unittest
58 {
59 	import std.stdio : stderr;
60 	import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
61 	import dscanner.analysis.helpers : assertAnalyzerWarnings;
62 
63 	StaticAnalysisConfig sac = disabledConfig();
64 	sac.unused_parameter_check = Check.enabled;
65 	assertAnalyzerWarnings(q{
66 
67 	// bug encountered after correct DIP 1009 impl in dparse
68 	version (StdDdoc)
69 	{
70 		bool isAbsolute(R)(R path) pure nothrow @safe
71 		if (isRandomAccessRange!R && isSomeChar!(ElementType!R) ||
72 			is(StringTypeOf!R));
73 	}
74 
75 	void inPSC(in int a){} // [warn]: Parameter a is never used.
76 
77 	void doStuff(int a, int b) // [warn]: Parameter b is never used.
78 	{
79 		return a;
80 	}
81 
82 	// Issue 352
83 	void test352_1()
84 	{
85 		void f(int *x) {*x = 1;}
86 	}
87 
88 	void test352_2()
89 	{
90 		void f(Bat** bat) {*bat = bats.ptr + 8;}
91 	}
92 
93 	// Issue 490
94 	void test490()
95 	{
96 		auto cb1 = delegate(size_t _) {};
97 		cb1(3);
98 		auto cb2 = delegate(size_t a) {}; // [warn]: Parameter a is never used.
99 		cb2(3);
100 	}
101 
102 	bool hasDittos(int decl)
103 	{
104 		mixin("decl++;");
105 	}
106 
107 	// https://github.com/dlang-community/D-Scanner/issues/794
108 	void traits()
109 	{
110 		struct S { int i; }
111 
112 		static foo(S s)
113 		{
114 			__traits(getMember, s, "i") = 99;
115 		}
116 	}
117 
118 	}}, sac);
119 	stderr.writeln("Unittest for UnusedParameterCheck passed.");
120 }