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 dscanner.analysis.numbers;
7 
8 import std.stdio;
9 import std.regex;
10 import dparse.ast;
11 import dparse.lexer;
12 import dscanner.analysis.base;
13 import dscanner.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, bool skipTests = false)
28 	{
29 		super(fileName, sc, skipTests);
30 	}
31 
32 	override void visit(const Token t)
33 	{
34 		import std.algorithm : startsWith;
35 
36 		if (isNumberLiteral(t.type) && !t.text.startsWith("0x")
37 				&& ((t.text.startsWith("0b") && !t.text.matchFirst(badBinaryRegex)
38 					.empty) || !t.text.matchFirst(badDecimalRegex).empty))
39 		{
40 			addErrorMessage(t.line, t.column, "dscanner.style.number_literals",
41 					"Use underscores to improve number constant readability.");
42 		}
43 	}
44 
45 private:
46 	auto badBinaryRegex = ctRegex!(`^0b[01]{9,}`);
47 	auto badDecimalRegex = ctRegex!(`^\d{5,}`);
48 }
49 
50 unittest
51 {
52 	import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
53 
54 	StaticAnalysisConfig sac = disabledConfig();
55 	sac.number_style_check = Check.enabled;
56 	assertAnalyzerWarnings(q{
57 		void testNumbers()
58 		{
59 			int a;
60 			a = 1; // ok
61 			a = 10; // ok
62 			a = 100; // ok
63 			a = 1000; // FIXME: boom
64 			a = 10000; // [warn]: Use underscores to improve number constant readability.
65 			a = 100000; // [warn]: Use underscores to improve number constant readability.
66 			a = 1000000; // [warn]: Use underscores to improve number constant readability.
67 		}
68 	}c, sac);
69 
70 	stderr.writeln("Unittest for NumberStyleCheck passed.");
71 }