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