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