ErrorReporter.h (11408B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef frontend_ErrorReporter_h 8 #define frontend_ErrorReporter_h 9 10 #include "mozilla/Variant.h" 11 12 #include <optional> 13 #include <stdarg.h> // for va_list 14 #include <stddef.h> // for size_t 15 #include <stdint.h> // for uint32_t 16 17 #include "js/ColumnNumber.h" // JS::LimitedColumnNumberOneOrigin 18 #include "js/UniquePtr.h" 19 #include "vm/ErrorReporting.h" // ErrorMetadata, ReportCompile{Error,Warning} 20 21 namespace JS { 22 class JS_PUBLIC_API ReadOnlyCompileOptions; 23 } 24 25 namespace js { 26 namespace frontend { 27 28 // An interface class to provide strictMode getter method, which is used by 29 // ErrorReportMixin::strictModeError* methods. 30 // 31 // This class is separated to be used as a back-channel from TokenStream to the 32 // strict mode flag which is available inside Parser, to avoid exposing the 33 // rest of SharedContext to TokenStream. 34 class StrictModeGetter { 35 public: 36 virtual bool strictMode() const = 0; 37 }; 38 39 // This class provides error reporting methods, including warning, extra 40 // warning, and strict mode error. 41 // 42 // A class that inherits this class must provide the following methods: 43 // * options 44 // * getContext 45 // * computeErrorMetadata 46 class ErrorReportMixin : public StrictModeGetter { 47 public: 48 // Returns a compile options (extra warning, warning as error) for current 49 // compilation. 50 virtual const JS::ReadOnlyCompileOptions& options() const = 0; 51 52 // Returns the current context. 53 virtual FrontendContext* getContext() const = 0; 54 55 // A variant class for the offset of the error or warning. 56 struct Current {}; 57 struct NoOffset {}; 58 using ErrorOffset = mozilla::Variant<uint32_t, Current, NoOffset>; 59 60 // Fills ErrorMetadata fields for an error or warning at given offset. 61 // * offset is uint32_t if methods ending with "At" is called 62 // * offset is NoOffset if methods ending with "NoOffset" is called 63 // * offset is Current otherwise 64 [[nodiscard]] virtual bool computeErrorMetadata( 65 ErrorMetadata* err, const ErrorOffset& offset) const = 0; 66 67 // ==== error ==== 68 // 69 // Reports an error. 70 // 71 // Methods ending with "At" are for an error at given offset. 72 // The offset is passed to computeErrorMetadata method and is transparent 73 // for this class. 74 // 75 // Methods ending with "NoOffset" are for an error that doesn't correspond 76 // to any offset. NoOffset is passed to computeErrorMetadata for them. 77 // 78 // Other methods except errorWithNotesAtVA are for an error at the current 79 // offset. Current is passed to computeErrorMetadata for them. 80 // 81 // Methods contains "WithNotes" can be used if there are error notes. 82 // 83 // errorWithNotesAtVA is the actual implementation for all of above. 84 // This can be called if the caller already has a va_list. 85 86 void error(unsigned errorNumber, ...) const { 87 va_list args; 88 va_start(args, errorNumber); 89 90 errorWithNotesAtVA(nullptr, mozilla::AsVariant(Current()), errorNumber, 91 &args); 92 93 va_end(args); 94 } 95 void errorWithNotes(UniquePtr<JSErrorNotes> notes, unsigned errorNumber, 96 ...) const { 97 va_list args; 98 va_start(args, errorNumber); 99 100 errorWithNotesAtVA(std::move(notes), mozilla::AsVariant(Current()), 101 errorNumber, &args); 102 103 va_end(args); 104 } 105 void errorAt(uint32_t offset, unsigned errorNumber, ...) const { 106 va_list args; 107 va_start(args, errorNumber); 108 109 errorWithNotesAtVA(nullptr, mozilla::AsVariant(offset), errorNumber, &args); 110 111 va_end(args); 112 } 113 void errorWithNotesAt(UniquePtr<JSErrorNotes> notes, uint32_t offset, 114 unsigned errorNumber, ...) const { 115 va_list args; 116 va_start(args, errorNumber); 117 118 errorWithNotesAtVA(std::move(notes), mozilla::AsVariant(offset), 119 errorNumber, &args); 120 121 va_end(args); 122 } 123 void errorNoOffset(unsigned errorNumber, ...) const { 124 va_list args; 125 va_start(args, errorNumber); 126 127 errorWithNotesAtVA(nullptr, mozilla::AsVariant(NoOffset()), errorNumber, 128 &args); 129 130 va_end(args); 131 } 132 void errorWithNotesNoOffset(UniquePtr<JSErrorNotes> notes, 133 unsigned errorNumber, ...) const { 134 va_list args; 135 va_start(args, errorNumber); 136 137 errorWithNotesAtVA(std::move(notes), mozilla::AsVariant(NoOffset()), 138 errorNumber, &args); 139 140 va_end(args); 141 } 142 void errorWithNotesAtVA(UniquePtr<JSErrorNotes> notes, 143 const ErrorOffset& offset, unsigned errorNumber, 144 va_list* args) const { 145 ErrorMetadata metadata; 146 if (!computeErrorMetadata(&metadata, offset)) { 147 return; 148 } 149 150 ReportCompileErrorLatin1VA(getContext(), std::move(metadata), 151 std::move(notes), errorNumber, args); 152 } 153 154 // ==== warning ==== 155 // 156 // Reports a warning. 157 // 158 // Returns true if the warning is reported. 159 // Returns false if the warning is treated as an error, or an error occurs 160 // while reporting. 161 // 162 // See the comment on the error section for details on what the arguments 163 // and function names indicate for all these functions. 164 165 [[nodiscard]] bool warning(unsigned errorNumber, ...) const { 166 va_list args; 167 va_start(args, errorNumber); 168 169 bool result = warningWithNotesAtVA(nullptr, mozilla::AsVariant(Current()), 170 errorNumber, &args); 171 172 va_end(args); 173 174 return result; 175 } 176 [[nodiscard]] bool warningAt(uint32_t offset, unsigned errorNumber, 177 ...) const { 178 va_list args; 179 va_start(args, errorNumber); 180 181 bool result = warningWithNotesAtVA(nullptr, mozilla::AsVariant(offset), 182 errorNumber, &args); 183 184 va_end(args); 185 186 return result; 187 } 188 [[nodiscard]] bool warningNoOffset(unsigned errorNumber, ...) const { 189 va_list args; 190 va_start(args, errorNumber); 191 192 bool result = warningWithNotesAtVA(nullptr, mozilla::AsVariant(NoOffset()), 193 errorNumber, &args); 194 195 va_end(args); 196 197 return result; 198 } 199 [[nodiscard]] bool warningWithNotesAtVA(UniquePtr<JSErrorNotes> notes, 200 const ErrorOffset& offset, 201 unsigned errorNumber, 202 va_list* args) const { 203 ErrorMetadata metadata; 204 if (!computeErrorMetadata(&metadata, offset)) { 205 return false; 206 } 207 208 return compileWarning(std::move(metadata), std::move(notes), errorNumber, 209 args); 210 } 211 212 // ==== strictModeError ==== 213 // 214 // Reports an error if in strict mode code, or warn if not. 215 // 216 // Returns true if not in strict mode and a warning is reported. 217 // Returns false if the error reported, or an error occurs while reporting. 218 // 219 // See the comment on the error section for details on what the arguments 220 // and function names indicate for all these functions. 221 222 [[nodiscard]] bool strictModeError(unsigned errorNumber, ...) const { 223 va_list args; 224 va_start(args, errorNumber); 225 226 bool result = strictModeErrorWithNotesAtVA( 227 nullptr, mozilla::AsVariant(Current()), errorNumber, &args); 228 229 va_end(args); 230 231 return result; 232 } 233 [[nodiscard]] bool strictModeErrorWithNotes(UniquePtr<JSErrorNotes> notes, 234 unsigned errorNumber, ...) const { 235 va_list args; 236 va_start(args, errorNumber); 237 238 bool result = strictModeErrorWithNotesAtVA( 239 std::move(notes), mozilla::AsVariant(Current()), errorNumber, &args); 240 241 va_end(args); 242 243 return result; 244 } 245 [[nodiscard]] bool strictModeErrorAt(uint32_t offset, unsigned errorNumber, 246 ...) const { 247 va_list args; 248 va_start(args, errorNumber); 249 250 bool result = strictModeErrorWithNotesAtVA( 251 nullptr, mozilla::AsVariant(offset), errorNumber, &args); 252 253 va_end(args); 254 255 return result; 256 } 257 [[nodiscard]] bool strictModeErrorWithNotesAt(UniquePtr<JSErrorNotes> notes, 258 uint32_t offset, 259 unsigned errorNumber, 260 ...) const { 261 va_list args; 262 va_start(args, errorNumber); 263 264 bool result = strictModeErrorWithNotesAtVA( 265 std::move(notes), mozilla::AsVariant(offset), errorNumber, &args); 266 267 va_end(args); 268 269 return result; 270 } 271 [[nodiscard]] bool strictModeErrorNoOffset(unsigned errorNumber, ...) const { 272 va_list args; 273 va_start(args, errorNumber); 274 275 bool result = strictModeErrorWithNotesAtVA( 276 nullptr, mozilla::AsVariant(NoOffset()), errorNumber, &args); 277 278 va_end(args); 279 280 return result; 281 } 282 [[nodiscard]] bool strictModeErrorWithNotesNoOffset( 283 UniquePtr<JSErrorNotes> notes, unsigned errorNumber, ...) const { 284 va_list args; 285 va_start(args, errorNumber); 286 287 bool result = strictModeErrorWithNotesAtVA( 288 std::move(notes), mozilla::AsVariant(NoOffset()), errorNumber, &args); 289 290 va_end(args); 291 292 return result; 293 } 294 [[nodiscard]] bool strictModeErrorWithNotesAtVA(UniquePtr<JSErrorNotes> notes, 295 const ErrorOffset& offset, 296 unsigned errorNumber, 297 va_list* args) const { 298 if (!strictMode()) { 299 return true; 300 } 301 302 ErrorMetadata metadata; 303 if (!computeErrorMetadata(&metadata, offset)) { 304 return false; 305 } 306 307 ReportCompileErrorLatin1VA(getContext(), std::move(metadata), 308 std::move(notes), errorNumber, args); 309 return false; 310 } 311 312 // Reports a warning, or an error if the warning is treated as an error. 313 [[nodiscard]] bool compileWarning(ErrorMetadata&& metadata, 314 UniquePtr<JSErrorNotes> notes, 315 unsigned errorNumber, va_list* args) const { 316 return ReportCompileWarning(getContext(), std::move(metadata), 317 std::move(notes), errorNumber, args); 318 } 319 }; 320 321 // An interface class to provide miscellaneous methods used by error reporting 322 // etc. They're mostly used by BytecodeCompiler, BytecodeEmitter, and helper 323 // classes for emitter. 324 class ErrorReporter : public ErrorReportMixin { 325 public: 326 // Returns Some(true) if the given offset is inside the given line 327 // number `lineNum`, or Some(false) otherwise. 328 // 329 // Return None if an error happens. This method itself doesn't report an 330 // error, and any failure is supposed to be reported as OOM in the caller. 331 virtual std::optional<bool> isOnThisLine(size_t offset, 332 uint32_t lineNum) const = 0; 333 334 // Returns the line number for given offset. 335 virtual uint32_t lineAt(size_t offset) const = 0; 336 337 // Returns the column number for given offset. 338 virtual JS::LimitedColumnNumberOneOrigin columnAt(size_t offset) const = 0; 339 }; 340 341 } // namespace frontend 342 } // namespace js 343 344 #endif // frontend_ErrorReporter_h