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 }