1 //          Copyright Brian Schott (Hackerpilot) 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 
6 module analysis.incorrect_infinite_range;
7 
8 import analysis.base;
9 import analysis.helpers;
10 import dparse.ast;
11 import dparse.lexer;
12 
13 /**
14  * Checks for incorrect infinite range definitions
15  */
16 class IncorrectInfiniteRangeCheck : BaseAnalyzer
17 {
18 	alias visit = BaseAnalyzer.visit;
19 
20 	///
21 	this(string fileName)
22 	{
23 		super(fileName, null);
24 	}
25 
26 	override void visit(const StructBody structBody)
27 	{
28 		inStruct++;
29 		structBody.accept(this);
30 		inStruct--;
31 	}
32 
33 	override void visit(const FunctionDeclaration fd)
34 	{
35 		if (inStruct > 0 && fd.name.text == "empty")
36 		{
37 			line = fd.name.line;
38 			column = fd.name.column;
39 			fd.accept(this);
40 		}
41 	}
42 
43 	override void visit(const FunctionBody fb)
44 	{
45 		if (fb.bodyStatement !is null)
46 			visit(fb.bodyStatement.blockStatement);
47 		else
48 			visit(fb.blockStatement);
49 	}
50 
51 	override void visit(const BlockStatement bs)
52 	{
53 		if (bs.declarationsAndStatements is null)
54 			return;
55 		if (bs.declarationsAndStatements.declarationsAndStatements is null)
56 			return;
57 		if (bs.declarationsAndStatements.declarationsAndStatements.length != 1)
58 			return;
59 		visit(bs.declarationsAndStatements);
60 	}
61 
62 	override void visit(const ReturnStatement rs)
63 	{
64 		if (rs.expression.items.length != 1)
65 			return;
66 		UnaryExpression unary = cast(UnaryExpression) rs.expression.items[0];
67 		if (unary is null)
68 			return;
69 		if (unary.primaryExpression is null)
70 			return;
71 		if (unary.primaryExpression.primary != tok!"false")
72 			return;
73 		addErrorMessage(line, column, KEY, MESSAGE);
74 	}
75 
76 	override void visit(const Unittest u)
77 	{
78 	}
79 
80 private:
81 	uint inStruct;
82 	enum string KEY = "dscanner.suspicios.incorrect_infinite_range";
83 	enum string MESSAGE = "Use `enum bool empty = false;` to define an infinite range.";
84 	size_t line;
85 	size_t column;
86 }
87 
88 unittest
89 {
90 	import std.stdio : stderr;
91 	import analysis.config : StaticAnalysisConfig;
92 	import std.format : format;
93 
94 	StaticAnalysisConfig sac;
95 	sac.incorrect_infinite_range_check = true;
96 	assertAnalyzerWarnings(q{struct InfiniteRange
97 {
98 	bool empty() // [warn]: %1$s
99 	{
100 		return false;
101 	}
102 
103 	bool stuff()
104 	{
105 		return false;
106 	}
107 
108 	unittest
109 	{
110 		return false;
111 	}
112 }
113 
114 bool empty() { return false; }
115 class C { bool empty() { return false; } } // [warn]: %1$s
116 
117 }}
118 		.format(IncorrectInfiniteRangeCheck.MESSAGE), sac);
119 	stderr.writeln("Unittest for IncorrectInfiniteRangeCheck passed.");
120 }