1+ #ifndef CHIBCC_DIAGNOSTIC_H
2+ #define CHIBCC_DIAGNOSTIC_H
3+
4+ #include " Common.h"
5+
6+ namespace chibcc {
7+
8+ // ===----------------------------------------------------------------------===//
9+ // Diagnostic Levels
10+ // ===----------------------------------------------------------------------===//
11+
12+ enum class DiagnosticLevel {
13+ Ignored = 0 ,
14+ Note,
15+ Remark,
16+ Warning,
17+ Error,
18+ Fatal
19+ };
20+
21+ // ===----------------------------------------------------------------------===//
22+ // Diagnostic IDs
23+ // ===----------------------------------------------------------------------===//
24+
25+ namespace diag {
26+ enum {
27+ #define DIAG (ENUM, LEVEL, DESC ) ENUM,
28+ #include " DiagnosticKinds.def"
29+ NUM_BUILTIN_DIAGNOSTICS
30+ };
31+ } // namespace diag
32+
33+ // ===----------------------------------------------------------------------===//
34+ // Source Location
35+ // ===----------------------------------------------------------------------===//
36+
37+ class SourceLocation {
38+ private:
39+ const char *Ptr;
40+
41+ public:
42+ SourceLocation () : Ptr(nullptr ) {}
43+ explicit SourceLocation (const char *Loc) : Ptr(Loc) {}
44+
45+ bool isValid () const { return Ptr != nullptr ; }
46+ bool isInvalid () const { return Ptr == nullptr ; }
47+
48+ const char *getPointer () const { return Ptr; }
49+
50+ bool operator ==(const SourceLocation &RHS) const { return Ptr == RHS.Ptr ; }
51+ bool operator !=(const SourceLocation &RHS) const { return Ptr != RHS.Ptr ; }
52+ };
53+
54+ // ===----------------------------------------------------------------------===//
55+ // Source Range
56+ // ===----------------------------------------------------------------------===//
57+
58+ class SourceRange {
59+ private:
60+ SourceLocation Begin, End;
61+
62+ public:
63+ SourceRange () = default ;
64+ SourceRange (SourceLocation Loc) : Begin(Loc), End(Loc) {}
65+ SourceRange (SourceLocation Begin, SourceLocation End)
66+ : Begin(Begin), End(End) {}
67+
68+ SourceLocation getBegin () const { return Begin; }
69+ SourceLocation getEnd () const { return End; }
70+
71+ void setBegin (SourceLocation Loc) { Begin = Loc; }
72+ void setEnd (SourceLocation Loc) { End = Loc; }
73+
74+ bool isValid () const { return Begin.isValid () && End.isValid (); }
75+ bool isInvalid () const { return !isValid (); }
76+ };
77+
78+ // ===----------------------------------------------------------------------===//
79+ // Diagnostic Engine
80+ // ===----------------------------------------------------------------------===//
81+
82+ class DiagnosticEngine {
83+ private:
84+ const char *SourceBuffer;
85+ std::string FileName;
86+ unsigned NumWarnings;
87+ unsigned NumErrors;
88+ bool SuppressAllDiagnostics;
89+ bool WarningsAsErrors;
90+
91+ void emitDiagnostic (SourceLocation Loc, DiagnosticLevel Level,
92+ const std::string &Message);
93+ void printSourceLine (SourceLocation Loc);
94+ void printCaretDiagnostic (SourceLocation Loc, SourceRange Range);
95+
96+ public:
97+ DiagnosticEngine (const char *Buffer, const std::string &File = " <input>" )
98+ : SourceBuffer(Buffer), FileName(File), NumWarnings(0 ), NumErrors(0 ),
99+ SuppressAllDiagnostics (false ), WarningsAsErrors(false ) {}
100+
101+ // / \brief Report a diagnostic at the given location.
102+ void report (SourceLocation Loc, unsigned DiagID, const std::string &Message);
103+
104+ // / \brief Report a diagnostic with a source range.
105+ void report (SourceRange Range, unsigned DiagID, const std::string &Message);
106+
107+ // / \brief Convenience methods for common diagnostic levels
108+ void reportError (SourceLocation Loc, const std::string &Message);
109+ void reportWarning (SourceLocation Loc, const std::string &Message);
110+ void reportNote (SourceLocation Loc, const std::string &Message);
111+ void reportFatal (SourceLocation Loc, const std::string &Message);
112+
113+ // / \brief Get diagnostic counts
114+ unsigned getNumWarnings () const { return NumWarnings; }
115+ unsigned getNumErrors () const { return NumErrors; }
116+ bool hasErrorOccurred () const { return NumErrors > 0 ; }
117+
118+ // / \brief Control diagnostic behavior
119+ void setSuppressAllDiagnostics (bool Val = true ) {
120+ SuppressAllDiagnostics = Val;
121+ }
122+ void setWarningsAsErrors (bool Val = true ) { WarningsAsErrors = Val; }
123+
124+ // / \brief Get the diagnostic level for a given diagnostic ID
125+ static DiagnosticLevel getDiagnosticLevel (unsigned DiagID);
126+
127+ // / \brief Get the diagnostic description for a given diagnostic ID
128+ static const char *getDiagnosticText (unsigned DiagID);
129+ };
130+
131+ // ===----------------------------------------------------------------------===//
132+ // Diagnostic Builder
133+ // ===----------------------------------------------------------------------===//
134+
135+ class DiagnosticBuilder {
136+ private:
137+ DiagnosticEngine *Engine;
138+ SourceLocation Loc;
139+ SourceRange Range;
140+ unsigned DiagID;
141+ std::string Message;
142+ bool IsActive;
143+
144+ public:
145+ DiagnosticBuilder (DiagnosticEngine *Engine, SourceLocation Loc,
146+ unsigned DiagID)
147+ : Engine(Engine), Loc(Loc), Range(Loc), DiagID(DiagID), IsActive(true ) {}
148+
149+ DiagnosticBuilder (DiagnosticBuilder &&Other)
150+ : Engine(Other.Engine), Loc(Other.Loc), Range(Other.Range),
151+ DiagID (Other.DiagID), Message(std::move(Other.Message)),
152+ IsActive(Other.IsActive) {
153+ Other.IsActive = false ;
154+ }
155+
156+ ~DiagnosticBuilder () {
157+ if (IsActive && Engine) {
158+ Engine->report (Range, DiagID, Message);
159+ }
160+ }
161+
162+ // / \brief Add a string to the diagnostic message
163+ DiagnosticBuilder &operator <<(const std::string &Str) {
164+ Message += Str;
165+ return *this ;
166+ }
167+
168+ DiagnosticBuilder &operator <<(const char *Str) {
169+ Message += Str;
170+ return *this ;
171+ }
172+
173+ DiagnosticBuilder &operator <<(int Val) {
174+ Message += std::to_string (Val);
175+ return *this ;
176+ }
177+
178+ // / \brief Add a source range to highlight
179+ DiagnosticBuilder &addRange (SourceRange R) {
180+ Range = R;
181+ return *this ;
182+ }
183+
184+ // / \brief Add a fix-it hint
185+ DiagnosticBuilder &addFixItHint (SourceRange, const std::string &Text) {
186+ // For now, just add to message - could be enhanced later
187+ Message += " (fix: replace with '" + Text + " ')" ;
188+ return *this ;
189+ }
190+ };
191+
192+ } // namespace chibcc
193+
194+ #endif // CHIBCC_DIAGNOSTIC_H
0 commit comments