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 }
22 
23 enum comparitor = q{ a.line < b.line || (a.line == b.line && a.column < b.column) };
24 
25 alias MessageSet = RedBlackTree!(Message, comparitor, true);
26 
27 abstract class BaseAnalyzer : ASTVisitor
28 {
29 public:
30 	this(string fileName, const Scope* sc, bool skipTests = false)
31 	{
32 		this.sc = sc;
33 		this.fileName = fileName;
34 		this.skipTests = skipTests;
35 		_messages = new MessageSet;
36 	}
37 
38 	Message[] messages()
39 	{
40 		return _messages[].array;
41 	}
42 
43 	alias visit = ASTVisitor.visit;
44 
45 	/**
46 	* Visits a unittest.
47 	*
48 	* When overriden, the protected bool "skipTests" should be handled
49 	* so that the content of the test is not analyzed.
50 	*/
51 	override void visit(const Unittest unittest_)
52 	{
53 		if (!skipTests)
54 			unittest_.accept(this);
55 	}
56 
57 protected:
58 
59 	bool inAggregate;
60 	bool skipTests;
61 
62 	template visitTemplate(T)
63 	{
64 		override void visit(const T structDec)
65 		{
66 			inAggregate = true;
67 			structDec.accept(this);
68 			inAggregate = false;
69 		}
70 	}
71 
72 	void addErrorMessage(size_t line, size_t column, string key, string message)
73 	{
74 		_messages.insert(Message(fileName, line, column, key, message));
75 	}
76 
77 	/**
78 	 * The file name
79 	 */
80 	string fileName;
81 
82 	const(Scope)* sc;
83 
84 	MessageSet _messages;
85 }