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 }