1 module dscanner.analysis.base;
2 
3 import std.container;
4 import std..string;
5 import dparse.ast;
6 import std.array;
7 import dsymbol.scope_ : Scope;
8 
9 struct Message
10 {
11 	/// Name of the file where the warning was triggered
12 	string fileName;
13 	/// Line number where the warning was triggered
14 	size_t line;
15 	/// Column number where the warning was triggered (in bytes)
16 	size_t column;
17 	/// Name of the warning
18 	string key;
19 	/// Warning message
20 	string message;
21 	/// Check name
22 	string checkName;
23 }
24 
25 enum comparitor = q{ a.line < b.line || (a.line == b.line && a.column < b.column) };
26 
27 alias MessageSet = RedBlackTree!(Message, comparitor, true);
28 
29 mixin template AnalyzerInfo(string checkName)
30 {
31 	enum string name = checkName;
32 
33 	override protected string getName()
34 	{
35 		return name;
36 	}
37 }
38 
39 abstract class BaseAnalyzer : ASTVisitor
40 {
41 public:
42 	this(string fileName, const Scope* sc, bool skipTests = false)
43 	{
44 		this.sc = sc;
45 		this.fileName = fileName;
46 		this.skipTests = skipTests;
47 		_messages = new MessageSet;
48 	}
49 
50 	protected string getName()
51 	{
52 		assert(0);
53 	}
54 
55 	Message[] messages()
56 	{
57 		return _messages[].array;
58 	}
59 
60 	alias visit = ASTVisitor.visit;
61 
62 	/**
63 	* Visits a unittest.
64 	*
65 	* When overriden, the protected bool "skipTests" should be handled
66 	* so that the content of the test is not analyzed.
67 	*/
68 	override void visit(const Unittest unittest_)
69 	{
70 		if (!skipTests)
71 			unittest_.accept(this);
72 	}
73 
74 protected:
75 
76 	bool inAggregate;
77 	bool skipTests;
78 
79 	template visitTemplate(T)
80 	{
81 		override void visit(const T structDec)
82 		{
83 			inAggregate = true;
84 			structDec.accept(this);
85 			inAggregate = false;
86 		}
87 	}
88 
89 	void addErrorMessage(size_t line, size_t column, string key, string message)
90 	{
91 		_messages.insert(Message(fileName, line, column, key, message, getName()));
92 	}
93 
94 	/**
95 	 * The file name
96 	 */
97 	string fileName;
98 
99 	const(Scope)* sc;
100 
101 	MessageSet _messages;
102 }