1 //          Copyright Brian Schott (Hackerpilot) 2014.
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.numbers;
7 
8 import std.stdio;
9 import std.regex;
10 import dparse.ast;
11 import dparse.lexer;
12 import analysis.base;
13 import analysis.helpers;
14 import dsymbol.scope_ : Scope;
15 
16 /**
17  * Checks for long and hard-to-read number literals
18  */
19 class NumberStyleCheck : BaseAnalyzer
20 {
21 public:
22 	alias visit = BaseAnalyzer.visit;
23 
24 	/**
25 	 * Constructs the style checker with the given file name.
26 	 */
27 	this(string fileName, const(Scope)* sc)
28 	{
29 		super(fileName, sc);
30 	}
31 
32 	override void visit(const Token t)
33 	{
34 		import std.algorithm : startsWith;
35 		if (isNumberLiteral(t.type) && !t.text.startsWith("0x")
36 			&& ((t.text.startsWith("0b") && !t.text.matchFirst(badBinaryRegex).empty)
37 				|| !t.text.matchFirst(badDecimalRegex).empty))
38 		{
39 			addErrorMessage(t.line, t.column, "dscanner.style.number_literals",
40 				"Use underscores to improve number constant readability.");
41 		}
42 	}
43 private:
44 	auto badBinaryRegex = ctRegex!(`^0b[01]{9,}`);
45 	auto badDecimalRegex = ctRegex!(`^\d{5,}`);
46 }
47 
48 unittest
49 {
50 	import analysis.config : StaticAnalysisConfig;
51 	StaticAnalysisConfig sac;
52 	sac.number_style_check = true;
53 	assertAnalyzerWarnings(q{
54 		void testNumbers()
55 		{
56 			int a;
57 			a = 1; // ok
58 			a = 10; // ok
59 			a = 100; // ok
60 			a = 1000; // FIXME: boom
61 			a = 10000; // [warn]: Use underscores to improve number constant readability.
62 			a = 100000; // [warn]: Use underscores to improve number constant readability.
63 			a = 1000000; // [warn]: Use underscores to improve number constant readability.
64 		}
65 	}}, sac);
66 
67 	stderr.writeln("Unittest for NumberStyleCheck passed.");
68 }
69