1 /** 2 * Compiler implementation of the 3 * $(LINK2 http://www.dlang.org, D programming language). 4 * 5 * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved 6 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 7 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/errors.d, _errors.d) 9 * Documentation: https://dlang.org/phobos/dmd_errors.html 10 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/errors.d 11 */ 12 13 module dmd.diagnostic; 14 15 import core.stdc.stdarg : va_list; 16 17 import dmd.globals : Loc; 18 19 alias DiagnosticHandler = void delegate(const ref Loc loc, 20 Severity severity, scope const char* messageFormat, 21 va_list args, bool isSupplemental = false) pure nothrow; 22 23 /// The severity level of a diagnostic. 24 enum Severity 25 { 26 /// An error occurred. 27 error, 28 29 /// A warning occurred. 30 warning, 31 32 /// A deprecation occurred. 33 deprecation, 34 } 35 36 struct Diagnostic 37 { 38 /// The location of where the diagnostic occurred. 39 const Loc location; 40 41 /// The message. 42 const string message; 43 44 /// The severity of the diagnostic. 45 const Severity severity; 46 47 /// The supplemental diagnostics belonging to this diagnostic. 48 private const(Diagnostic)[] _supplementalDiagnostics; 49 50 /// Returns: a textual representation of the diagnostic set 51 string toString() const pure 52 { 53 import std.format : format; 54 import std..string : fromStringz; 55 56 return format!"%s:%s:%s: %s: %s%s%(%s\n%)"( 57 location.filename.fromStringz, 58 location.linnum, 59 location.charnum, 60 severity, 61 message, 62 supplementalDiagnostics.length > 0 ? "\n" : "", 63 supplementalDiagnostics 64 ); 65 } 66 67 pure nothrow @safe: 68 69 /// Returns: the supplemental diagnostics attached to this diagnostic. 70 const(Diagnostic[]) supplementalDiagnostics() const @nogc 71 { 72 return _supplementalDiagnostics; 73 } 74 75 /** 76 * Adds a supplemental diagnostic to this diagnostic. 77 * 78 * Params: 79 * diagnostic = the supplemental diagnostic to add 80 */ 81 private void addSupplementalDiagnostic(Diagnostic diagnostic) 82 in(diagnostic.severity == severity) 83 { 84 _supplementalDiagnostics ~= diagnostic; 85 } 86 } 87 88 /// Stores a set of diagnostics. 89 struct DiagnosticSet 90 { 91 private Diagnostic[] _diagnostics; 92 93 pure: 94 95 /// Returns: a textual representation of the diagnostic set 96 string toString() const 97 { 98 import std.format : format; 99 100 return format!"%(%s\n%)"(_diagnostics); 101 } 102 103 @safe nothrow: 104 105 /** 106 * Adds the given diagnostic to the set of diagnostics. 107 * 108 * Params: 109 * diagnostic = the diagnostic to add 110 */ 111 DiagnosticSet opOpAssign(string op)(Diagnostic diagnostic) 112 if (op == "~") 113 { 114 _diagnostics ~= diagnostic; 115 return this; 116 } 117 118 /// ditto 119 void add(Diagnostic diagnostic) 120 { 121 _diagnostics ~= diagnostic; 122 } 123 124 /** 125 * Adds the given supplemental diagnostic to the last added diagnostic. 126 * 127 * Params: 128 * diagnostic = the supplemental diagnostic to add 129 */ 130 void addSupplemental(Diagnostic diagnostic) 131 { 132 _diagnostics[$ - 1].addSupplementalDiagnostic(diagnostic); 133 } 134 135 @nogc: 136 137 /// Returns: the diagnostic at the front of the range. 138 const(Diagnostic) front() const 139 { 140 return _diagnostics[0]; 141 } 142 143 /// Advances the range forward. 144 void popFront() 145 { 146 _diagnostics = _diagnostics[1 .. $]; 147 } 148 149 /// Returns: `true` if no diagnostics are stored. 150 bool empty() const 151 { 152 return _diagnostics.length == 0; 153 } 154 155 /// Returns: the number of diagnostics stored. 156 size_t length() const 157 { 158 return _diagnostics.length; 159 } 160 161 /** 162 * Returns the diagnostic stored at the given index. 163 * 164 * Params: 165 * index = the index of the diagnostic to return 166 * 167 * Returns: the diagnostic 168 */ 169 const(Diagnostic) opIndex(size_t index) const 170 { 171 return _diagnostics[index]; 172 } 173 } 174 175 DiagnosticHandler suppressingDiagnosticHandler = ( 176 const ref Loc loc, 177 Severity severity, 178 scope const char* messageFormat, 179 va_list args, 180 bool isSupplemental = false 181 ) pure nothrow {}; 182 183 struct CollectingDiagnosticHandler 184 { 185 private DiagnosticSet diagnostics_; 186 187 DiagnosticSet diagnostics() pure nothrow @safe @nogc 188 { 189 return diagnostics_; 190 } 191 192 void handleDiagnostic( 193 const ref Loc loc, Severity severity, 194 scope const char* messageFormat, 195 va_list args, 196 bool isSupplemental = false 197 ) pure nothrow 198 { 199 import dmd.root.outbuffer : OutBuffer; 200 201 auto buffer = OutBuffer(); 202 buffer.vprintf(messageFormat, args); 203 auto diagnostic = Diagnostic(loc, buffer.extractSlice, severity); 204 205 if (isSupplemental) 206 diagnostics_.addSupplemental(diagnostic); 207 else 208 diagnostics_ ~= diagnostic; 209 } 210 } 211 212 struct DefaultDiagnosticReporter 213 { 214 void report(DiagnosticSet diagnostics) nothrow 215 { 216 alias ReportingFunction = 217 extern (C++) void function( 218 ref const(Loc) loc, const(char)* format, ... 219 ) nothrow; 220 221 static ReportingFunction getReportingFunction(Severity severity) 222 { 223 import dmd.errors : deprecation, error, warning; 224 225 final switch (severity) 226 { 227 case Severity.error: return &error; 228 case Severity.warning: return &warning; 229 case Severity.deprecation: return &deprecation; 230 } 231 } 232 233 static ReportingFunction getSupplementalReportingFunction(Severity severity) 234 { 235 import dmd.errors : deprecationSupplemental, errorSupplemental, 236 warningSupplemental; 237 238 final switch (severity) 239 { 240 case Severity.error: return &errorSupplemental; 241 case Severity.warning: return &warningSupplemental; 242 case Severity.deprecation: return &deprecationSupplemental; 243 } 244 } 245 246 static void report(const ref Diagnostic diagnostic, ReportingFunction func) 247 { 248 with (diagnostic) 249 func(location, "%.*s", cast(int) message.length, message.ptr); 250 } 251 252 foreach (const ref diagnostic; diagnostics) 253 { 254 const func = getReportingFunction(diagnostic.severity); 255 report(diagnostic, func); 256 257 foreach (const ref supplemental; diagnostic.supplementalDiagnostics) 258 { 259 const supplementalFunc = 260 getSupplementalReportingFunction(diagnostic.severity); 261 report(supplemental, supplementalFunc); 262 } 263 } 264 } 265 } 266 267 struct DefaultDiagnosticHandler 268 { 269 private CollectingDiagnosticHandler handler; 270 private DefaultDiagnosticReporter reporter; 271 272 DiagnosticHandler diagnosticHandler() pure nothrow @nogc @safe return 273 { 274 return &handler.handleDiagnostic; 275 } 276 277 void report() nothrow 278 { 279 reporter.report(handler.diagnostics); 280 handler.diagnostics_ = DiagnosticSet(); 281 } 282 }