1 //          Copyright Brian Schott (Hackerpilot) 2016.
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 
6 module dscanner.analysis.lambda_return_check;
7 
8 import dparse.ast;
9 import dparse.lexer;
10 import dscanner.analysis.base;
11 import dscanner.utils : safeAccess;
12 
13 final class LambdaReturnCheck : BaseAnalyzer
14 {
15 	alias visit = BaseAnalyzer.visit;
16 
17 	this(string fileName, bool skipTests = false)
18 	{
19 		super(fileName, null, skipTests);
20 	}
21 
22 	override void visit(const FunctionLiteralExpression fLit)
23 	{
24 		auto fe = safeAccess(fLit).assignExpression.as!UnaryExpression
25 			.primaryExpression.functionLiteralExpression.unwrap;
26 
27 		if (fe is null || fe.parameters !is null || fe.identifier != tok!"" ||
28 			fe.specifiedFunctionBody is null || fe.specifiedFunctionBody.blockStatement is null)
29 		{
30 			return;
31 		}
32 		addErrorMessage(fLit.line, fLit.column, KEY, "This lambda returns a lambda. Add parenthesis to clarify.");
33 	}
34 
35 private:
36 	enum KEY = "dscanner.confusing.lambda_returns_lambda";
37 }
38 
39 version(Windows) {/*because of newline in code*/} else
40 unittest
41 {
42 	import dscanner.analysis.helpers : assertAnalyzerWarnings;
43 	import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
44 	import std.stdio : stderr;
45 
46 	StaticAnalysisConfig sac = disabledConfig();
47 	sac.lambda_return_check = Check.enabled;
48 
49 	auto code = `
50 		void main()
51 		{
52 			int[] b;
53 			auto a = b.map!(a => { return a * a + 2; }).array(); // [warn]: This lambda returns a lambda. Add parenthesis to clarify.
54 			pragma(msg, typeof(a => { return a; })); // [warn]: This lambda returns a lambda. Add parenthesis to clarify.
55 			pragma(msg, typeof((a) => { return a; })); // [warn]: This lambda returns a lambda. Add parenthesis to clarify.
56 			pragma(msg, typeof({ return a; }));
57 			pragma(msg, typeof(a => () { return a; }));
58 		}`c;
59 	assertAnalyzerWarnings(code, sac);
60 	stderr.writeln("Unittest for LambdaReturnCheck passed.");
61 }