From c9b9bb74442a18b26df08c790a81559220ad53d1 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Tue, 24 Oct 2023 20:01:00 -0400 Subject: [PATCH 001/117] feat(emacs): add test for Flymake Our existing Flymake testing is weak. Add a test which covers almost all of the Flymake plugin's code. --- plugin/emacs/test/quicklintjs-test.el | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/plugin/emacs/test/quicklintjs-test.el b/plugin/emacs/test/quicklintjs-test.el index 53cb5ae129..5bd1cfaf83 100644 --- a/plugin/emacs/test/quicklintjs-test.el +++ b/plugin/emacs/test/quicklintjs-test.el @@ -9,6 +9,8 @@ (expand-file-name default-directory) ".melpa-cache/")) +(setq quicklintjs-test-dir (file-name-directory (or load-file-name buffer-file-name))) + (defun quicklintjs-install-deps (deps) (mapcar (lambda (pkg) (unless (package-installed-p pkg) (if (> emacs-major-version 24) @@ -39,6 +41,11 @@ (defun def-flymake-tests () (require 'flymake-quicklintjs) + + ; Disable warning which causes tests to fail when run non-interactively: + ; "Disabling backend flymake-proc-legacy-flymake because (error Can’t find a suitable init function)" + (remove-hook 'flymake-diagnostic-functions 'flymake-proc-legacy-flymake) + (ert-deftest quicklintjs-flymake-parse-errors-and-warnings () (skip-unless (>= emacs-major-version 26)) (let ((js-buf (generate-new-buffer "*js-buf*"))) @@ -89,7 +96,21 @@ foobar\")((16 . 22) 2 \"E0057\" \"use of undeclared variable: foobar\")(\ (point-min) (point-max) flymake-quicklintjs-program nil out-buf nil "--stdin" - "--output-format=emacs-lisp") 0)))))) + "--output-format=emacs-lisp") 0))))) + + (ert-deftest quicklintjs-flymake-check-errors-js () + (with-temp-buffer + (javascript-mode) + (insert-file-contents-literally (expand-file-name "error.js" quicklintjs-test-dir) nil nil nil t) + (flymake-mode 1) + (add-hook 'flymake-diagnostic-functions #'flymake-quicklintjs nil t) + (flymake-start) + + (with-timeout (5 + (ert-fail "Test timed out waiting for diagnostics.")) + ;; TODO(strager): Assert specific diagnostics + (while (not (flymake-diagnostics)) + (accept-process-output nil 0.01)))))) (defun def-eglot-tests () (ert-deftest quicklintjs-is-in-eglot-servers () From 457ece728fb9ec8b3a7964af8c219f6846b196a9 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Tue, 24 Oct 2023 20:01:28 -0400 Subject: [PATCH 002/117] fix(emacs): clear diagnostics properly in Flymake When our Flymake code set diagnostics, it set them for the whole buffer with :range. However, the :range was incorrect; the begin/end points given were for the *stdout* temporary buffer, not for the user's code buffer. This meant that Flymake diagnostics markers were often not removed because they were not inside the range. (stdout is often much smaller than the JavaScript source being linted.) Fix this by using :range with points derived from the correct buffer. --- docs/CHANGELOG.md | 2 ++ plugin/emacs/flymake-quicklintjs.el | 13 +++++++------ plugin/emacs/test/quicklintjs-test.el | 24 ++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index d4e10ea55e..8575115fbd 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -50,6 +50,8 @@ Semantic Versioning. in the head of a `for` loop. For example, quick-lint-js no longer warns about `let x; for (let x = 0;;);`. * Emacs: .el files are now installed in the correct place on Arch Linux, btw. +* Emacs: The Flymake plugin now reliably clears out diagnostics after issues are + fixed. Sticky diagnostics are no more. * TypeScript support (still experimental): * A newline after `public`, `protected`, `private`, or `readonly` inside a class is now interpreted correctly. diff --git a/plugin/emacs/flymake-quicklintjs.el b/plugin/emacs/flymake-quicklintjs.el index d29d46a624..a007925f9b 100644 --- a/plugin/emacs/flymake-quicklintjs.el +++ b/plugin/emacs/flymake-quicklintjs.el @@ -96,12 +96,13 @@ REPORT-FN is Flymake's callback." (point-min) (point-max)))) (if (not (string-empty-p stderr-data)) (flymake-log :warning "%S" stderr-data)))) - (with-current-buffer stdout-buf - (let ((diags (flymake-quicklintjs--make-diagnostics - src-buf - (car (read-from-string - (buffer-substring-no-properties - (point-min) (point-max))))))) + (let ((diags (flymake-quicklintjs--make-diagnostics + src-buf + (car (read-from-string + (with-current-buffer stdout-buf + (buffer-substring-no-properties + (point-min) (point-max)))))))) + (with-current-buffer src-buf (if (or diags (zerop (process-exit-status p))) (funcall report-fn diags :region (cons (point-min) (point-max))) diff --git a/plugin/emacs/test/quicklintjs-test.el b/plugin/emacs/test/quicklintjs-test.el index 5bd1cfaf83..cbdc597432 100644 --- a/plugin/emacs/test/quicklintjs-test.el +++ b/plugin/emacs/test/quicklintjs-test.el @@ -110,6 +110,30 @@ foobar\")((16 . 22) 2 \"E0057\" \"use of undeclared variable: foobar\")(\ (ert-fail "Test timed out waiting for diagnostics.")) ;; TODO(strager): Assert specific diagnostics (while (not (flymake-diagnostics)) + (accept-process-output nil 0.01))))) + + ;; This is a regression test. Buffers were mixed up causing + ;; diagnostics after a certain point (usually a few bytes in) to not + ;; be cleared. + (ert-deftest quicklintjs-flymake-fixing-error-clears-diagnostics () + (with-temp-buffer + (javascript-mode) + (insert "/*xxx*/ consol") + (flymake-mode 1) + (add-hook 'flymake-diagnostic-functions #'flymake-quicklintjs nil t) + (flymake-start) + + (with-timeout (5 + (ert-fail "Test timed out waiting for diagnostics.")) + (while (not (flymake-diagnostics)) + (accept-process-output nil 0.01))) + + (insert "e") ;; Buffer content: /*xxx*/ console + (flymake-start) + + (with-timeout (5 + (ert-fail "Test timed out waiting for diagnostics to be removed.")) + (while (flymake-diagnostics) (accept-process-output nil 0.01)))))) (defun def-eglot-tests () From 4bf1896ce5c973805f3a1723a0ee2444cb6a5a9d Mon Sep 17 00:00:00 2001 From: Ariel Don Date: Wed, 25 Oct 2023 19:30:04 -0400 Subject: [PATCH 003/117] feat: error on multiple export defaults in module --- docs/errors/E0715.md | 31 +++++++++++++++++++ po/messages.pot | 8 +++++ .../diag/diagnostic-metadata-generated.cpp | 18 +++++++++++ .../diag/diagnostic-metadata-generated.h | 3 +- src/quick-lint-js/diag/diagnostic-types-2.h | 11 +++++++ src/quick-lint-js/fe/parse-statement.cpp | 13 ++++++++ src/quick-lint-js/fe/parse.h | 5 +++ .../i18n/translation-table-generated.cpp | 6 +++- .../i18n/translation-table-generated.h | 6 ++-- .../i18n/translation-table-test-generated.h | 24 +++++++++++++- test/test-parse-module.cpp | 18 +++++++++++ 11 files changed, 138 insertions(+), 5 deletions(-) create mode 100644 docs/errors/E0715.md diff --git a/docs/errors/E0715.md b/docs/errors/E0715.md new file mode 100644 index 0000000000..2fd63b9315 --- /dev/null +++ b/docs/errors/E0715.md @@ -0,0 +1,31 @@ +# E0715: cannot use multiple `export default` statements in one module + +Modules in JavaScript can use two types of exports: default export and named export. While a module +can use multiple named exports, it can only use a single default export. + + +```javascript +export default function foo() { + console.log("foo"); +} + +export default function bar() { + console.log("bar"); +} +``` + + +If you want to export several values from a module, use named exports. + + +```javascript +function foo(x) { + console.log("foo"); +} + +function bar(x) { + console.log("bar"); +} + +export { foo, bar }; +``` diff --git a/po/messages.pot b/po/messages.pot index baa254be30..57504375ed 100644 --- a/po/messages.pot +++ b/po/messages.pot @@ -2081,6 +2081,14 @@ msgstr "" msgid "'async' keyword is not allowed on getters or setters" msgstr "" +#: src/quick-lint-js/diag/diagnostic-metadata-generated.cpp +msgid "cannot use multiple `export default` statements in one module" +msgstr "" + +#: src/quick-lint-js/diag/diagnostic-metadata-generated.cpp +msgid "export default previously appeared here" +msgstr "" + #: test/test-diagnostic-formatter.cpp #: test/test-vim-qflist-json-diag-reporter.cpp msgid "something happened" diff --git a/src/quick-lint-js/diag/diagnostic-metadata-generated.cpp b/src/quick-lint-js/diag/diagnostic-metadata-generated.cpp index e53d4f6276..8f4b3cface 100644 --- a/src/quick-lint-js/diag/diagnostic-metadata-generated.cpp +++ b/src/quick-lint-js/diag/diagnostic-metadata-generated.cpp @@ -6407,6 +6407,24 @@ const QLJS_CONSTINIT Diagnostic_Info all_diagnostic_infos[] = { }, }, }, + + // Diag_Multiple_Export_Defaults + { + .code = 715, + .severity = Diagnostic_Severity::error, + .message_formats = { + QLJS_TRANSLATABLE("cannot use multiple `export default` statements in one module"), + QLJS_TRANSLATABLE("export default previously appeared here"), + }, + .message_args = { + { + Diagnostic_Message_Arg_Info(offsetof(Diag_Multiple_Export_Defaults, second_export_default), Diagnostic_Arg_Type::source_code_span), + }, + { + Diagnostic_Message_Arg_Info(offsetof(Diag_Multiple_Export_Defaults, first_export_default), Diagnostic_Arg_Type::source_code_span), + }, + }, + }, }; } diff --git a/src/quick-lint-js/diag/diagnostic-metadata-generated.h b/src/quick-lint-js/diag/diagnostic-metadata-generated.h index 28d0409760..ce26201539 100644 --- a/src/quick-lint-js/diag/diagnostic-metadata-generated.h +++ b/src/quick-lint-js/diag/diagnostic-metadata-generated.h @@ -439,10 +439,11 @@ namespace quick_lint_js { QLJS_DIAG_TYPE_NAME(Diag_Missing_Comma_Between_Array_Elements) \ QLJS_DIAG_TYPE_NAME(Diag_Class_Generator_On_Getter_Or_Setter) \ QLJS_DIAG_TYPE_NAME(Diag_Class_Async_On_Getter_Or_Setter) \ + QLJS_DIAG_TYPE_NAME(Diag_Multiple_Export_Defaults) \ /* END */ // clang-format on -inline constexpr int Diag_Type_Count = 428; +inline constexpr int Diag_Type_Count = 429; extern const Diagnostic_Info all_diagnostic_infos[Diag_Type_Count]; } diff --git a/src/quick-lint-js/diag/diagnostic-types-2.h b/src/quick-lint-js/diag/diagnostic-types-2.h index 07918727b5..59839d2462 100644 --- a/src/quick-lint-js/diag/diagnostic-types-2.h +++ b/src/quick-lint-js/diag/diagnostic-types-2.h @@ -3307,6 +3307,17 @@ struct Diag_Class_Async_On_Getter_Or_Setter { Source_Code_Span async_keyword; Source_Code_Span getter_setter_keyword; }; + +struct Diag_Multiple_Export_Defaults { + [[qljs::diag("E0715", Diagnostic_Severity::error)]] // + [[qljs::message( + "cannot use multiple `export default` statements in one module", + ARG(second_export_default))]] // + [[qljs::message("export default previously appeared here", + ARG(first_export_default))]] // + Source_Code_Span second_export_default; + Source_Code_Span first_export_default; +}; } QLJS_WARNING_POP diff --git a/src/quick-lint-js/fe/parse-statement.cpp b/src/quick-lint-js/fe/parse-statement.cpp index 8902971c06..f97a0b74f6 100644 --- a/src/quick-lint-js/fe/parse-statement.cpp +++ b/src/quick-lint-js/fe/parse-statement.cpp @@ -35,6 +35,8 @@ bool Parser::parse_and_visit_module_catching_fatal_parse_errors( } void Parser::parse_and_visit_module(Parse_Visitor_Base &v) { + QLJS_ASSERT( + !this->first_export_default_statement_default_keyword_.has_value()); bool done = false; Parse_Statement_Options statement_options = { .possibly_followed_by_another_statement = true, @@ -1011,6 +1013,17 @@ void Parser::parse_and_visit_export(Parse_Visitor_Base &v, switch (this->peek().type) { // export default class C {} case Token_Type::kw_default: + if (this->first_export_default_statement_default_keyword_.has_value()) { + this->diag_reporter_->report(Diag_Multiple_Export_Defaults{ + .second_export_default = this->peek().span(), + .first_export_default = + *this->first_export_default_statement_default_keyword_, + }); + } else { + this->first_export_default_statement_default_keyword_ = + this->peek().span(); + } + this->is_current_typescript_namespace_non_empty_ = true; if (this->in_typescript_namespace_or_module_.has_value() && !this->in_typescript_module_) { diff --git a/src/quick-lint-js/fe/parse.h b/src/quick-lint-js/fe/parse.h index e5a8790db6..69d55e4f1c 100644 --- a/src/quick-lint-js/fe/parse.h +++ b/src/quick-lint-js/fe/parse.h @@ -545,6 +545,11 @@ class Parser { void parse_and_visit_named_exports_for_typescript_type_only_import( Parse_Visitor_Base &v, Source_Code_Span type_keyword); + // If set, refers to the first `export default` statement in this module. A + // module cannot contain more than one `export default`. + std::optional + first_export_default_statement_default_keyword_ = std::nullopt; + struct Parse_Export_Options { TypeScript_Declare_Context declare_context; diff --git a/src/quick-lint-js/i18n/translation-table-generated.cpp b/src/quick-lint-js/i18n/translation-table-generated.cpp index ace2dc583b..04ee6b82d4 100644 --- a/src/quick-lint-js/i18n/translation-table-generated.cpp +++ b/src/quick-lint-js/i18n/translation-table-generated.cpp @@ -206,6 +206,7 @@ const Translation_Table translation_data = { {0, 0, 0, 67, 0, 53}, // {0, 0, 0, 0, 0, 37}, // {0, 0, 0, 0, 0, 43}, // + {0, 0, 0, 0, 0, 62}, // {0, 0, 0, 50, 0, 47}, // {72, 31, 71, 68, 56, 61}, // {34, 30, 0, 46, 0, 40}, // @@ -259,7 +260,8 @@ const Translation_Table translation_data = { {33, 27, 36, 45, 0, 35}, // {39, 42, 0, 49, 0, 41}, // {24, 24, 0, 24, 0, 24}, // - {22, 22, 42, 22, 40, 22}, // + {0, 0, 0, 0, 0, 22}, // + {22, 22, 42, 22, 40, 40}, // {32, 30, 35, 26, 30, 29}, // {0, 0, 0, 27, 0, 32}, // {35, 45, 38, 53, 33, 46}, // @@ -1998,6 +2000,7 @@ const Translation_Table translation_data = { u8"cannot update variable with '{0}' while declaring it\0" u8"cannot use '...' on 'this' parameter\0" u8"cannot use 'declare' keyword with 'import'\0" + u8"cannot use multiple `export default` statements in one module\0" u8"cannot use type directly in its own definition\0" u8"catch variable can only be typed as '*', 'any', or 'unknown'\0" u8"character is not allowed in identifiers\0" @@ -2052,6 +2055,7 @@ const Translation_Table translation_data = { u8"expected variable name for 'import'-'as'\0" u8"expected {1:headlinese}\0" u8"expected {1:singular}\0" + u8"export default previously appeared here\0" u8"exporting requires 'default'\0" u8"exporting requires '{{' and '}'\0" u8"extra ',' is not allowed between enum members\0" diff --git a/src/quick-lint-js/i18n/translation-table-generated.h b/src/quick-lint-js/i18n/translation-table-generated.h index 16657ed1f5..514e20b711 100644 --- a/src/quick-lint-js/i18n/translation-table-generated.h +++ b/src/quick-lint-js/i18n/translation-table-generated.h @@ -18,8 +18,8 @@ namespace quick_lint_js { using namespace std::literals::string_view_literals; constexpr std::uint32_t translation_table_locale_count = 5; -constexpr std::uint16_t translation_table_mapping_table_size = 522; -constexpr std::size_t translation_table_string_table_size = 79941; +constexpr std::uint16_t translation_table_mapping_table_size = 524; +constexpr std::size_t translation_table_string_table_size = 80043; constexpr std::size_t translation_table_locale_table_size = 35; QLJS_CONSTEVAL std::uint16_t translation_table_const_look_up( @@ -220,6 +220,7 @@ QLJS_CONSTEVAL std::uint16_t translation_table_const_look_up( "cannot update variable with '{0}' while declaring it"sv, "cannot use '...' on 'this' parameter"sv, "cannot use 'declare' keyword with 'import'"sv, + "cannot use multiple `export default` statements in one module"sv, "cannot use type directly in its own definition"sv, "catch variable can only be typed as '*', 'any', or 'unknown'"sv, "character is not allowed in identifiers"sv, @@ -274,6 +275,7 @@ QLJS_CONSTEVAL std::uint16_t translation_table_const_look_up( "expected variable name for 'import'-'as'"sv, "expected {1:headlinese}"sv, "expected {1:singular}"sv, + "export default previously appeared here"sv, "exporting requires 'default'"sv, "exporting requires '{{' and '}'"sv, "extra ',' is not allowed between enum members"sv, diff --git a/src/quick-lint-js/i18n/translation-table-test-generated.h b/src/quick-lint-js/i18n/translation-table-test-generated.h index f50238d171..59c04ad26a 100644 --- a/src/quick-lint-js/i18n/translation-table-test-generated.h +++ b/src/quick-lint-js/i18n/translation-table-test-generated.h @@ -27,7 +27,7 @@ struct Translated_String { }; // clang-format off -inline const Translated_String test_translation_table[521] = { +inline const Translated_String test_translation_table[523] = { { "\"global-groups\" entries must be strings"_translatable, u8"\"global-groups\" entries must be strings", @@ -2162,6 +2162,17 @@ inline const Translated_String test_translation_table[521] = { u8"cannot use 'declare' keyword with 'import'", }, }, + { + "cannot use multiple `export default` statements in one module"_translatable, + u8"cannot use multiple `export default` statements in one module", + { + u8"cannot use multiple `export default` statements in one module", + u8"cannot use multiple `export default` statements in one module", + u8"cannot use multiple `export default` statements in one module", + u8"cannot use multiple `export default` statements in one module", + u8"cannot use multiple `export default` statements in one module", + }, + }, { "cannot use type directly in its own definition"_translatable, u8"cannot use type directly in its own definition", @@ -2756,6 +2767,17 @@ inline const Translated_String test_translation_table[521] = { u8"expected {1:singular}", }, }, + { + "export default previously appeared here"_translatable, + u8"export default previously appeared here", + { + u8"export default previously appeared here", + u8"export default previously appeared here", + u8"export default previously appeared here", + u8"export default previously appeared here", + u8"export default previously appeared here", + }, + }, { "exporting requires 'default'"_translatable, u8"exporting requires 'default'", diff --git a/test/test-parse-module.cpp b/test/test-parse-module.cpp index 4bfee6a51e..a6dac87cec 100644 --- a/test/test-parse-module.cpp +++ b/test/test-parse-module.cpp @@ -162,6 +162,24 @@ TEST_F(Test_Parse_Module, export_default) { })); } + { + Spy_Visitor p = test_parse_and_visit_module( + u8"export default class A {} export default class B {}"_sv, // + u8" ^^^^^^^ Diag_Multiple_Export_Defaults.first_export_default\n" + u8" ^^^^^^^ .second_export_default"_diag); + EXPECT_THAT(p.visits, ElementsAreArray({ + "visit_enter_class_scope", // A + "visit_enter_class_scope_body", // + "visit_exit_class_scope", // + "visit_variable_declaration", // + "visit_enter_class_scope", // B + "visit_enter_class_scope_body", // + "visit_exit_class_scope", // + "visit_variable_declaration", // + "visit_end_of_module", + })); + } + { Spy_Visitor p = test_parse_and_visit_statement( u8"export default async (a) => b;"_sv, no_diags, javascript_options); From d4dae96550385e8a033997e3db97301cc5f9b99b Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Wed, 25 Oct 2023 19:35:07 -0400 Subject: [PATCH 004/117] feat(docs): update changelog and authors --- docs/AUTHORS.md | 1 + docs/CHANGELOG.md | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/docs/AUTHORS.md b/docs/AUTHORS.md index 10fc34d955..2972c7948c 100644 --- a/docs/AUTHORS.md +++ b/docs/AUTHORS.md @@ -29,6 +29,7 @@ authored portions of quick-lint-js: * Amir; amir77mafi@gmail.com; signed CLA-v1.md * Ang Kosal; angkosal@gmail.com; signed CLA-v1.md * Angel Avila; angel.j.avila@gmail.com; signed CLA-v1.md +* Ariel Don; ariel@arieldon.com; signed CLA-v1.md * Asaduzzaman Pavel; k1ngs.k1ngdom@live.com; signed CLA-v1.md * Austin Garcia; theholychowders@gmail.com; signed CLA-v1.md * Biel A. P. (0xbiel); bielp07@gmail.com; signed CLA-v1.md diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 8575115fbd..0df95f2f24 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -21,6 +21,9 @@ Semantic Versioning. setters cannot be generators"). (Implemented by [koopiehoop][].) * `async get` and `async set` in classes now report [E0714][] ("'async' keyword is not allowed on getters or setters"). (Implemented by [koopiehoop][].) +* Multiple `export default` statements now report [E0715][] ("cannot use + multiple `export default` statements in one module"). (Implemented by + [Ariel Don][].) * Emacs: The Debian/Ubuntu package now installs the Emacs plugin. Manual installation of the .el files is no longer required. * CLI: The new `--stdin-path` CLI option allows users of the `--stdin` option @@ -1076,6 +1079,7 @@ Beta release. [AidenThing]: https://github.com/AidenThing [Alek Lefebvre]: https://github.com/AlekLefebvre [Amir]: https://github.com/ahmafi +[Ariel Don]: https://github.com/arieldon [Austin Garcia]: https://github.com/holychowders [Christian Mund]: https://github.com/kkkrist [Daniel La Rocque]: https://github.com/dlarocque @@ -1242,3 +1246,4 @@ Beta release. [E0712]: https://quick-lint-js.com/errors/E0712/ [E0713]: https://quick-lint-js.com/errors/E0713/ [E0714]: https://quick-lint-js.com/errors/E0714/ +[E0715]: https://quick-lint-js.com/errors/E0715/ From 6cfaa0daef24d1ab9d61f02ef4dfb7006187142a Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Wed, 25 Oct 2023 20:01:00 -0400 Subject: [PATCH 005/117] chore: prepare for 2.17.0 release --- Formula/quick-lint-js.rb | 2 +- dist/arch/PKGBUILD-dev | 2 +- dist/arch/PKGBUILD-git | 2 +- dist/arch/PKGBUILD-release | 2 +- dist/chocolatey/quick-lint-js.nuspec | 2 +- dist/chocolatey/tools/VERIFICATION.txt | 4 +- dist/debian/README.md | 4 +- dist/debian/debian/changelog | 6 + dist/debian/debian/changelog-bionic | 6 + dist/msix/AppxManifest.xml | 2 +- dist/npm/BUILDING.md | 8 +- dist/npm/package.json | 2 +- dist/scoop/quick-lint-js.template.json | 2 +- dist/sign-release.go | 36 ++-- ...lint.quick-lint-js.installer.template.yaml | 2 +- ...t.quick-lint-js.locale.en-US.template.yaml | 2 +- .../quick-lint.quick-lint-js.template.yaml | 2 +- docs/CHANGELOG.md | 4 +- docs/man/quick-lint-js-lsp.8 | 4 +- docs/man/quick-lint-js.1 | 163 +++++++++++++++++- docs/man/quick-lint-js.config.5 | 4 +- .../quick-lint-js.vim/doc/quick-lint-js.txt | 2 +- plugin/vscode-lsp/README.md | 2 +- plugin/vscode-lsp/package.json | 2 +- plugin/vscode/BUILDING.md | 2 +- plugin/vscode/package.json | 2 +- version | 4 +- 27 files changed, 220 insertions(+), 55 deletions(-) diff --git a/Formula/quick-lint-js.rb b/Formula/quick-lint-js.rb index cd969a71b3..03c80e0f6b 100644 --- a/Formula/quick-lint-js.rb +++ b/Formula/quick-lint-js.rb @@ -4,7 +4,7 @@ class QuickLintJs < Formula desc "Find bugs in your JavaScript code" homepage "https://quick-lint-js.com/" - url "https://c.quick-lint-js.com/releases/2.16.0/source/quick-lint-js-2.16.0.tar.gz" + url "https://c.quick-lint-js.com/releases/2.17.0/source/quick-lint-js-2.17.0.tar.gz" license "GPL-3.0-or-later" head "https://github.com/quick-lint/quick-lint-js.git", branch: "master" diff --git a/dist/arch/PKGBUILD-dev b/dist/arch/PKGBUILD-dev index 753300ecb5..aba4cb9710 100644 --- a/dist/arch/PKGBUILD-dev +++ b/dist/arch/PKGBUILD-dev @@ -5,7 +5,7 @@ # Contributor: Shivam Mehta pkgname=quick-lint-js-dev -pkgver=2.16.0 +pkgver=2.17.0 pkgrel=1 pkgdesc="Find bugs in JavaScript programs" arch=(aarch64 arm armv6h armv7h i686 pentium4 x86_64) diff --git a/dist/arch/PKGBUILD-git b/dist/arch/PKGBUILD-git index 4fdc9c75ed..296dac13ef 100644 --- a/dist/arch/PKGBUILD-git +++ b/dist/arch/PKGBUILD-git @@ -5,7 +5,7 @@ # Contributor: Shivam Mehta pkgname=quick-lint-js-git -pkgver=2.16.0 +pkgver=2.17.0 pkgrel=1 pkgdesc="Find bugs in JavaScript programs" arch=(aarch64 arm armv6h armv7h i686 pentium4 x86_64) diff --git a/dist/arch/PKGBUILD-release b/dist/arch/PKGBUILD-release index 93ae48eae5..15264260fe 100644 --- a/dist/arch/PKGBUILD-release +++ b/dist/arch/PKGBUILD-release @@ -5,7 +5,7 @@ # Contributor: Shivam Mehta pkgname=quick-lint-js -pkgver=2.16.0 +pkgver=2.17.0 pkgrel=1 pkgdesc="Find bugs in JavaScript programs" arch=(aarch64 arm armv6h armv7h i686 pentium4 x86_64) diff --git a/dist/chocolatey/quick-lint-js.nuspec b/dist/chocolatey/quick-lint-js.nuspec index abf4ee6854..6cfef8b5f3 100644 --- a/dist/chocolatey/quick-lint-js.nuspec +++ b/dist/chocolatey/quick-lint-js.nuspec @@ -3,7 +3,7 @@ quick-lint-js - 2.16.0 + 2.17.0 quick-lint-js (Install) Matthew "strager" Glazar et al Matthew "strager" Glazar diff --git a/dist/chocolatey/tools/VERIFICATION.txt b/dist/chocolatey/tools/VERIFICATION.txt index 0686c6802c..6d60afc94e 100644 --- a/dist/chocolatey/tools/VERIFICATION.txt +++ b/dist/chocolatey/tools/VERIFICATION.txt @@ -5,5 +5,5 @@ in verifying that this package's contents are trustworthy. I, Matthew "strager" Glazar, am the software vendor who packaged this software for Chocolatey. -Upstream SHA256 checksums: https://c.quick-lint-js.com/releases/2.16.0/SHA256SUMS -GPG signature: https://c.quick-lint-js.com/releases/2.16.0/SHA256SUMS.asc +Upstream SHA256 checksums: https://c.quick-lint-js.com/releases/2.17.0/SHA256SUMS +GPG signature: https://c.quick-lint-js.com/releases/2.17.0/SHA256SUMS.asc diff --git a/dist/debian/README.md b/dist/debian/README.md index 49d7b88833..ef41e7dbcb 100644 --- a/dist/debian/README.md +++ b/dist/debian/README.md @@ -48,7 +48,7 @@ To test `asgen-config.json` or metadata changes locally: * Change `MediaBaseUrl` to `"http://localhost:8069/appstream/export/media/"`. * Change `HtmlBaseUrl` to `"http://localhost:8069/appstream/export/html/"`. 5. Create a directory `debian/pool/`. -6. Copy `dist/debian/*2.16.0*` (built by the [Building](#Building) instructions +6. Copy `dist/debian/*2.17.0*` (built by the [Building](#Building) instructions above) into the `debian/pool/` directory. 7. Run `./dist/debian/update-repository path/to/debian`. 8. Start an HTTP server in the `debian` directory. For example: @@ -73,7 +73,7 @@ To release to downstream Debian, we [ship a source package to Debian mentors][]. 1. Download a signed release .tar.gz and .tar.gz.asc (e.g. from ). 2. Create a package using `package.sh`: - `./dist/debian/package.sh --output-directory debian-package --orig path/to/quick-lint-js-2.16.0.tar.gz --sign` + `./dist/debian/package.sh --output-directory debian-package --orig path/to/quick-lint-js-2.17.0.tar.gz --sign` * NOTE: `package.sh` will use the `debian` sources from your checkout (`./dist/debian/debian/`), not from the signed release tarball. 3. Upload the package: `dput mentors debian-package/quick-lint-js_2.4.2-1_source.changes` diff --git a/dist/debian/debian/changelog b/dist/debian/debian/changelog index e6dfdf6465..2229591df1 100644 --- a/dist/debian/debian/changelog +++ b/dist/debian/debian/changelog @@ -1,3 +1,9 @@ +quick-lint-js (2.17.0-1) unstable; urgency=medium + + * New release. + + -- Matthew "strager" Glazar Wed, 25 Oct 2023 19:42:44 -0400 + quick-lint-js (2.16.0-1) unstable; urgency=medium * New release. diff --git a/dist/debian/debian/changelog-bionic b/dist/debian/debian/changelog-bionic index a4b8bf16f9..dc2cac96e9 100644 --- a/dist/debian/debian/changelog-bionic +++ b/dist/debian/debian/changelog-bionic @@ -1,3 +1,9 @@ +quick-lint-js (2.17.0-1) unstable; urgency=medium + + * New release. + + -- Matthew "strager" Glazar Wed, 25 Oct 2023 19:42:44 -0400 + quick-lint-js (2.16.0-1) unstable; urgency=medium * New release. diff --git a/dist/msix/AppxManifest.xml b/dist/msix/AppxManifest.xml index d0f0231ff6..43673dc2fe 100644 --- a/dist/msix/AppxManifest.xml +++ b/dist/msix/AppxManifest.xml @@ -10,7 +10,7 @@ + Version="2.17.0.0" /> quick-lint-js diff --git a/dist/npm/BUILDING.md b/dist/npm/BUILDING.md index d114e934ca..969fa8437f 100644 --- a/dist/npm/BUILDING.md +++ b/dist/npm/BUILDING.md @@ -8,12 +8,12 @@ To build this quick-lint-js npm package: * `dist/npm/linux-x64/bin/quick-lint-js`: Linux x86_64 executable * `dist/npm/darwin-x64/bin/quick-lint-js`: macOS 64-bit Intel executable * `dist/npm/win32-x64/bin/quick-lint-js.exe`: Windows x64 executable -3. Run `npm pack .` to create `quick-lint-js-2.16.0.tgz`. +3. Run `npm pack .` to create `quick-lint-js-2.17.0.tgz`. To install system-wide, run -`npm install --global --unsafe-perm ./quick-lint-js-2.16.0.tgz`. +`npm install --global --unsafe-perm ./quick-lint-js-2.17.0.tgz`. To install within an existing Node.js project, run -`npm install /path/to/quick-lint-js-2.16.0.tgz`. +`npm install /path/to/quick-lint-js-2.17.0.tgz`. -To publish to npm's registry, run `npm publish ./quick-lint-js-2.16.0.tgz`. +To publish to npm's registry, run `npm publish ./quick-lint-js-2.17.0.tgz`. diff --git a/dist/npm/package.json b/dist/npm/package.json index 63fd772040..3f3beaabac 100644 --- a/dist/npm/package.json +++ b/dist/npm/package.json @@ -1,7 +1,7 @@ { "name": "quick-lint-js", "description": "Find bugs in your JavaScript code", - "version": "2.16.0", + "version": "2.17.0", "keywords": [ "quick", "lint", diff --git a/dist/scoop/quick-lint-js.template.json b/dist/scoop/quick-lint-js.template.json index 7d2b241748..9754210702 100644 --- a/dist/scoop/quick-lint-js.template.json +++ b/dist/scoop/quick-lint-js.template.json @@ -1,5 +1,5 @@ { - "version": "2.16.0", + "version": "2.17.0", "description": "Find bugs in JavaScript programs.", "homepage": "https://quick-lint-js.com/", "license": "GPL-3.0-or-later,MIT,BSL-1.0,Apache-2.0,ZPL-2.1,Public Domain,Unknown,ISC,BSD-2-Clause,MIT-CMU,LGPL-2.1-or-later,GPL-2.0-or-later,BSD-3-Clause", diff --git a/dist/sign-release.go b/dist/sign-release.go index e23d962408..974429390a 100644 --- a/dist/sign-release.go +++ b/dist/sign-release.go @@ -115,7 +115,7 @@ func main() { log.Fatal(err) } - sourceTarballPath := filepath.Join(destinationDir, "source/quick-lint-js-2.16.0.tar.gz") + sourceTarballPath := filepath.Join(destinationDir, "source/quick-lint-js-2.17.0.tar.gz") log.Printf("signing: %s\n", sourceTarballPath) if err := RelicFile(sourceTarballPath, sourceTarballPath+".asc", RelicSignPGP); err != nil { log.Fatal(err) @@ -160,23 +160,23 @@ var filesToTransform map[DeepPath]FileTransformType = map[DeepPath]FileTransform NewDeepPath2("manual/windows-arm.zip", "bin/quick-lint-js.exe"): RelicWindows, NewDeepPath2("manual/windows-x86.zip", "bin/quick-lint-js.exe"): RelicWindows, NewDeepPath2("manual/windows.zip", "bin/quick-lint-js.exe"): RelicWindows, - NewDeepPath2("npm/quick-lint-js-2.16.0.tgz", "package/darwin-arm64/bin/quick-lint-js"): RelicApple, - NewDeepPath2("npm/quick-lint-js-2.16.0.tgz", "package/darwin-x64/bin/quick-lint-js"): RelicApple, - NewDeepPath2("npm/quick-lint-js-2.16.0.tgz", "package/linux-arm/bin/quick-lint-js"): RelicPGP, - NewDeepPath2("npm/quick-lint-js-2.16.0.tgz", "package/linux-arm64/bin/quick-lint-js"): RelicPGP, - NewDeepPath2("npm/quick-lint-js-2.16.0.tgz", "package/linux-x64/bin/quick-lint-js"): RelicPGP, - NewDeepPath2("npm/quick-lint-js-2.16.0.tgz", "package/win32-arm64/bin/quick-lint-js.exe"): RelicWindows, - NewDeepPath2("npm/quick-lint-js-2.16.0.tgz", "package/win32-ia32/bin/quick-lint-js.exe"): RelicWindows, - NewDeepPath2("npm/quick-lint-js-2.16.0.tgz", "package/win32-x64/bin/quick-lint-js.exe"): RelicWindows, - NewDeepPath2("vscode/quick-lint-js-2.16.0.vsix", "extension/dist/quick-lint-js-vscode-node_darwin-arm64.node"): RelicApple, - NewDeepPath2("vscode/quick-lint-js-2.16.0.vsix", "extension/dist/quick-lint-js-vscode-node_darwin-x64.node"): RelicApple, - NewDeepPath2("vscode/quick-lint-js-2.16.0.vsix", "extension/dist/quick-lint-js-vscode-node_linux-arm.node"): RelicPGP, - NewDeepPath2("vscode/quick-lint-js-2.16.0.vsix", "extension/dist/quick-lint-js-vscode-node_linux-arm64.node"): RelicPGP, - NewDeepPath2("vscode/quick-lint-js-2.16.0.vsix", "extension/dist/quick-lint-js-vscode-node_linux-x64.node"): RelicPGP, - NewDeepPath2("vscode/quick-lint-js-2.16.0.vsix", "extension/dist/quick-lint-js-vscode-node_win32-arm.node"): RelicWindows, - NewDeepPath2("vscode/quick-lint-js-2.16.0.vsix", "extension/dist/quick-lint-js-vscode-node_win32-arm64.node"): RelicWindows, - NewDeepPath2("vscode/quick-lint-js-2.16.0.vsix", "extension/dist/quick-lint-js-vscode-node_win32-ia32.node"): RelicWindows, - NewDeepPath2("vscode/quick-lint-js-2.16.0.vsix", "extension/dist/quick-lint-js-vscode-node_win32-x64.node"): RelicWindows, + NewDeepPath2("npm/quick-lint-js-2.17.0.tgz", "package/darwin-arm64/bin/quick-lint-js"): RelicApple, + NewDeepPath2("npm/quick-lint-js-2.17.0.tgz", "package/darwin-x64/bin/quick-lint-js"): RelicApple, + NewDeepPath2("npm/quick-lint-js-2.17.0.tgz", "package/linux-arm/bin/quick-lint-js"): RelicPGP, + NewDeepPath2("npm/quick-lint-js-2.17.0.tgz", "package/linux-arm64/bin/quick-lint-js"): RelicPGP, + NewDeepPath2("npm/quick-lint-js-2.17.0.tgz", "package/linux-x64/bin/quick-lint-js"): RelicPGP, + NewDeepPath2("npm/quick-lint-js-2.17.0.tgz", "package/win32-arm64/bin/quick-lint-js.exe"): RelicWindows, + NewDeepPath2("npm/quick-lint-js-2.17.0.tgz", "package/win32-ia32/bin/quick-lint-js.exe"): RelicWindows, + NewDeepPath2("npm/quick-lint-js-2.17.0.tgz", "package/win32-x64/bin/quick-lint-js.exe"): RelicWindows, + NewDeepPath2("vscode/quick-lint-js-2.17.0.vsix", "extension/dist/quick-lint-js-vscode-node_darwin-arm64.node"): RelicApple, + NewDeepPath2("vscode/quick-lint-js-2.17.0.vsix", "extension/dist/quick-lint-js-vscode-node_darwin-x64.node"): RelicApple, + NewDeepPath2("vscode/quick-lint-js-2.17.0.vsix", "extension/dist/quick-lint-js-vscode-node_linux-arm.node"): RelicPGP, + NewDeepPath2("vscode/quick-lint-js-2.17.0.vsix", "extension/dist/quick-lint-js-vscode-node_linux-arm64.node"): RelicPGP, + NewDeepPath2("vscode/quick-lint-js-2.17.0.vsix", "extension/dist/quick-lint-js-vscode-node_linux-x64.node"): RelicPGP, + NewDeepPath2("vscode/quick-lint-js-2.17.0.vsix", "extension/dist/quick-lint-js-vscode-node_win32-arm.node"): RelicWindows, + NewDeepPath2("vscode/quick-lint-js-2.17.0.vsix", "extension/dist/quick-lint-js-vscode-node_win32-arm64.node"): RelicWindows, + NewDeepPath2("vscode/quick-lint-js-2.17.0.vsix", "extension/dist/quick-lint-js-vscode-node_win32-ia32.node"): RelicWindows, + NewDeepPath2("vscode/quick-lint-js-2.17.0.vsix", "extension/dist/quick-lint-js-vscode-node_win32-x64.node"): RelicWindows, NewDeepPath("windows/quick-lint-js.msix"): RelicWindows, NewDeepPath2("windows/quick-lint-js.msix", "quick-lint-js.exe"): RelicWindows, } diff --git a/dist/winget/quick-lint.quick-lint-js.installer.template.yaml b/dist/winget/quick-lint.quick-lint-js.installer.template.yaml index 12d9bd3acb..c16faaed9e 100644 --- a/dist/winget/quick-lint.quick-lint-js.installer.template.yaml +++ b/dist/winget/quick-lint.quick-lint-js.installer.template.yaml @@ -5,7 +5,7 @@ # http://creativecommons.org/publicdomain/zero/1.0/ PackageIdentifier: quick-lint.quick-lint-js -PackageVersion: 2.16.0.0 +PackageVersion: 2.17.0.0 Installers: - InstallerUrl: {{ .BaseURI }}windows/quick-lint-js.msix diff --git a/dist/winget/quick-lint.quick-lint-js.locale.en-US.template.yaml b/dist/winget/quick-lint.quick-lint-js.locale.en-US.template.yaml index 6e4b06beb7..8dfdf082c9 100644 --- a/dist/winget/quick-lint.quick-lint-js.locale.en-US.template.yaml +++ b/dist/winget/quick-lint.quick-lint-js.locale.en-US.template.yaml @@ -5,7 +5,7 @@ # http://creativecommons.org/publicdomain/zero/1.0/ PackageIdentifier: quick-lint.quick-lint-js -PackageVersion: 2.16.0.0 +PackageVersion: 2.17.0.0 PackageLocale: en-US PackageName: quick-lint-js diff --git a/dist/winget/quick-lint.quick-lint-js.template.yaml b/dist/winget/quick-lint.quick-lint-js.template.yaml index ce93a6a09f..472b539456 100644 --- a/dist/winget/quick-lint.quick-lint-js.template.yaml +++ b/dist/winget/quick-lint.quick-lint-js.template.yaml @@ -5,7 +5,7 @@ # http://creativecommons.org/publicdomain/zero/1.0/ PackageIdentifier: quick-lint.quick-lint-js -PackageVersion: 2.16.0.0 +PackageVersion: 2.17.0.0 DefaultLocale: en-US ManifestType: version diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 0df95f2f24..65509b49fd 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -6,7 +6,9 @@ based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). quick-lint-js' version numbers are arbitrary. quick-lint-js does *not* adhere to Semantic Versioning. -## Unreleased +## 2.17.0 (2023-10-25) + +[Downloads](https://c.quick-lint-js.com/releases/2.17.0/) ### Added diff --git a/docs/man/quick-lint-js-lsp.8 b/docs/man/quick-lint-js-lsp.8 index d6cb31e288..67254da484 100644 --- a/docs/man/quick-lint-js-lsp.8 +++ b/docs/man/quick-lint-js-lsp.8 @@ -12,10 +12,10 @@ .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.17 .\" Manual: \ \& -.\" Source: quick-lint-js version  2.16.0 +.\" Source: quick-lint-js version  2.17.0 .\" Language: English .\" -.TH "QUICK\-LINT\-JS\-LSP" "8" "" "quick\-lint\-js version  2.16.0" "\ \&" +.TH "QUICK\-LINT\-JS\-LSP" "8" "" "quick\-lint\-js version  2.17.0" "\ \&" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/docs/man/quick-lint-js.1 b/docs/man/quick-lint-js.1 index 4b3e8de9b1..e67fae9840 100644 --- a/docs/man/quick-lint-js.1 +++ b/docs/man/quick-lint-js.1 @@ -12,10 +12,10 @@ .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.17 .\" Manual: \ \& -.\" Source: quick-lint-js version  2.16.0 +.\" Source: quick-lint-js version  2.17.0 .\" Language: English .\" -.TH "QUICK\-LINT\-JS" "1" "" "quick\-lint\-js version  2.16.0" "\ \&" +.TH "QUICK\-LINT\-JS" "1" "" "quick\-lint\-js version  2.17.0" "\ \&" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 @@ -181,11 +181,56 @@ searching for a configuration file (see \fBquick\-lint\-js.config\fP(5)). Therefore, if multiple input files are given, \fB\-\-path\-for\-config\-search\fP can be specified multiple times. If \fB\-\-path\-for\-config\-search\fP is the last option, it has no effect. .sp +\fB\-\-path\-for\-config\-search\fP overrides \fB\-\-stdin\-path\fP. +.sp Incompatible with \fB\-\-lsp\-server\fP. .sp Added in quick\-lint\-js version 0.4.0. .RE .sp +\fB\-\-stdin\-path\fP=\fIpath\fP +.RS 4 + Change the behavior of \fB\-\-stdin\fP. +\fB\-\-stdin\fP still reads a string from standard input, but otherwise it behaves as if the file at \fIpath\fP was specified instead: +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +. sp -1 +. IP \(bu 2.3 +.\} +The default language is determined by \fIpath\fP (unless overridden by \fB\-\-language\fP). +See \fB\-\-language\fP for details. +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +. sp -1 +. IP \(bu 2.3 +.\} +Searching for a configuration file +is based on \fIpath\fP (unless overridden by \fB\-\-config\-file\fP or \fB\-\-path\-for\-config\-file\fP). +(See \fBquick\-lint\-js.config\fP(5) for details on configuration file searching.) +.RE +.sp +\fB\-\-stdin\-path\fP applies to only \fB\-\-stdin\fP, not file paths (even special files such as /dev/stdin). +.sp +\fB\-\-stdin\-path\fP may appear anywhere in the command line (except after \fB\-\-\fP). +.sp +\fIpath\fP must be a syntactically\-valid path. +\fIpath\fP does not need to exist in the filesystem. +\fIpath\fP may be a relative path or an absolute path. +.sp +Incompatible with \fB\-\-lsp\-server\fP. +.sp +Added in quick\-lint\-js version 2.17.0. +.RE +.sp \fB\-\-config\-file\fP=\fIfile\fP .RS 4 Read configuration options from \fIfile\fP and apply them to input files which are given later in the command line. @@ -196,6 +241,8 @@ See the EXAMPLE section for an example. .sp If \fB\-\-config\-file\fP is not given, \fBquick\-lint\-js\fP searches for a configuration file according to the rules specified in \fBquick\-lint\-js.config\fP(5). .sp +\fB\-\-config\-file\fP overrides \fB\-\-path\-for\-config\-file\fP and \fB\-\-stdin\-path\fP. +.sp Incompatible with \fB\-\-lsp\-server\fP. .sp Added in quick\-lint\-js version 0.3.0. @@ -257,6 +304,83 @@ Interpret input files which are given later in the command line as if they were . sp -1 . IP \(bu 2.3 .\} +\fBexperimental\-default\fP: infer the \fIlanguageid\fP from the file\(cqs extension (EXPERIMENTAL; subject to change in future versions of quick\-lint\-js): +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +. sp -1 +. IP \(bu 2.3 +.\} +\fB.js\fP: \fBjavascript\-jsx\fP +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +. sp -1 +. IP \(bu 2.3 +.\} +\fB.jsx\fP: \fBjavascript\-jsx\fP +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +. sp -1 +. IP \(bu 2.3 +.\} +\fB.d.ts\fP: \fBexperimental\-typescript\-definition\fP +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +. sp -1 +. IP \(bu 2.3 +.\} +\fB.ts\fP: \fBexperimental\-typescript\fP +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +. sp -1 +. IP \(bu 2.3 +.\} +\fB.tsx\fP: \fBexperimental\-typescript\-jsx\fP +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +. sp -1 +. IP \(bu 2.3 +.\} +(anything else): \fBjavascript\-jsx\fP +.RE +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +. sp -1 +. IP \(bu 2.3 +.\} \fBjavascript\fP: the latest ECMAScript standard with proposed features. .RE .sp @@ -315,6 +439,31 @@ See the EXAMPLE section for an example. .sp If \fB\-\-language\fP is the last option, it has no effect. .sp +If the input file is \fB\-\-stdin\fP: +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +. sp -1 +. IP \(bu 2.3 +.\} +If \fB\-\-stdin\-path\fP is specified, its \fIpath\fP is used for \fB\-\-language=default\fP. +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +. sp -1 +. IP \(bu 2.3 +.\} +If \fB\-\-stdin\-path\fP is not specified, then the path is assumed to be \fBexample.js\fP. +This means that \fB\-\-language=default\fP will behave like \fB\-\-language=javascript\-jsx\fP. +.RE +.sp Incompatible with \fB\-\-lsp\-server\fP. .sp Added in quick\-lint\-js version 2.10.0. @@ -331,13 +480,15 @@ Incompatible with \fB\-\-lsp\-server\fP. .sp \fB\-\-stdin\fP .RS 4 -Read standard input as a JavaScript file. +Read standard input as an input file. .sp -If neither \fB\-\-config\-file\fP nor \fB\-\-path\-for\-config\-search\fP is specified, an empty configuration file is assumed. +If none of \fB\-\-config\-file\fP, \fB\-\-path\-for\-config\-search\fP, or \fB\-\-stdin\-path\fP are specified, an empty configuration file is assumed. If \fB\-\-config\-file\fP is specified, \fIfile\fP is used for linting standard input. -If \fB\-\-path\-for\-config\-search\fP is specified and \fB\-\-config\-file\fP is not specified, +If \fB\-\-config\-file\fP is not specified and either \fB\-\-stdin\-path\fP or \fB\-\-path\-for\-config\-search\fP is specified, \fBquick\-lint\-js\fP searches for a configuration file according to the rules specified in \fBquick\-lint\-js.config\fP(5) -starting from \fB\-\-path\-for\-config\-search\fP\*(Aqs \fIpath\fP. +starting from \fB\-\-stdin\-path\fP\*(Aqs \fIpath\fP or \fB\-\-path\-for\-config\-search\fP\*(Aqs \fIpath\fP. +.sp +If neither \fB\-\-stdin\-path\fP nor \fB\-\-language\fP are specified, the \fBjavascript\-jsx\fP language is used. .sp Incompatible with \fB\-\-lsp\-server\fP. .sp diff --git a/docs/man/quick-lint-js.config.5 b/docs/man/quick-lint-js.config.5 index d49db3f630..f747923563 100644 --- a/docs/man/quick-lint-js.config.5 +++ b/docs/man/quick-lint-js.config.5 @@ -12,10 +12,10 @@ .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.17 .\" Manual: \ \& -.\" Source: quick-lint-js version  2.16.0 +.\" Source: quick-lint-js version  2.17.0 .\" Language: English .\" -.TH "QUICK\-LINT\-JS.CONFIG" "5" "" "quick\-lint\-js version  2.16.0" "\ \&" +.TH "QUICK\-LINT\-JS.CONFIG" "5" "" "quick\-lint\-js version  2.17.0" "\ \&" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/plugin/vim/quick-lint-js.vim/doc/quick-lint-js.txt b/plugin/vim/quick-lint-js.vim/doc/quick-lint-js.txt index 0681d319a3..b8b8d5dccd 100644 --- a/plugin/vim/quick-lint-js.vim/doc/quick-lint-js.txt +++ b/plugin/vim/quick-lint-js.vim/doc/quick-lint-js.txt @@ -7,7 +7,7 @@ This file contains instructions for installing and using the quick-lint-js plugin. -This plugin version is designed for quick-lint-js version 2.16.0. Older or +This plugin version is designed for quick-lint-js version 2.17.0. Older or newer versions might or might not work. 1. Installing quick-lint-js |quick-lint-js-app-install| diff --git a/plugin/vscode-lsp/README.md b/plugin/vscode-lsp/README.md index a1c31e92ae..4aa8f7e72a 100644 --- a/plugin/vscode-lsp/README.md +++ b/plugin/vscode-lsp/README.md @@ -10,6 +10,6 @@ To build the extension, run the following commands: $ yarn $ ./node_modules/.bin/vsce package -This will create a file called `quick-lint-js-lsp-2.16.0.vsix`. +This will create a file called `quick-lint-js-lsp-2.17.0.vsix`. [VisualStudioCode]: https://code.visualstudio.com/ diff --git a/plugin/vscode-lsp/package.json b/plugin/vscode-lsp/package.json index c32548073f..85a18f878c 100644 --- a/plugin/vscode-lsp/package.json +++ b/plugin/vscode-lsp/package.json @@ -2,7 +2,7 @@ "name": "quick-lint-js-lsp", "description": "Find JavaScript bugs with quick-lint-js (LSP version, not recommended)", "publisher": "quick-lint", - "version": "2.16.0", + "version": "2.17.0", "engines": { "vscode": "^1.43.0" }, diff --git a/plugin/vscode/BUILDING.md b/plugin/vscode/BUILDING.md index 0f718058b9..b2bf5b1a74 100644 --- a/plugin/vscode/BUILDING.md +++ b/plugin/vscode/BUILDING.md @@ -15,7 +15,7 @@ CMake][build-quick-lint-js] with `-DQUICK_LINT_JS_ENABLE_VSCODE=YES $ # Copy files into the VS Code extension: $ cmake --install build --component vscode-node --prefix plugin/vscode -Finally, run the following commands to create `quick-lint-js-2.16.0.vsix`: +Finally, run the following commands to create `quick-lint-js-2.17.0.vsix`: $ cd plugin/vscode/ # Navigate to this directory. $ yarn diff --git a/plugin/vscode/package.json b/plugin/vscode/package.json index 7215322cbb..1a96e84406 100644 --- a/plugin/vscode/package.json +++ b/plugin/vscode/package.json @@ -2,7 +2,7 @@ "name": "quick-lint-js", "description": "Find JavaScript bugs with quick-lint-js", "publisher": "quick-lint", - "version": "2.16.0", + "version": "2.17.0", "license": "SEE LICENSE IN LICENSE", "categories": [ "Linters" diff --git a/version b/version index 64b1d8a38d..140ee6da8c 100644 --- a/version +++ b/version @@ -1,2 +1,2 @@ -2.16.0 -2023-09-06 +2.17.0 +2023-10-25 From 3bfc72d57720171fb21e2567bc44734a24748f5f Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Wed, 25 Oct 2023 21:44:32 -0400 Subject: [PATCH 006/117] fix(dist): update SSL.com root certificate Our copy of the SSL.com certificate, used to verify signed timestamps, is expired. Import the latest certificate from from SSL https://www.ssl.com/how-to/install-ssl-com-ca-root-certificates/#downloads. --- ...L_COM_ROOT_CERTIFICATION_AUTHORITY_RSA.crt | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/dist/certificates/SSL_COM_ROOT_CERTIFICATION_AUTHORITY_RSA.crt b/dist/certificates/SSL_COM_ROOT_CERTIFICATION_AUTHORITY_RSA.crt index 8ccbcef9ed..77ec988e1d 100644 --- a/dist/certificates/SSL_COM_ROOT_CERTIFICATION_AUTHORITY_RSA.crt +++ b/dist/certificates/SSL_COM_ROOT_CERTIFICATION_AUTHORITY_RSA.crt @@ -1,34 +1,34 @@ -----BEGIN CERTIFICATE----- -MIIF2DCCBMCgAwIBAgIRAOQnBJX2jJHW0Ox7SU6k3xwwDQYJKoZIhvcNAQELBQAw -fjELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu -QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEiMCAG -A1UEAxMZQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQTAeFw0xODA5MTEwOTI2NDda -Fw0yMzA5MTEwOTI2NDdaMHwxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQ -MA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTEwLwYD -VQQDDChTU0wuY29tIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBMIIC -IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA+Q/doyt9y9Aq/uxnhabnLhu6 -d+Hj9a+k7PpKXZHEV0drGHdrdvL9k+Q9D8IWngtmw1aUnheDhc5W7/IW/QBi9SIJ -VOhlF05BueBPRpeqG8i4bmJeabFf2yoCfvxsyvNB2O3Q6Pw/YUjtsAMUHRAOSxng -u07shmX/NvNeZwILnYZVYf16OO3+4hkAt2+hUGJ1dDyg+sglkrRueiLH+B6h47Ld -kTGrKx0E/6VKBDfphaQzK/3i1lU0fBmkSmjHsqjTt8qhk4jrwZe8jPkd2SKEJHTH -BD1qqSmTzOu4W+H+XyWqNFjIwSNUnRuYEcM4nH49hmylD0CGfAL0XAJPKMuucZ8P -Osgz/hElNer8usVgPdl8GNWyqdN1eANyIso6wx/vLOUuqfqeLLZRRv2vA9bqYGjq -hRY2a4XpHsCz3cQk3IAqgUFtlD7I4MmBQQCeXr9/xQiYohgsQkCz+W84J0tOgPQ9 -gUfgiHzqHM61dVxRLhwrfxpyKOcAtdF0xtfkn60Hk7ZTNTX8N+TD9l0WviFz3pIK -+KBjaryWkmo++LxlVZve9Q2JJgT8JRqmJWnLwm3KfOJZX5es6+8uyLzXG1k8K8zy -GciTaydjGc/86Sb4ynGbf5P+NGeETpnr/LN4CTNwumamdu0bc+sapQ3EIhMglFYK -TixsTrH9z5wJuqIz7YcCAwEAAaOCAVEwggFNMBIGA1UdEwEB/wQIMAYBAf8CAQIw -HQYDVR0OBBYEFN0ECQei9Xp9UlMSkpXuOIAlDaZZMB8GA1UdIwQYMBaAFAh2zcsH -/yT2xc3tu5C84oQ3RnX3MA4GA1UdDwEB/wQEAwIBBjA2BgNVHR8ELzAtMCugKaAn -hiVodHRwOi8vc3NsY29tLmNybC5jZXJ0dW0ucGwvY3RuY2EuY3JsMHMGCCsGAQUF -BwEBBGcwZTApBggrBgEFBQcwAYYdaHR0cDovL3NzbGNvbS5vY3NwLWNlcnR1bS5j -b20wOAYIKwYBBQUHMAKGLGh0dHA6Ly9zc2xjb20ucmVwb3NpdG9yeS5jZXJ0dW0u -cGwvY3RuY2EuY2VyMDoGA1UdIAQzMDEwLwYEVR0gADAnMCUGCCsGAQUFBwIBFhlo -dHRwczovL3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEBCwUAA4IBAQAflZoj -VO6FwvPUb7npBI9Gfyz3MsCnQ6wHAO3gqUUt/Rfh7QBAyK+YrPXAGa0boJcwQGzs -W/ujk06MiWIbfPA6X6dCz1jKdWWcIky/dnuYk5wVgzOxDtxROId8lZwSaZQeAHh0 -ftzABne6cC2HLNdoneO6ha1J849ktBUGg5LGl6RAk4ut8WeUtLlaZ1Q8qBvZBc/k -pPmIEgAGiCWF1F7u85NX1oH4LK739VFIq7ZiOnnb7C7yPxRWOsjZy6SiTyWo0Zur -LTAgUAcab/HxlB05g2PoH/1J0OgdRrJGgia9nJ3homhBSFFuevw1lvRU0rwrROVH -13eCpUqrX5czqyQR +MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE +BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK +DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz +OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv +bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R +xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX +qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC +C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3 +6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh +/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF +YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E +JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc +US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8 +ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm ++Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi +M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G +A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV +cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc +Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs +PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/ +q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0 +cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr +a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I +H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y +K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu +nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf +oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY +Ic2wBlX7Jz9TkHCpBB5XJ7k= -----END CERTIFICATE----- From ea5fca9fb186838b49481fe7f5156f6effc3aebf Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Wed, 25 Oct 2023 22:03:00 -0400 Subject: [PATCH 007/117] fix(dist): don't accidentally include old files in release When releasing quick-lint-js version 2.17.0, I accidentally included some files from the 2.16.0 release. This is because I had stale builds and signed-builds folders from when I released 2.16.0. Update the release script to complain if an old builds or signed-builds folder is found. --- dist/release.go | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/dist/release.go b/dist/release.go index 81227eb83d..44edeb6449 100644 --- a/dist/release.go +++ b/dist/release.go @@ -165,6 +165,13 @@ var Steps []Step = []Step{ }, }, + Step{ + Title: "Check builds folder", + Run: func() { + EnsureEmptyDirectory("builds") + }, + }, + Step{ Title: "Download builds", Run: func() { @@ -177,6 +184,13 @@ var Steps []Step = []Step{ }, }, + Step{ + Title: "Check signed-builds folder", + Run: func() { + EnsureEmptyDirectory("signed-builds") + }, + }, + Step{ Title: "Sign the build artifacts", Run: func() { @@ -684,6 +698,28 @@ func UpdateDebianChangelog(changelogFilePath string, versionInfo VersionFileInfo return nil } +func EnsureEmptyDirectory(path string) { +Retry: + err := os.Mkdir(path, 0700) + if err == nil { + // A newly-created directory is empty. + return + } + if !os.IsExist(err) { + // Unknown error. Report it to the user. + Stopf("%v", err) + } + entries, readError := os.ReadDir(path) + directoryIsEmpty := readError == nil && len(entries) == 0 + if directoryIsEmpty { + return + } + + fmt.Printf("Error: A '%s' folder already exists. Delete it then type 'done'.\n", path) + WaitForDone() + goto Retry +} + func StringLines(s string) []string { return strings.Split(s, "\n") } From 29f461a80941071bfdde616aff8ad442a9aef1f8 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Wed, 25 Oct 2023 22:43:53 -0400 Subject: [PATCH 008/117] fix(website): fix broken links; Rome -> Biome The Rome project has [effectively] been renamed to Biome. Change the project name on our home page and update the broken links. --- website/public/index.ejs.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/website/public/index.ejs.html b/website/public/index.ejs.html index 18737a26c8..cd8550c6c7 100755 --- a/website/public/index.ejs.html +++ b/website/public/index.ejs.html @@ -542,7 +542,7 @@

Features

JSHint - Rome + Biome Deno @@ -566,8 +566,8 @@

Features

>
slow - 🚀
quick + 🚀
quick 🐢Features some - somesome
lint rules
@@ -708,7 +708,7 @@

Features

quick-lint-js ESLint JSHint - Rome + Biome Deno From 3923f0df76d24b73d57f15eec61ab190ea048093 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Thu, 26 Oct 2023 18:08:30 -0400 Subject: [PATCH 009/117] fix(build): fix installing build tools for cross-compilation 'cmake --install . --component build-tools' copies no files [1]. This was caused by commit 1f2e1a47 where the code calling install() became dead code on accident. Call install() so that 'cmake --install' copies the build artifacts as intended. [1] https://github.com/quick-lint/quick-lint-js/issues/1099 Refs: 1f2e1a4701793cac24eaac44d7af81a8b820b1bc --- docs/CHANGELOG.md | 7 +++++++ tools/CMakeLists.txt | 1 - 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 65509b49fd..1d261588e8 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -6,6 +6,13 @@ based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). quick-lint-js' version numbers are arbitrary. quick-lint-js does *not* adhere to Semantic Versioning. +## Unreleased + +### Fixed + +* `cmake --install` with `--component build-tools` now installs the build + tools. (This is a regression introduced in quick-lint-js version 2.16.0.) + ## 2.17.0 (2023-10-25) [Downloads](https://c.quick-lint-js.com/releases/2.17.0/) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 71ccbdf1b8..b541afb528 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -68,7 +68,6 @@ if (QUICK_LINT_JS_ENABLE_BUILD_TOOLS) COMMENT "Building all quick-lint-js build-time tools" DEPENDS ${QUICK_LINT_JS_BUILD_TOOL_TARGETS} ) -elseif (QUICK_LINT_JS_ENABLE_BUILD_TOOLS) install( TARGETS ${QUICK_LINT_JS_BUILD_TOOL_TARGETS} COMPONENT build-tools From 5804e3ca19f75ef6f31336f9a734a848a6a9a775 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Thu, 26 Oct 2023 18:10:52 -0400 Subject: [PATCH 010/117] feat(docs): document known build-tools install issue for older versions https://github.com/quick-lint/quick-lint-js/issues/1099 --- docs/CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 1d261588e8..321a8f3ef8 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -17,6 +17,13 @@ Semantic Versioning. [Downloads](https://c.quick-lint-js.com/releases/2.17.0/) +### Known issues + +* `cmake --install` with `--component build-tools` does not install the build + tools. (This is a regression introduced in quick-lint-js version 2.16.0.) + Patch: [Git commit + 3923f0df76d24b73d57f15eec61ab190ea048093][cmake-install-component-build-tools-patch] + ### Added * quick-lint-js now understands decorators. @@ -89,6 +96,12 @@ Semantic Versioning. [Downloads](https://c.quick-lint-js.com/releases/2.16.0/) +### Known issues + +* `cmake --install` with `--component build-tools` does not install the build + tools. Patch: [Git commit + 3923f0df76d24b73d57f15eec61ab190ea048093][cmake-install-component-build-tools-patch] + ### Added * `2 ^ 8` now reports [E0710][] ("'^' is the XOR operator; to exponentiate, use @@ -1079,6 +1092,7 @@ Beta release. [Bun]: https://bun.sh/ [Deno]: https://deno.land/ [cli-language]: ../cli/#language +[cmake-install-component-build-tools-patch]: https://github.com/quick-lint/quick-lint-js/commit/3923f0df76d24b73d57f15eec61ab190ea048093.patch [coc.nvim]: https://github.com/neoclide/coc.nvim [config-global-groups]: https://quick-lint-js.com/config/#global-groups [cross-compiling-quick-lint-js]: https://quick-lint-js.com/contribute/build-from-source/cross-compiling/ From c2e6ed69db23996a3a6456077fc7ab143fb3a005 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Thu, 26 Oct 2023 16:38:04 -0700 Subject: [PATCH 011/117] feat(benchmark-lsp): switch from Rome to Biome The Rome project is dead. Its successor is Biome. Benchmark Biome's LSP server instead of Rome's. --- benchmark/benchmark-lsp/README.md | 2 +- benchmark/benchmark-lsp/benchmark-config.cpp | 10 ++--- .../benchmark-lsp/{rome => biome}/.gitignore | 0 .../{rome => biome}/package.json | 2 +- .../benchmark-lsp/{rome => biome}/run.sh | 4 +- benchmark/benchmark-lsp/biome/yarn.lock | 45 +++++++++++++++++++ benchmark/benchmark-lsp/rome/yarn.lock | 45 ------------------- 7 files changed, 54 insertions(+), 54 deletions(-) rename benchmark/benchmark-lsp/{rome => biome}/.gitignore (100%) rename benchmark/benchmark-lsp/{rome => biome}/package.json (51%) rename benchmark/benchmark-lsp/{rome => biome}/run.sh (91%) create mode 100644 benchmark/benchmark-lsp/biome/yarn.lock delete mode 100644 benchmark/benchmark-lsp/rome/yarn.lock diff --git a/benchmark/benchmark-lsp/README.md b/benchmark/benchmark-lsp/README.md index 39443d3593..fc1fabd990 100644 --- a/benchmark/benchmark-lsp/README.md +++ b/benchmark/benchmark-lsp/README.md @@ -6,6 +6,7 @@ This directory contains a tool which measures the speed of LSP servers. Install the LSP servers you want to benchmark: +* **Biome**: Run `yarn` in the `biome/` directory. * **Deno**: Install [Deno][]. Ensure the `deno` command is in `$PATH`. * **ESLint**: Run `yarn` in the `eslint/` directory. Then, run `npm ci && npm run compile:server` in the `eslint/node_modules/vscode-eslint/` @@ -13,7 +14,6 @@ Install the LSP servers you want to benchmark: * **Flow**: Run `yarn` in the `flow/` directory. * **RSLint**: Install [RSLint's rslint_lsp crate][install-rslint]. Ensure the `rslint-lsp` command is in `$PATH`. -* **Rome**: Run `yarn` in the `rome/` directory. * **TypeScript**: Run `yarn` in the `typescript/` and `typescript-jsx/` directories. * **quick-lint-js**: Install quick-lint-js. Ensure the `quick-lint-js` command diff --git a/benchmark/benchmark-lsp/benchmark-config.cpp b/benchmark/benchmark-lsp/benchmark-config.cpp index 0dc240b95b..f7d79f58e7 100644 --- a/benchmark/benchmark-lsp/benchmark-config.cpp +++ b/benchmark/benchmark-lsp/benchmark-config.cpp @@ -304,10 +304,10 @@ Benchmark_Config Benchmark_Config::load() { }, Benchmark_Config_Server{ - .name = "Rome", - .program_name = "Rome", + .name = "Biome", + .program_name = "Biome", .command = {"./run.sh"}, - .cwd = "rome/", + .cwd = "biome/", }, Benchmark_Config_Server{ @@ -423,8 +423,8 @@ Benchmark_Config Benchmark_Config::load() { }, Benchmark_Config_Program{ - .name = "Rome", - .get_metadata = []() { return get_yarn_packages_versions("rome"); }, + .name = "Biome", + .get_metadata = []() { return get_yarn_packages_versions("biome"); }, }, Benchmark_Config_Program{ diff --git a/benchmark/benchmark-lsp/rome/.gitignore b/benchmark/benchmark-lsp/biome/.gitignore similarity index 100% rename from benchmark/benchmark-lsp/rome/.gitignore rename to benchmark/benchmark-lsp/biome/.gitignore diff --git a/benchmark/benchmark-lsp/rome/package.json b/benchmark/benchmark-lsp/biome/package.json similarity index 51% rename from benchmark/benchmark-lsp/rome/package.json rename to benchmark/benchmark-lsp/biome/package.json index 68d4805b83..54dc3bd748 100644 --- a/benchmark/benchmark-lsp/rome/package.json +++ b/benchmark/benchmark-lsp/biome/package.json @@ -1,5 +1,5 @@ { "dependencies": { - "rome": "*" + "@biomejs/biome": "*" } } diff --git a/benchmark/benchmark-lsp/rome/run.sh b/benchmark/benchmark-lsp/biome/run.sh similarity index 91% rename from benchmark/benchmark-lsp/rome/run.sh rename to benchmark/benchmark-lsp/biome/run.sh index bfc0b61c69..68e250f5e0 100755 --- a/benchmark/benchmark-lsp/rome/run.sh +++ b/benchmark/benchmark-lsp/biome/run.sh @@ -7,8 +7,8 @@ set -e set -u here="$(dirname "${0}")" -"${here}/node_modules/.bin/rome" stop >&2 -exec "${here}/node_modules/.bin/rome" lsp-proxy +"${here}/node_modules/.bin/biome" stop >&2 +exec "${here}/node_modules/.bin/biome" lsp-proxy # quick-lint-js finds bugs in JavaScript programs. # Copyright (C) 2020 Matthew "strager" Glazar diff --git a/benchmark/benchmark-lsp/biome/yarn.lock b/benchmark/benchmark-lsp/biome/yarn.lock new file mode 100644 index 0000000000..7b0edd13f7 --- /dev/null +++ b/benchmark/benchmark-lsp/biome/yarn.lock @@ -0,0 +1,45 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@biomejs/biome@*": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@biomejs/biome/-/biome-1.3.1.tgz#6ab36d619e04ebd22ca96a7ea3386acd3bddd1d8" + integrity sha512-ufGCBj8ZNbF+vZDZscqvvLIGsh8M4BduQoJ1X3nm8c9Dupp8gzAKibZSWDLLcgnsAVeKEmWwY6r3Wv/JIa0LgA== + optionalDependencies: + "@biomejs/cli-darwin-arm64" "1.3.1" + "@biomejs/cli-darwin-x64" "1.3.1" + "@biomejs/cli-linux-arm64" "1.3.1" + "@biomejs/cli-linux-x64" "1.3.1" + "@biomejs/cli-win32-arm64" "1.3.1" + "@biomejs/cli-win32-x64" "1.3.1" + +"@biomejs/cli-darwin-arm64@1.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.3.1.tgz#170b0063686112dc667f1b40170d83da19216241" + integrity sha512-m3cBroQftLFYFh3to6RO4ooLqZsE2K9yf5xOlDjm6D4Vrgq85XFwDOxjjJyGGDjDPQ55xGunm80qmGr8jTjiyA== + +"@biomejs/cli-darwin-x64@1.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.3.1.tgz#170569dbdc874e2b926790dbf66f32bf05ea0a85" + integrity sha512-i2yDivc/HHBRFJMoRUUPsFs9pKK0NnS/8tQg/uqNsAkLMF9OKZCCxtUJPmpUBHpdQ2f39An1cVpFmCIEv0uYJQ== + +"@biomejs/cli-linux-arm64@1.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.3.1.tgz#8c26ad89eb8bab3a680ede83430e593ceed4ac0a" + integrity sha512-H56MB7Mf59snzG+nLpfS2j3jXsJ+a6aQOBeRiT0rgn44FZ63yI9jWNIgN1+Xylsa8shmwtquOkoxLS/4KKt0Qg== + +"@biomejs/cli-linux-x64@1.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64/-/cli-linux-x64-1.3.1.tgz#47604e949f4cb9c4343e03a088cd86f7768a4359" + integrity sha512-8ENayCpYXXC77a7AxDNjC+pPKMYteLzysxhkCCZ7Gd2sWtrH8iMM45JL8wQJhoHz5NT3+qgsfGafiNuxeVAVlg== + +"@biomejs/cli-win32-arm64@1.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.3.1.tgz#0a32fee3f71971854df5bf126250661dd09b2465" + integrity sha512-gAx/E949/1/jQDwG9nTspVtjikBI/y7RbbUwwBVABF1bcAUC63VhrHfKJRbM7VTXMlZ7n9YrxkyMww8vf40qcQ== + +"@biomejs/cli-win32-x64@1.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-x64/-/cli-win32-x64-1.3.1.tgz#dc5d5f4198333de084ee35773a3f8681847cd2d0" + integrity sha512-+08eKmEdVM7d4UxY/tff2aPXbeUNNp6wwH7v0FbrE+25mH9lhELgylEk4+k6OLXOcDT7KDAduzP2f9CuM/Aj9w== diff --git a/benchmark/benchmark-lsp/rome/yarn.lock b/benchmark/benchmark-lsp/rome/yarn.lock deleted file mode 100644 index 1abaa93455..0000000000 --- a/benchmark/benchmark-lsp/rome/yarn.lock +++ /dev/null @@ -1,45 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@rometools/cli-darwin-arm64@12.1.3": - version "12.1.3" - resolved "https://registry.yarnpkg.com/@rometools/cli-darwin-arm64/-/cli-darwin-arm64-12.1.3.tgz#b00fe225e34047c4dac63588e237b11ebec47694" - integrity sha512-AmFTUDYjBuEGQp/Wwps+2cqUr+qhR7gyXAUnkL5psCuNCz3807TrUq/ecOoct5MIavGJTH6R4aaSL6+f+VlBEg== - -"@rometools/cli-darwin-x64@12.1.3": - version "12.1.3" - resolved "https://registry.yarnpkg.com/@rometools/cli-darwin-x64/-/cli-darwin-x64-12.1.3.tgz#e5bbf02afb1aab7447e743092245dea992b4b29f" - integrity sha512-k8MbWna8q4LRlb005N2X+JS1UQ+s3ZLBBvwk4fP8TBxlAJXUz17jLLu/Fi+7DTTEmMhM84TWj4FDKW+rNar28g== - -"@rometools/cli-linux-arm64@12.1.3": - version "12.1.3" - resolved "https://registry.yarnpkg.com/@rometools/cli-linux-arm64/-/cli-linux-arm64-12.1.3.tgz#e75b01b74c134edc811e21fa7e1e440602930d59" - integrity sha512-X/uLhJ2/FNA3nu5TiyeNPqiD3OZoFfNfRvw6a3ut0jEREPvEn72NI7WPijH/gxSz55znfQ7UQ6iM4DZumUknJg== - -"@rometools/cli-linux-x64@12.1.3": - version "12.1.3" - resolved "https://registry.yarnpkg.com/@rometools/cli-linux-x64/-/cli-linux-x64-12.1.3.tgz#2b9f4a68079783f275d4d27df83e4fa2220ec6fc" - integrity sha512-csP17q1eWiUXx9z6Jr/JJPibkplyKIwiWPYNzvPCGE8pHlKhwZj3YHRuu7Dm/4EOqx0XFIuqqWZUYm9bkIC8xg== - -"@rometools/cli-win32-arm64@12.1.3": - version "12.1.3" - resolved "https://registry.yarnpkg.com/@rometools/cli-win32-arm64/-/cli-win32-arm64-12.1.3.tgz#714acb67ac4ea4c15e2bc6aea4dd290c76c8efc6" - integrity sha512-RymHWeod57EBOJY4P636CgUwYA6BQdkQjh56XKk4pLEHO6X1bFyMet2XL7KlHw5qOTalzuzf5jJqUs+vf3jdXQ== - -"@rometools/cli-win32-x64@12.1.3": - version "12.1.3" - resolved "https://registry.yarnpkg.com/@rometools/cli-win32-x64/-/cli-win32-x64-12.1.3.tgz#b4f53491d2ca8f1234b3613b7cc73418ad8d76bb" - integrity sha512-yHSKYidqJMV9nADqg78GYA+cZ0hS1twANAjiFibQdXj9aGzD+s/IzIFEIi/U/OBLvWYg/SCw0QVozi2vTlKFDQ== - -rome@*: - version "12.1.3" - resolved "https://registry.yarnpkg.com/rome/-/rome-12.1.3.tgz#4d4d62cad16216843680bd3ca11a4c248134902a" - integrity sha512-e+ff72hxDpe/t5/Us7YRBVw3PBET7SeczTQNn6tvrWdrCaAw3qOukQQ+tDCkyFtS4yGsnhjrJbm43ctNbz27Yg== - optionalDependencies: - "@rometools/cli-darwin-arm64" "12.1.3" - "@rometools/cli-darwin-x64" "12.1.3" - "@rometools/cli-linux-arm64" "12.1.3" - "@rometools/cli-linux-x64" "12.1.3" - "@rometools/cli-win32-arm64" "12.1.3" - "@rometools/cli-win32-x64" "12.1.3" From 96d8b8e3344c599ce05492b95c27d5b11956868f Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Thu, 26 Oct 2023 16:41:49 -0700 Subject: [PATCH 012/117] chore(benchmark-lsp): upgrade linters Run 'yarn upgrade --latest && git checkout -- package.json && yarn' to update ESLint, TypeScript, and Flow. --- benchmark/benchmark-lsp/eslint/yarn.lock | 1421 +++++++++++------ benchmark/benchmark-lsp/flow/yarn.lock | 6 +- .../benchmark-lsp/typescript-jsx/yarn.lock | 498 +----- benchmark/benchmark-lsp/typescript/yarn.lock | 498 +----- 4 files changed, 913 insertions(+), 1510 deletions(-) diff --git a/benchmark/benchmark-lsp/eslint/yarn.lock b/benchmark/benchmark-lsp/eslint/yarn.lock index a666f30832..80ca535aa0 100644 --- a/benchmark/benchmark-lsp/eslint/yarn.lock +++ b/benchmark/benchmark-lsp/eslint/yarn.lock @@ -2,34 +2,61 @@ # yarn lockfile v1 -"@eslint/eslintrc@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f" - integrity sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw== +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": + version "4.10.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" + integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== + +"@eslint/eslintrc@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396" + integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.3.2" - globals "^13.15.0" + espree "^9.6.0" + globals "^13.19.0" ignore "^5.2.0" import-fresh "^3.2.1" js-yaml "^4.1.0" minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@humanwhocodes/config-array@^0.9.2": - version "0.9.5" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7" - integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw== +"@eslint/js@8.52.0": + version "8.52.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.52.0.tgz#78fe5f117840f69dc4a353adf9b9cd926353378c" + integrity sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA== + +"@humanwhocodes/config-array@^0.11.13": + version "0.11.13" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.13.tgz#075dc9684f40a531d9b26b0822153c1e832ee297" + integrity sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ== dependencies: - "@humanwhocodes/object-schema" "^1.2.1" + "@humanwhocodes/object-schema" "^2.0.1" debug "^4.1.1" - minimatch "^3.0.4" + minimatch "^3.0.5" -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz#e5211452df060fa8522b55c7b3c0c4d1981cb044" + integrity sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -44,7 +71,7 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -"@nodelib/fs.walk@^1.2.3": +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": version "1.2.8" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== @@ -52,107 +79,122 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@types/json-schema@^7.0.9": - version "7.0.11" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" - integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== +"@types/json-schema@^7.0.12": + version "7.0.14" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.14.tgz#74a97a5573980802f32c8e47b663530ab3b6b7d1" + integrity sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw== "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== +"@types/semver@^7.5.0": + version "7.5.4" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.4.tgz#0a41252ad431c473158b22f9bfb9a63df7541cff" + integrity sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ== + "@typescript-eslint/eslint-plugin@*": - version "5.26.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.26.0.tgz#c1f98ccba9d345e38992975d3ca56ed6260643c2" - integrity sha512-oGCmo0PqnRZZndr+KwvvAUvD3kNE4AfyoGCwOZpoCncSh4MVD06JTE8XQa2u9u+NX5CsyZMBTEc2C72zx38eYA== - dependencies: - "@typescript-eslint/scope-manager" "5.26.0" - "@typescript-eslint/type-utils" "5.26.0" - "@typescript-eslint/utils" "5.26.0" + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.0.tgz#fdb6f3821c0167e3356e9d89c80e8230b2e401f4" + integrity sha512-lgX7F0azQwRPB7t7WAyeHWVfW1YJ9NIgd9mvGhfQpRY56X6AVf8mwM8Wol+0z4liE7XX3QOt8MN1rUKCfSjRIA== + dependencies: + "@eslint-community/regexpp" "^4.5.1" + "@typescript-eslint/scope-manager" "6.9.0" + "@typescript-eslint/type-utils" "6.9.0" + "@typescript-eslint/utils" "6.9.0" + "@typescript-eslint/visitor-keys" "6.9.0" debug "^4.3.4" - functional-red-black-tree "^1.0.1" - ignore "^5.2.0" - regexpp "^3.2.0" - semver "^7.3.7" - tsutils "^3.21.0" + graphemer "^1.4.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" "@typescript-eslint/parser@*": - version "5.26.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.26.0.tgz#a61b14205fe2ab7533deb4d35e604add9a4ceee2" - integrity sha512-n/IzU87ttzIdnAH5vQ4BBDnLPly7rC5VnjN3m0xBG82HK6rhRxnCb3w/GyWbNDghPd+NktJqB/wl6+YkzZ5T5Q== - dependencies: - "@typescript-eslint/scope-manager" "5.26.0" - "@typescript-eslint/types" "5.26.0" - "@typescript-eslint/typescript-estree" "5.26.0" + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.9.0.tgz#2b402cadeadd3f211c25820e5433413347b27391" + integrity sha512-GZmjMh4AJ/5gaH4XF2eXA8tMnHWP+Pm1mjQR2QN4Iz+j/zO04b9TOvJYOX2sCNIQHtRStKTxRY1FX7LhpJT4Gw== + dependencies: + "@typescript-eslint/scope-manager" "6.9.0" + "@typescript-eslint/types" "6.9.0" + "@typescript-eslint/typescript-estree" "6.9.0" + "@typescript-eslint/visitor-keys" "6.9.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.26.0": - version "5.26.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.26.0.tgz#44209c7f649d1a120f0717e0e82da856e9871339" - integrity sha512-gVzTJUESuTwiju/7NiTb4c5oqod8xt5GhMbExKsCTp6adU3mya6AGJ4Pl9xC7x2DX9UYFsjImC0mA62BCY22Iw== +"@typescript-eslint/scope-manager@6.9.0": + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.9.0.tgz#2626e9a7fe0e004c3e25f3b986c75f584431134e" + integrity sha512-1R8A9Mc39n4pCCz9o79qRO31HGNDvC7UhPhv26TovDsWPBDx+Sg3rOZdCELIA3ZmNoWAuxaMOT7aWtGRSYkQxw== dependencies: - "@typescript-eslint/types" "5.26.0" - "@typescript-eslint/visitor-keys" "5.26.0" + "@typescript-eslint/types" "6.9.0" + "@typescript-eslint/visitor-keys" "6.9.0" -"@typescript-eslint/type-utils@5.26.0": - version "5.26.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.26.0.tgz#937dee97702361744a3815c58991acf078230013" - integrity sha512-7ccbUVWGLmcRDSA1+ADkDBl5fP87EJt0fnijsMFTVHXKGduYMgienC/i3QwoVhDADUAPoytgjbZbCOMj4TY55A== +"@typescript-eslint/type-utils@6.9.0": + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.9.0.tgz#23923c8c9677c2ad41457cf8e10a5f2946be1b04" + integrity sha512-XXeahmfbpuhVbhSOROIzJ+b13krFmgtc4GlEuu1WBT+RpyGPIA4Y/eGnXzjbDj5gZLzpAXO/sj+IF/x2GtTMjQ== dependencies: - "@typescript-eslint/utils" "5.26.0" + "@typescript-eslint/typescript-estree" "6.9.0" + "@typescript-eslint/utils" "6.9.0" debug "^4.3.4" - tsutils "^3.21.0" + ts-api-utils "^1.0.1" -"@typescript-eslint/types@5.26.0": - version "5.26.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.26.0.tgz#cb204bb154d3c103d9cc4d225f311b08219469f3" - integrity sha512-8794JZFE1RN4XaExLWLI2oSXsVImNkl79PzTOOWt9h0UHROwJedNOD2IJyfL0NbddFllcktGIO2aOu10avQQyA== +"@typescript-eslint/types@6.9.0": + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.9.0.tgz#86a0cbe7ac46c0761429f928467ff3d92f841098" + integrity sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw== -"@typescript-eslint/typescript-estree@5.26.0": - version "5.26.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.26.0.tgz#16cbceedb0011c2ed4f607255f3ee1e6e43b88c3" - integrity sha512-EyGpw6eQDsfD6jIqmXP3rU5oHScZ51tL/cZgFbFBvWuCwrIptl+oueUZzSmLtxFuSOQ9vDcJIs+279gnJkfd1w== +"@typescript-eslint/typescript-estree@6.9.0": + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.0.tgz#d0601b245be873d8fe49f3737f93f8662c8693d4" + integrity sha512-NJM2BnJFZBEAbCfBP00zONKXvMqihZCrmwCaik0UhLr0vAgb6oguXxLX1k00oQyD+vZZ+CJn3kocvv2yxm4awQ== dependencies: - "@typescript-eslint/types" "5.26.0" - "@typescript-eslint/visitor-keys" "5.26.0" + "@typescript-eslint/types" "6.9.0" + "@typescript-eslint/visitor-keys" "6.9.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" - semver "^7.3.7" - tsutils "^3.21.0" - -"@typescript-eslint/utils@5.26.0": - version "5.26.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.26.0.tgz#896b8480eb124096e99c8b240460bb4298afcfb4" - integrity sha512-PJFwcTq2Pt4AMOKfe3zQOdez6InIDOjUJJD3v3LyEtxHGVVRK3Vo7Dd923t/4M9hSH2q2CLvcTdxlLPjcIk3eg== - dependencies: - "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.26.0" - "@typescript-eslint/types" "5.26.0" - "@typescript-eslint/typescript-estree" "5.26.0" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - -"@typescript-eslint/visitor-keys@5.26.0": - version "5.26.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.26.0.tgz#7195f756e367f789c0e83035297c45b417b57f57" - integrity sha512-wei+ffqHanYDOQgg/fS6Hcar6wAWv0CUPQ3TZzOWd2BLfgP539rb49bwua8WRAs7R6kOSLn82rfEu2ro6Llt8Q== - dependencies: - "@typescript-eslint/types" "5.26.0" - eslint-visitor-keys "^3.3.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/utils@6.9.0": + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.9.0.tgz#5bdac8604fca4823f090e4268e681c84d3597c9f" + integrity sha512-5Wf+Jsqya7WcCO8me504FBigeQKVLAMPmUzYgDbWchINNh1KJbxCgVya3EQ2MjvJMVeXl3pofRmprqX6mfQkjQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.12" + "@types/semver" "^7.5.0" + "@typescript-eslint/scope-manager" "6.9.0" + "@typescript-eslint/types" "6.9.0" + "@typescript-eslint/typescript-estree" "6.9.0" + semver "^7.5.4" + +"@typescript-eslint/visitor-keys@6.9.0": + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz#cc69421c10c4ac997ed34f453027245988164e80" + integrity sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg== + dependencies: + "@typescript-eslint/types" "6.9.0" + eslint-visitor-keys "^3.4.1" + +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.7.1: - version "8.7.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" - integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== +acorn@^8.9.0: + version "8.11.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.1.tgz#29c6f12c3002d884b6f8baa37089e1917425cd3d" + integrity sha512-IJTNCJMRHfRfb8un89z1QtS0x890C2QUrUxFMK8zy+RizcId6mfnqOf68Bu9YkDgpLYuvCm6aYbwDatXVZPjMQ== -ajv@^6.10.0, ajv@^6.12.4: +ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -179,15 +221,23 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -array-includes@^3.1.4, array-includes@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.5.tgz#2c320010db8d31031fd2a5f6b3bbd4b1aad31bdb" - integrity sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ== +array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== dependencies: call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.19.5" - get-intrinsic "^1.1.1" + is-array-buffer "^3.0.1" + +array-includes@^3.1.6, array-includes@^3.1.7: + version "3.1.7" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" + integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" is-string "^1.0.7" array-union@^2.1.0: @@ -195,25 +245,72 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array.prototype.flat@^1.2.5: - version "1.3.0" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz#0b0c1567bf57b38b56b4c97b8aa72ab45e4adc7b" - integrity sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw== +array.prototype.findlastindex@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz#b37598438f97b579166940814e2c0493a4f50207" + integrity sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" + get-intrinsic "^1.2.1" -array.prototype.flatmap@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz#a7e8ed4225f4788a70cd910abcf0791e76a5534f" - integrity sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg== +array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" + integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +array.prototype.flatmap@^1.3.1, array.prototype.flatmap@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" + integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +array.prototype.tosorted@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.2.tgz#620eff7442503d66c799d95503f82b475745cefd" + integrity sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" + get-intrinsic "^1.2.1" + +arraybuffer.prototype.slice@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz#98bd561953e3e74bb34938e77647179dfe6e9f12" + integrity sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw== + dependencies: + array-buffer-byte-length "^1.0.0" + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + is-array-buffer "^3.0.2" + is-shared-array-buffer "^1.0.2" + +asynciterator.prototype@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz#8c5df0514936cdd133604dfcc9d3fb93f09b2b62" + integrity sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg== + dependencies: + has-symbols "^1.0.3" + +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== balanced-match@^1.0.0: version "1.0.2" @@ -240,13 +337,14 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== +call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" + integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" + function-bind "^1.1.2" + get-intrinsic "^1.2.1" + set-function-length "^1.1.1" callsites@^3.0.0: version "3.1.0" @@ -297,13 +395,6 @@ cssesc@^3.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -debug@^2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -323,11 +414,21 @@ deep-is@^0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -define-properties@^1.1.3, define-properties@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" - integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== +define-data-property@^1.0.1, define-data-property@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" + integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== dependencies: + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + +define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" has-property-descriptors "^1.0.0" object-keys "^1.1.1" @@ -352,41 +453,86 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.5: - version "1.20.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814" - integrity sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA== +es-abstract@^1.22.1: + version "1.22.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.3.tgz#48e79f5573198de6dee3589195727f4f74bc4f32" + integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== dependencies: - call-bind "^1.0.2" + array-buffer-byte-length "^1.0.0" + arraybuffer.prototype.slice "^1.0.2" + available-typed-arrays "^1.0.5" + call-bind "^1.0.5" + es-set-tostringtag "^2.0.1" es-to-primitive "^1.2.1" - function-bind "^1.1.1" - function.prototype.name "^1.1.5" - get-intrinsic "^1.1.1" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.2" get-symbol-description "^1.0.0" - has "^1.0.3" + globalthis "^1.0.3" + gopd "^1.0.1" has-property-descriptors "^1.0.0" + has-proto "^1.0.1" has-symbols "^1.0.3" - internal-slot "^1.0.3" - is-callable "^1.2.4" + hasown "^2.0.0" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" + is-callable "^1.2.7" is-negative-zero "^2.0.2" is-regex "^1.1.4" is-shared-array-buffer "^1.0.2" is-string "^1.0.7" + is-typed-array "^1.1.12" is-weakref "^1.0.2" - object-inspect "^1.12.0" + object-inspect "^1.13.1" object-keys "^1.1.1" - object.assign "^4.1.2" - regexp.prototype.flags "^1.4.3" - string.prototype.trimend "^1.0.5" - string.prototype.trimstart "^1.0.5" + object.assign "^4.1.4" + regexp.prototype.flags "^1.5.1" + safe-array-concat "^1.0.1" + safe-regex-test "^1.0.0" + string.prototype.trim "^1.2.8" + string.prototype.trimend "^1.0.7" + string.prototype.trimstart "^1.0.7" + typed-array-buffer "^1.0.0" + typed-array-byte-length "^1.0.0" + typed-array-byte-offset "^1.0.0" + typed-array-length "^1.0.4" unbox-primitive "^1.0.2" + which-typed-array "^1.1.13" + +es-iterator-helpers@^1.0.12: + version "1.0.15" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz#bd81d275ac766431d19305923707c3efd9f1ae40" + integrity sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g== + dependencies: + asynciterator.prototype "^1.0.0" + call-bind "^1.0.2" + define-properties "^1.2.1" + es-abstract "^1.22.1" + es-set-tostringtag "^2.0.1" + function-bind "^1.1.1" + get-intrinsic "^1.2.1" + globalthis "^1.0.3" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + internal-slot "^1.0.5" + iterator.prototype "^1.1.2" + safe-array-concat "^1.0.1" + +es-set-tostringtag@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz#11f7cc9f63376930a5f20be4915834f4bc74f9c9" + integrity sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q== + dependencies: + get-intrinsic "^1.2.2" + has-tostringtag "^1.0.0" + hasown "^2.0.0" es-shim-unscopables@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" - integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== + version "1.0.2" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" + integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== dependencies: - has "^1.0.3" + hasown "^2.0.0" es-to-primitive@^1.2.1: version "1.2.1" @@ -412,161 +558,150 @@ eslint-config-airbnb-base@*: object.entries "^1.1.5" semver "^6.3.0" -eslint-import-resolver-node@^0.3.6: - version "0.3.6" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" - integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== +eslint-import-resolver-node@^0.3.9: + version "0.3.9" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" + integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== dependencies: debug "^3.2.7" - resolve "^1.20.0" + is-core-module "^2.13.0" + resolve "^1.22.4" -eslint-module-utils@^2.7.3: - version "2.7.3" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee" - integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ== +eslint-module-utils@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz#e439fee65fc33f6bba630ff621efc38ec0375c49" + integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== dependencies: debug "^3.2.7" - find-up "^2.1.0" eslint-plugin-import@*: - version "2.26.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz#f812dc47be4f2b72b478a021605a59fc6fe8b88b" - integrity sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA== - dependencies: - array-includes "^3.1.4" - array.prototype.flat "^1.2.5" - debug "^2.6.9" + version "2.29.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz#8133232e4329ee344f2f612885ac3073b0b7e155" + integrity sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg== + dependencies: + array-includes "^3.1.7" + array.prototype.findlastindex "^1.2.3" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" + debug "^3.2.7" doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.6" - eslint-module-utils "^2.7.3" - has "^1.0.3" - is-core-module "^2.8.1" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.8.0" + hasown "^2.0.0" + is-core-module "^2.13.1" is-glob "^4.0.3" minimatch "^3.1.2" - object.values "^1.1.5" - resolve "^1.22.0" - tsconfig-paths "^3.14.1" + object.fromentries "^2.0.7" + object.groupby "^1.0.1" + object.values "^1.1.7" + semver "^6.3.1" + tsconfig-paths "^3.14.2" eslint-plugin-react@*: - version "7.30.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.30.0.tgz#8e7b1b2934b8426ac067a0febade1b13bd7064e3" - integrity sha512-RgwH7hjW48BleKsYyHK5vUAvxtE9SMPDKmcPRQgtRCYaZA0XQPt5FSkrU3nhz5ifzMZcA8opwmRJ2cmOO8tr5A== + version "7.33.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz#69ee09443ffc583927eafe86ffebb470ee737608" + integrity sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw== dependencies: - array-includes "^3.1.5" - array.prototype.flatmap "^1.3.0" + array-includes "^3.1.6" + array.prototype.flatmap "^1.3.1" + array.prototype.tosorted "^1.1.1" doctrine "^2.1.0" + es-iterator-helpers "^1.0.12" estraverse "^5.3.0" jsx-ast-utils "^2.4.1 || ^3.0.0" minimatch "^3.1.2" - object.entries "^1.1.5" - object.fromentries "^2.0.5" - object.hasown "^1.1.1" - object.values "^1.1.5" + object.entries "^1.1.6" + object.fromentries "^2.0.6" + object.hasown "^1.1.2" + object.values "^1.1.6" prop-types "^15.8.1" - resolve "^2.0.0-next.3" - semver "^6.3.0" - string.prototype.matchall "^4.0.7" + resolve "^2.0.0-next.4" + semver "^6.3.1" + string.prototype.matchall "^4.0.8" eslint-plugin-vue@*: - version "9.0.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.0.1.tgz#66ba4a6e4085a26a724adcde06eaf72b178285c9" - integrity sha512-/w/9/vzz+4bSYtp5UqXgJ0CfycXTMtpp6lkz7/fMp0CcJxPWyRP6Pr88ihhrsNEcVt2ZweMupWRNYa+5Md41LQ== + version "9.18.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.18.0.tgz#2a2dbb3c67317e8c11ab56cafaa15a3a7eac6282" + integrity sha512-yUM8a2OD/7Qs0PiugkRaxgz5KBRvzMvWShity2UvVFAN0yk8029mGpTdg/TNARPiYzp335mEwDHwcAR8tQNe4g== dependencies: - eslint-utils "^3.0.0" + "@eslint-community/eslint-utils" "^4.4.0" natural-compare "^1.4.0" - nth-check "^2.0.1" - postcss-selector-parser "^6.0.9" - semver "^7.3.5" - vue-eslint-parser "^9.0.1" + nth-check "^2.1.1" + postcss-selector-parser "^6.0.13" + semver "^7.5.4" + vue-eslint-parser "^9.3.1" xml-name-validator "^4.0.0" -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-scope@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" - integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== +eslint-scope@^7.1.1, eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - -eslint-visitor-keys@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" - integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== eslint@*: - version "8.16.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.16.0.tgz#6d936e2d524599f2a86c708483b4c372c5d3bbae" - integrity sha512-MBndsoXY/PeVTDJeWsYj7kLZ5hQpJOfMYLsF6LicLHQWbRDG19lK5jOix4DPl8yY4SUFcE3txy86OzFLWT+yoA== - dependencies: - "@eslint/eslintrc" "^1.3.0" - "@humanwhocodes/config-array" "^0.9.2" - ajv "^6.10.0" + version "8.52.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.52.0.tgz#d0cd4a1fac06427a61ef9242b9353f36ea7062fc" + integrity sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.2" + "@eslint/js" "8.52.0" + "@humanwhocodes/config-array" "^0.11.13" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" debug "^4.3.2" doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.1.1" - eslint-utils "^3.0.0" - eslint-visitor-keys "^3.3.0" - espree "^9.3.2" - esquery "^1.4.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" esutils "^2.0.2" fast-deep-equal "^3.1.3" file-entry-cache "^6.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^6.0.1" - globals "^13.15.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" ignore "^5.2.0" - import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" + is-path-inside "^3.0.3" js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" lodash.merge "^4.6.2" minimatch "^3.1.2" natural-compare "^1.4.0" - optionator "^0.9.1" - regexpp "^3.2.0" + optionator "^0.9.3" strip-ansi "^6.0.1" - strip-json-comments "^3.1.0" text-table "^0.2.0" - v8-compile-cache "^2.0.3" -espree@^9.3.1, espree@^9.3.2: - version "9.3.2" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.2.tgz#f58f77bd334731182801ced3380a8cc859091596" - integrity sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA== +espree@^9.3.1, espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== dependencies: - acorn "^8.7.1" + acorn "^8.9.0" acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.3.0" + eslint-visitor-keys "^3.4.1" -esquery@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== +esquery@^1.4.0, esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== dependencies: estraverse "^5.1.0" @@ -577,11 +712,6 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" @@ -598,9 +728,9 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== fast-glob@^3.2.9: - version "3.2.11" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" - integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== + version "3.3.1" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" + integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -616,12 +746,12 @@ fast-json-stable-stringify@^2.0.0: fast-levenshtein@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== fastq@^1.6.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" - integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + version "1.15.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== dependencies: reusify "^1.0.4" @@ -639,64 +769,69 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== dependencies: - locate-path "^2.0.0" + locate-path "^6.0.0" + path-exists "^4.0.0" flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + version "3.1.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.1.1.tgz#a02a15fdec25a8f844ff7cc658f03dd99eb4609b" + integrity sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q== dependencies: - flatted "^3.1.0" + flatted "^3.2.9" + keyv "^4.5.3" rimraf "^3.0.2" -flatted@^3.1.0: - version "3.2.5" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" - integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== +flatted@^3.2.9: + version "3.2.9" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" + integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== + +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.1, function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== -function.prototype.name@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" - integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== +function.prototype.name@^1.1.5, function.prototype.name@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - functions-have-names "^1.2.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + functions-have-names "^1.2.3" -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -functions-have-names@^1.2.2: +functions-have-names@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" + integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" get-symbol-description@^1.0.0: version "1.0.0" @@ -713,7 +848,7 @@ glob-parent@^5.1.2: dependencies: is-glob "^4.0.1" -glob-parent@^6.0.1: +glob-parent@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== @@ -732,13 +867,20 @@ glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" -globals@^13.15.0: - version "13.15.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.15.0.tgz#38113218c907d2f7e98658af246cef8b77e90bac" - integrity sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog== +globals@^13.19.0: + version "13.23.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.23.0.tgz#ef31673c926a0976e1f61dab4dca57e0c0a8af02" + integrity sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA== dependencies: type-fest "^0.20.2" +globalthis@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" + integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== + dependencies: + define-properties "^1.1.3" + globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" @@ -751,6 +893,18 @@ globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" @@ -762,13 +916,18 @@ has-flag@^4.0.0: integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== has-property-descriptors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" - integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340" + integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== dependencies: - get-intrinsic "^1.1.1" + get-intrinsic "^1.2.2" -has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== @@ -780,19 +939,19 @@ has-tostringtag@^1.0.0: dependencies: has-symbols "^1.0.2" -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== dependencies: - function-bind "^1.1.1" + function-bind "^1.1.2" -ignore@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" - integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== +ignore@^5.2.0, ignore@^5.2.4: + version "5.2.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== -import-fresh@^3.0.0, import-fresh@^3.2.1: +import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -803,12 +962,12 @@ import-fresh@^3.0.0, import-fresh@^3.2.1: imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" wrappy "1" @@ -818,15 +977,31 @@ inherits@2: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -internal-slot@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" - integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== +internal-slot@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.6.tgz#37e756098c4911c5e912b8edbf71ed3aa116f930" + integrity sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg== dependencies: - get-intrinsic "^1.1.0" - has "^1.0.3" + get-intrinsic "^1.2.2" + hasown "^2.0.0" side-channel "^1.0.4" +is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + is-typed-array "^1.1.10" + +is-async-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646" + integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA== + dependencies: + has-tostringtag "^1.0.0" + is-bigint@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" @@ -842,19 +1017,19 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-callable@^1.1.4, is-callable@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" - integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.2.0, is-core-module@^2.8.1: - version "2.9.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69" - integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== +is-core-module@^2.13.0, is-core-module@^2.13.1: + version "2.13.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== dependencies: - has "^1.0.3" + hasown "^2.0.0" -is-date-object@^1.0.1: +is-date-object@^1.0.1, is-date-object@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== @@ -864,7 +1039,21 @@ is-date-object@^1.0.1: is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-finalizationregistry@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz#c8749b65f17c133313e661b1289b95ad3dbd62e6" + integrity sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw== + dependencies: + call-bind "^1.0.2" + +is-generator-function@^1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: version "4.0.3" @@ -873,6 +1062,11 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: dependencies: is-extglob "^2.1.1" +is-map@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" + integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== + is-negative-zero@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" @@ -890,6 +1084,11 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" @@ -898,6 +1097,11 @@ is-regex@^1.1.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-set@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" + integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== + is-shared-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" @@ -919,6 +1123,18 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" +is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.9: + version "1.1.12" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" + integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== + dependencies: + which-typed-array "^1.1.11" + +is-weakmap@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" + integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== + is-weakref@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" @@ -926,10 +1142,34 @@ is-weakref@^1.0.2: dependencies: call-bind "^1.0.2" +is-weakset@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d" + integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +iterator.prototype@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0" + integrity sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w== + dependencies: + define-properties "^1.2.1" + get-intrinsic "^1.2.1" + has-symbols "^1.0.3" + reflect.getprototypeof "^1.0.4" + set-function-name "^2.0.1" "js-tokens@^3.0.0 || ^4.0.0": version "4.0.0" @@ -943,6 +1183,11 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -951,22 +1196,31 @@ json-schema-traverse@^0.4.1: json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -json5@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== +json5@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== dependencies: minimist "^1.2.0" "jsx-ast-utils@^2.4.1 || ^3.0.0": - version "3.3.0" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.0.tgz#e624f259143b9062c92b6413ff92a164c80d3ccb" - integrity sha512-XzO9luP6L0xkxwhIJMTJQpZo/eeN60K08jHdexfD569AGxeNug6UketeHXEhROoM8aR7EcUoOQmIhcJQjcuq8Q== + version "3.3.5" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a" + integrity sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ== dependencies: - array-includes "^3.1.4" - object.assign "^4.1.2" + array-includes "^3.1.6" + array.prototype.flat "^1.3.1" + object.assign "^4.1.4" + object.values "^1.1.6" + +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" levn@^0.4.1: version "0.4.1" @@ -976,13 +1230,12 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" + p-locate "^5.0.0" lodash.merge@^4.6.2: version "4.6.2" @@ -1021,7 +1274,7 @@ micromatch@^4.0.4: braces "^3.0.2" picomatch "^2.3.1" -minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -1029,14 +1282,9 @@ minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: brace-expansion "^1.1.7" minimist@^1.2.0, minimist@^1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" - integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== ms@2.1.2: version "2.1.2" @@ -1051,9 +1299,9 @@ ms@^2.1.1: natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -nth-check@^2.0.1: +nth-check@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== @@ -1063,100 +1311,105 @@ nth-check@^2.0.1: object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -object-inspect@^1.12.0, object-inspect@^1.9.0: - version "1.12.2" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" - integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== +object-inspect@^1.13.1, object-inspect@^1.9.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object.assign@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" - integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== +object.assign@^4.1.2, object.assign@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" + integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - has-symbols "^1.0.1" + call-bind "^1.0.2" + define-properties "^1.1.4" + has-symbols "^1.0.3" object-keys "^1.1.1" -object.entries@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861" - integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g== +object.entries@^1.1.5, object.entries@^1.1.6: + version "1.1.7" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.7.tgz#2b47760e2a2e3a752f39dd874655c61a7f03c131" + integrity sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" + define-properties "^1.2.0" + es-abstract "^1.22.1" -object.fromentries@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.5.tgz#7b37b205109c21e741e605727fe8b0ad5fa08251" - integrity sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw== +object.fromentries@^2.0.6, object.fromentries@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.7.tgz#71e95f441e9a0ea6baf682ecaaf37fa2a8d7e616" + integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" + define-properties "^1.2.0" + es-abstract "^1.22.1" -object.hasown@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.1.tgz#ad1eecc60d03f49460600430d97f23882cf592a3" - integrity sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A== +object.groupby@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.1.tgz#d41d9f3c8d6c778d9cbac86b4ee9f5af103152ee" + integrity sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ== dependencies: - define-properties "^1.1.4" - es-abstract "^1.19.5" + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" -object.values@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" - integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== +object.hasown@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.3.tgz#6a5f2897bb4d3668b8e79364f98ccf971bda55ae" + integrity sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA== + dependencies: + define-properties "^1.2.0" + es-abstract "^1.22.1" + +object.values@^1.1.6, object.values@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.7.tgz#617ed13272e7e1071b43973aa1655d9291b8442a" + integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" + define-properties "^1.2.0" + es-abstract "^1.22.1" once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== +optionator@^0.9.3: + version "0.9.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" - word-wrap "^1.2.3" -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== dependencies: - p-try "^1.0.0" + yocto-queue "^0.1.0" -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== dependencies: - p-limit "^1.1.0" - -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + p-limit "^3.0.2" parent-module@^1.0.0: version "1.0.1" @@ -1165,22 +1418,22 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-parse@^1.0.6, path-parse@^1.0.7: +path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== @@ -1195,10 +1448,10 @@ picomatch@^2.3.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -postcss-selector-parser@^6.0.9: - version "6.0.10" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d" - integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w== +postcss-selector-parser@^6.0.13: + version "6.0.13" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz#d05d8d76b1e8e173257ef9d60b706a8e5e99bf1b" + integrity sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ== dependencies: cssesc "^3.0.0" util-deprecate "^1.0.2" @@ -1218,9 +1471,9 @@ prop-types@^15.8.1: react-is "^16.13.1" punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== queue-microtask@^1.2.2: version "1.2.3" @@ -1232,41 +1485,49 @@ react-is@^16.13.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== -regexp.prototype.flags@^1.4.1, regexp.prototype.flags@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" - integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== +reflect.getprototypeof@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz#aaccbf41aca3821b87bb71d9dcbc7ad0ba50a3f3" + integrity sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - functions-have-names "^1.2.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + globalthis "^1.0.3" + which-builtin-type "^1.1.3" -regexpp@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== +regexp.prototype.flags@^1.5.0, regexp.prototype.flags@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" + integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + set-function-name "^2.0.0" resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve@^1.20.0, resolve@^1.22.0: - version "1.22.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" - integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== +resolve@^1.22.4: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== dependencies: - is-core-module "^2.8.1" + is-core-module "^2.13.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^2.0.0-next.3: - version "2.0.0-next.3" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.3.tgz#d41016293d4a8586a39ca5d9b5f15cbea1f55e46" - integrity sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q== +resolve@^2.0.0-next.4: + version "2.0.0-next.5" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" + integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA== dependencies: - is-core-module "^2.2.0" - path-parse "^1.0.6" + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" reusify@^1.0.4: version "1.0.4" @@ -1287,18 +1548,56 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +safe-array-concat@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.1.tgz#91686a63ce3adbea14d61b14c99572a8ff84754c" + integrity sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + has-symbols "^1.0.3" + isarray "^2.0.5" + +safe-regex-test@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" + integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + is-regex "^1.1.4" + +semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.5, semver@^7.3.6, semver@^7.3.7: - version "7.3.7" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" - integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== +semver@^7.3.6, semver@^7.5.4: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== dependencies: lru-cache "^6.0.0" +set-function-length@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed" + integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ== + dependencies: + define-data-property "^1.1.1" + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + +set-function-name@^2.0.0, set-function-name@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" + integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== + dependencies: + define-data-property "^1.0.1" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.0" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -1325,37 +1624,47 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -string.prototype.matchall@^4.0.7: - version "4.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz#8e6ecb0d8a1fb1fda470d81acecb2dba057a481d" - integrity sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg== +string.prototype.matchall@^4.0.8: + version "4.0.10" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz#a1553eb532221d4180c51581d6072cd65d1ee100" + integrity sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - get-intrinsic "^1.1.1" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" has-symbols "^1.0.3" - internal-slot "^1.0.3" - regexp.prototype.flags "^1.4.1" + internal-slot "^1.0.5" + regexp.prototype.flags "^1.5.0" + set-function-name "^2.0.0" side-channel "^1.0.4" -string.prototype.trimend@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0" - integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog== +string.prototype.trim@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" + integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== dependencies: call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.19.5" + define-properties "^1.2.0" + es-abstract "^1.22.1" -string.prototype.trimstart@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef" - integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg== +string.prototype.trimend@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e" + integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== dependencies: call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.19.5" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +string.prototype.trimstart@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298" + integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" strip-ansi@^6.0.1: version "6.0.1" @@ -1367,9 +1676,9 @@ strip-ansi@^6.0.1: strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -1389,7 +1698,7 @@ supports-preserve-symlinks-flag@^1.0.0: text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== to-regex-range@^5.0.1: version "5.0.1" @@ -1398,28 +1707,21 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -tsconfig-paths@^3.14.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" - integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== +ts-api-utils@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.3.tgz#f12c1c781d04427313dbac808f453f050e54a331" + integrity sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg== + +tsconfig-paths@^3.14.2: + version "3.14.2" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088" + integrity sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g== dependencies: "@types/json5" "^0.0.29" - json5 "^1.0.1" + json5 "^1.0.2" minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^1.8.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -1432,10 +1734,49 @@ type-fest@^0.20.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== +typed-array-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" + integrity sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + is-typed-array "^1.1.10" + +typed-array-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz#d787a24a995711611fb2b87a4052799517b230d0" + integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + +typed-array-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" + integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + +typed-array-length@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" + integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + is-typed-array "^1.1.9" + typescript@*: - version "4.7.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.2.tgz#1f9aa2ceb9af87cca227813b4310fff0b51593c4" - integrity sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A== + version "5.2.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" + integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== unbox-primitive@^1.0.2: version "1.0.2" @@ -1457,21 +1798,16 @@ uri-js@^4.2.2: util-deprecate@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -v8-compile-cache@^2.0.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== "vscode-eslint@https://github.com/microsoft/vscode-eslint/archive/d3c7703cd11dc6752c96edf0f140d50156d72dd7.tar.gz": version "2.2.3" resolved "https://github.com/microsoft/vscode-eslint/archive/d3c7703cd11dc6752c96edf0f140d50156d72dd7.tar.gz#c3e3397f7dc1a9ef4eb8fe882cb138cf25cf33e5" -vue-eslint-parser@^9.0.1: - version "9.0.2" - resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-9.0.2.tgz#d2535516f3f55adb387939427fe741065eb7948a" - integrity sha512-uCPQwTGjOtAYrwnU+76pYxalhjsh7iFBsHwBqDHiOPTxtICDaraO4Szw54WFTNZTAEsgHHzqFOu1mmnBOBRzDA== +vue-eslint-parser@^9.3.1: + version "9.3.2" + resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-9.3.2.tgz#6f9638e55703f1c77875a19026347548d93fd499" + integrity sha512-q7tWyCVaV9f8iQyIA5Mkj/S6AoJ9KBN8IeUSf3XEmBrOtxOZnfTg5s4KClbZBCK3GtnT/+RyCLZyDHuZwTuBjg== dependencies: debug "^4.3.4" eslint-scope "^7.1.1" @@ -1492,6 +1828,45 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" +which-builtin-type@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.3.tgz#b1b8443707cc58b6e9bf98d32110ff0c2cbd029b" + integrity sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw== + dependencies: + function.prototype.name "^1.1.5" + has-tostringtag "^1.0.0" + is-async-function "^2.0.0" + is-date-object "^1.0.5" + is-finalizationregistry "^1.0.2" + is-generator-function "^1.0.10" + is-regex "^1.1.4" + is-weakref "^1.0.2" + isarray "^2.0.5" + which-boxed-primitive "^1.0.2" + which-collection "^1.0.1" + which-typed-array "^1.1.9" + +which-collection@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" + integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== + dependencies: + is-map "^2.0.1" + is-set "^2.0.1" + is-weakmap "^2.0.1" + is-weakset "^2.0.1" + +which-typed-array@^1.1.11, which-typed-array@^1.1.13, which-typed-array@^1.1.9: + version "1.1.13" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" + integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.4" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" @@ -1499,15 +1874,10 @@ which@^2.0.1: dependencies: isexe "^2.0.0" -word-wrap@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== xml-name-validator@^4.0.0: version "4.0.0" @@ -1518,3 +1888,8 @@ yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/benchmark/benchmark-lsp/flow/yarn.lock b/benchmark/benchmark-lsp/flow/yarn.lock index 1d93978055..615af73591 100644 --- a/benchmark/benchmark-lsp/flow/yarn.lock +++ b/benchmark/benchmark-lsp/flow/yarn.lock @@ -3,6 +3,6 @@ flow-bin@*: - version "0.179.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.179.0.tgz#a9afbedda1687726296bfc8bd34247a6aae34d4f" - integrity sha512-odCiPkX5Vjrgupqxq2cjib0GtzAjGRHVkLk4TG15N4B+Fd2ghb8HSW6zrdX9GwaXrsuocxm5+oVzkaaUYUf+Pg== + version "0.219.5" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.219.5.tgz#c717695de7f4ac6fc09af5918307dccde270b935" + integrity sha512-dAOF6d7f4IVdh02yO+egQWRTXIIFj61ix47vRBh3Dlr0r6AkiByc5hALMuP/LdXpT3jNAJx/rfQdMa1+5K+c7g== diff --git a/benchmark/benchmark-lsp/typescript-jsx/yarn.lock b/benchmark/benchmark-lsp/typescript-jsx/yarn.lock index eb3d59c9c7..1d56f44ce9 100644 --- a/benchmark/benchmark-lsp/typescript-jsx/yarn.lock +++ b/benchmark/benchmark-lsp/typescript-jsx/yarn.lock @@ -2,498 +2,12 @@ # yarn lockfile v1 -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.walk@^1.2.3": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - -aggregate-error@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" - integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== - dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -clean-stack@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" - integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== - -commander@^9.0.0: - version "9.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-9.2.0.tgz#6e21014b2ed90d8b7c9647230d8b7a94a4a419a9" - integrity sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -crypto-random-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" - integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== - -del@^6.0.0: - version "6.1.1" - resolved "https://registry.yarnpkg.com/del/-/del-6.1.1.tgz#3b70314f1ec0aa325c6b14eb36b95786671edb7a" - integrity sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg== - dependencies: - globby "^11.0.1" - graceful-fs "^4.2.4" - is-glob "^4.0.1" - is-path-cwd "^2.2.0" - is-path-inside "^3.0.2" - p-map "^4.0.0" - rimraf "^3.0.2" - slash "^3.0.0" - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -fast-glob@^3.2.9: - version "3.2.11" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" - integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - -fastq@^1.6.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" - integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== - dependencies: - reusify "^1.0.4" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - -fs-extra@^10.0.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" - integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -glob-parent@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob@^7.1.3: - version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globby@^11.0.1: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" - -graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: - version "4.2.10" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" - integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== - -ignore@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" - integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== - -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-glob@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-path-cwd@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" - integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== - -is-path-inside@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -merge2@^1.3.0, merge2@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== - dependencies: - braces "^3.0.2" - picomatch "^2.3.1" - -minimatch@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -p-debounce@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-debounce/-/p-debounce-2.1.0.tgz#e79f70c6e325cbb9bddbcbec0b81025084671ad3" - integrity sha512-M9bMt62TTnozdZhqFgs+V7XD2MnuKCaz+7fZdlu2/T7xruI3uIE5CicQ0vx1hV7HIUYF0jF+4/R1AgfOkl74Qw== - -p-limit@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - -p-map@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" - integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== - dependencies: - aggregate-error "^3.0.0" - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -pkg-up@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" - integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== - dependencies: - find-up "^3.0.0" - -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -semver@^7.3.5: - version "7.3.7" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" - integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== - dependencies: - lru-cache "^6.0.0" - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -temp-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-2.0.0.tgz#bde92b05bdfeb1516e804c9c00ad45177f31321e" - integrity sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg== - -tempy@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tempy/-/tempy-1.0.1.tgz#30fe901fd869cfb36ee2bd999805aa72fbb035de" - integrity sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w== - dependencies: - del "^6.0.0" - is-stream "^2.0.0" - temp-dir "^2.0.0" - type-fest "^0.16.0" - unique-string "^2.0.0" - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -type-fest@^0.16.0: - version "0.16.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.16.0.tgz#3240b891a78b0deae910dbeb86553e552a148860" - integrity sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg== - typescript-language-server@*: - version "0.10.1" - resolved "https://registry.yarnpkg.com/typescript-language-server/-/typescript-language-server-0.10.1.tgz#69232fcd860209f97f240a83532b306af960f6e1" - integrity sha512-Lk98jYbHthLOhldFziQhk0TubE7RvUtQaVW5un7hOR2uDVH78lQHf5RZsgtmlAECgZRxWXgTOJUZ+BWJ+v/a7A== - dependencies: - commander "^9.0.0" - fs-extra "^10.0.0" - p-debounce "^2.1.0" - pkg-up "^3.1.0" - semver "^7.3.5" - tempy "^1.0.1" - vscode-languageserver "^7.0.0" - vscode-languageserver-protocol "3.16.0" - vscode-languageserver-textdocument "1.0.4" - vscode-uri "^3.0.2" - which "^2.0.2" + version "4.0.0" + resolved "https://registry.yarnpkg.com/typescript-language-server/-/typescript-language-server-4.0.0.tgz#93c753f3caddbe312cc3c0b3c52f19410420a857" + integrity sha512-u6GLfWtHzOfGNpn0XuUYFg8Jv3oXWKzY6o5/Lt6LbWE6Ux965z2lP+vM0AN8Z2EobnlrDzzdcKusUx46j2eP3A== typescript@*: - version "4.7.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.2.tgz#1f9aa2ceb9af87cca227813b4310fff0b51593c4" - integrity sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A== - -unique-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" - integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== - dependencies: - crypto-random-string "^2.0.0" - -universalify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" - integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== - -vscode-jsonrpc@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz#108bdb09b4400705176b957ceca9e0880e9b6d4e" - integrity sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg== - -vscode-languageserver-protocol@3.16.0: - version "3.16.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz#34135b61a9091db972188a07d337406a3cdbe821" - integrity sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A== - dependencies: - vscode-jsonrpc "6.0.0" - vscode-languageserver-types "3.16.0" - -vscode-languageserver-textdocument@1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.4.tgz#3cd56dd14cec1d09e86c4bb04b09a246cb3df157" - integrity sha512-/xhqXP/2A2RSs+J8JNXpiiNVvvNM0oTosNVmQnunlKvq9o4mupHOBAnnzH0lwIPKazXKvAKsVp1kr+H/K4lgoQ== - -vscode-languageserver-types@3.16.0: - version "3.16.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz#ecf393fc121ec6974b2da3efb3155644c514e247" - integrity sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA== - -vscode-languageserver@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-7.0.0.tgz#49b068c87cfcca93a356969d20f5d9bdd501c6b0" - integrity sha512-60HTx5ID+fLRcgdHfmz0LDZAXYEV68fzwG0JWwEPBode9NuMYTIxuYXPg4ngO8i8+Ou0lM7y6GzaYWbiDL0drw== - dependencies: - vscode-languageserver-protocol "3.16.0" - -vscode-uri@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.3.tgz#a95c1ce2e6f41b7549f86279d19f47951e4f4d84" - integrity sha512-EcswR2S8bpR7fD0YPeS7r2xXExrScVMxg4MedACaWHEtx9ftCF/qHG1xGkolzTPcEmjTavCQgbVzHUIdTMzFGA== - -which@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + version "5.2.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" + integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== diff --git a/benchmark/benchmark-lsp/typescript/yarn.lock b/benchmark/benchmark-lsp/typescript/yarn.lock index eb3d59c9c7..1d56f44ce9 100644 --- a/benchmark/benchmark-lsp/typescript/yarn.lock +++ b/benchmark/benchmark-lsp/typescript/yarn.lock @@ -2,498 +2,12 @@ # yarn lockfile v1 -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.walk@^1.2.3": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - -aggregate-error@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" - integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== - dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -clean-stack@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" - integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== - -commander@^9.0.0: - version "9.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-9.2.0.tgz#6e21014b2ed90d8b7c9647230d8b7a94a4a419a9" - integrity sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -crypto-random-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" - integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== - -del@^6.0.0: - version "6.1.1" - resolved "https://registry.yarnpkg.com/del/-/del-6.1.1.tgz#3b70314f1ec0aa325c6b14eb36b95786671edb7a" - integrity sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg== - dependencies: - globby "^11.0.1" - graceful-fs "^4.2.4" - is-glob "^4.0.1" - is-path-cwd "^2.2.0" - is-path-inside "^3.0.2" - p-map "^4.0.0" - rimraf "^3.0.2" - slash "^3.0.0" - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -fast-glob@^3.2.9: - version "3.2.11" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" - integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - -fastq@^1.6.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" - integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== - dependencies: - reusify "^1.0.4" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - -fs-extra@^10.0.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" - integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -glob-parent@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob@^7.1.3: - version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globby@^11.0.1: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" - -graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: - version "4.2.10" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" - integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== - -ignore@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" - integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== - -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-glob@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-path-cwd@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" - integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== - -is-path-inside@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -merge2@^1.3.0, merge2@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== - dependencies: - braces "^3.0.2" - picomatch "^2.3.1" - -minimatch@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -p-debounce@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-debounce/-/p-debounce-2.1.0.tgz#e79f70c6e325cbb9bddbcbec0b81025084671ad3" - integrity sha512-M9bMt62TTnozdZhqFgs+V7XD2MnuKCaz+7fZdlu2/T7xruI3uIE5CicQ0vx1hV7HIUYF0jF+4/R1AgfOkl74Qw== - -p-limit@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - -p-map@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" - integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== - dependencies: - aggregate-error "^3.0.0" - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -pkg-up@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" - integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== - dependencies: - find-up "^3.0.0" - -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -semver@^7.3.5: - version "7.3.7" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" - integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== - dependencies: - lru-cache "^6.0.0" - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -temp-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-2.0.0.tgz#bde92b05bdfeb1516e804c9c00ad45177f31321e" - integrity sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg== - -tempy@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tempy/-/tempy-1.0.1.tgz#30fe901fd869cfb36ee2bd999805aa72fbb035de" - integrity sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w== - dependencies: - del "^6.0.0" - is-stream "^2.0.0" - temp-dir "^2.0.0" - type-fest "^0.16.0" - unique-string "^2.0.0" - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -type-fest@^0.16.0: - version "0.16.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.16.0.tgz#3240b891a78b0deae910dbeb86553e552a148860" - integrity sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg== - typescript-language-server@*: - version "0.10.1" - resolved "https://registry.yarnpkg.com/typescript-language-server/-/typescript-language-server-0.10.1.tgz#69232fcd860209f97f240a83532b306af960f6e1" - integrity sha512-Lk98jYbHthLOhldFziQhk0TubE7RvUtQaVW5un7hOR2uDVH78lQHf5RZsgtmlAECgZRxWXgTOJUZ+BWJ+v/a7A== - dependencies: - commander "^9.0.0" - fs-extra "^10.0.0" - p-debounce "^2.1.0" - pkg-up "^3.1.0" - semver "^7.3.5" - tempy "^1.0.1" - vscode-languageserver "^7.0.0" - vscode-languageserver-protocol "3.16.0" - vscode-languageserver-textdocument "1.0.4" - vscode-uri "^3.0.2" - which "^2.0.2" + version "4.0.0" + resolved "https://registry.yarnpkg.com/typescript-language-server/-/typescript-language-server-4.0.0.tgz#93c753f3caddbe312cc3c0b3c52f19410420a857" + integrity sha512-u6GLfWtHzOfGNpn0XuUYFg8Jv3oXWKzY6o5/Lt6LbWE6Ux965z2lP+vM0AN8Z2EobnlrDzzdcKusUx46j2eP3A== typescript@*: - version "4.7.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.2.tgz#1f9aa2ceb9af87cca227813b4310fff0b51593c4" - integrity sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A== - -unique-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" - integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== - dependencies: - crypto-random-string "^2.0.0" - -universalify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" - integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== - -vscode-jsonrpc@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz#108bdb09b4400705176b957ceca9e0880e9b6d4e" - integrity sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg== - -vscode-languageserver-protocol@3.16.0: - version "3.16.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz#34135b61a9091db972188a07d337406a3cdbe821" - integrity sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A== - dependencies: - vscode-jsonrpc "6.0.0" - vscode-languageserver-types "3.16.0" - -vscode-languageserver-textdocument@1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.4.tgz#3cd56dd14cec1d09e86c4bb04b09a246cb3df157" - integrity sha512-/xhqXP/2A2RSs+J8JNXpiiNVvvNM0oTosNVmQnunlKvq9o4mupHOBAnnzH0lwIPKazXKvAKsVp1kr+H/K4lgoQ== - -vscode-languageserver-types@3.16.0: - version "3.16.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz#ecf393fc121ec6974b2da3efb3155644c514e247" - integrity sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA== - -vscode-languageserver@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-7.0.0.tgz#49b068c87cfcca93a356969d20f5d9bdd501c6b0" - integrity sha512-60HTx5ID+fLRcgdHfmz0LDZAXYEV68fzwG0JWwEPBode9NuMYTIxuYXPg4ngO8i8+Ou0lM7y6GzaYWbiDL0drw== - dependencies: - vscode-languageserver-protocol "3.16.0" - -vscode-uri@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.3.tgz#a95c1ce2e6f41b7549f86279d19f47951e4f4d84" - integrity sha512-EcswR2S8bpR7fD0YPeS7r2xXExrScVMxg4MedACaWHEtx9ftCF/qHG1xGkolzTPcEmjTavCQgbVzHUIdTMzFGA== - -which@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + version "5.2.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" + integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== From 7e14d11036987aa5cc03cefc3894754c9d636b41 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Thu, 26 Oct 2023 21:23:31 -0400 Subject: [PATCH 013/117] feat(tools): add script to run benchmarks on straglum Make my life easier by automating a lot of the work of running LSP benchmarks. --- tools/run-benchmarks-straglum.sh | 98 ++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100755 tools/run-benchmarks-straglum.sh diff --git a/tools/run-benchmarks-straglum.sh b/tools/run-benchmarks-straglum.sh new file mode 100755 index 0000000000..99e007a237 --- /dev/null +++ b/tools/run-benchmarks-straglum.sh @@ -0,0 +1,98 @@ +#!/usr/bin/env bash + +# Copyright (C) 2020 Matthew "strager" Glazar +# See end of file for extended copyright information. + +# This script runs LSP benchmarks on strager's straglum laptop for the +# website: https://quick-lint-js.com/benchmarks/ + +set -e +set -u + +sudo cpupower frequency-set --governor performance + +. ~/tmp/Projects/nvm/nvm.sh +nvm install node +nvm use node +npm install -g yarn + +CXX=g++-10 CXXFLAGS=-fcoroutines cmake -S . -B build -G Ninja -DQUICK_LINT_JS_ENABLE_BENCHMARKS=1 -DCMAKE_BUILD_TYPE=Release +ninja -C build quick-lint-js-benchmark-lsp-servers + +cd benchmark/benchmark-lsp/ + +( + cd eslint/ + yarn + cd node_modules/vscode-eslint/ + npm ci && npm run compile:server +) + +( + cd flow/ + yarn +) + +( + cd typescript/ + yarn +) + +sudo apt-get update +sudo apt-get install --yes quick-lint-js + +( + cd biome/ + yarn +) + +( + cd ~/tmp/Projects/RSLint/ + cargo build --release +) + +PATH="${HOME}/tmp/Projects/RSLint/target/release/:${PATH}" +PATH="${HOME}/bin/:${PATH}" # For Deno. + +cool_down_cpu() { + sleep 10 +} + +cool_down_cpu +../../build/benchmark/benchmark-lsp/quick-lint-js-benchmark-lsp-servers \ + --iterations 10 \ + --samples 10 \ + --output-json ../../website/public/benchmarks/full-change-wait-express-router-js.json \ + full-change-wait/express-router.js + +cool_down_cpu +../../build/benchmark/benchmark-lsp/quick-lint-js-benchmark-lsp-servers \ + --iterations 10 \ + --samples 10 \ + --output-json ../../website/public/benchmarks/incremental-change-wait-express-router-js.json \ + incremental-change-wait/express-router.js + +cool_down_cpu +../../build/benchmark/benchmark-lsp/quick-lint-js-benchmark-lsp-servers \ + --iterations 10 \ + --samples 10 \ + --output-json ../../website/public/benchmarks/incremental-change-wait-react-quickly-ch10-jsx.json \ + incremental-change-wait/react-quickly-ch10.jsx + +# quick-lint-js finds bugs in JavaScript programs. +# Copyright (C) 2020 Matthew "strager" Glazar +# +# This file is part of quick-lint-js. +# +# quick-lint-js is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# quick-lint-js is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with quick-lint-js. If not, see . From a1a23dcacc5f98d1795eaf26acb273d456e3273c Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Thu, 26 Oct 2023 21:23:31 -0400 Subject: [PATCH 014/117] refactor(docs): improve wording for clarity --- docs/CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 321a8f3ef8..d999f352ff 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -21,7 +21,7 @@ Semantic Versioning. * `cmake --install` with `--component build-tools` does not install the build tools. (This is a regression introduced in quick-lint-js version 2.16.0.) - Patch: [Git commit + Fix: [Git commit 3923f0df76d24b73d57f15eec61ab190ea048093][cmake-install-component-build-tools-patch] ### Added @@ -99,7 +99,7 @@ Semantic Versioning. ### Known issues * `cmake --install` with `--component build-tools` does not install the build - tools. Patch: [Git commit + tools. Fix: [Git commit 3923f0df76d24b73d57f15eec61ab190ea048093][cmake-install-component-build-tools-patch] ### Added From fc348d38e24ec0fb3c4dd2f091ec78fa371e8875 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Thu, 26 Oct 2023 21:23:31 -0400 Subject: [PATCH 015/117] fix(docs): fix broken Markdown for link --- docs/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index d999f352ff..3d5cdb16d7 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1247,6 +1247,7 @@ Beta release. [E0349]: https://quick-lint-js.com/errors/E0349/ [E0356]: https://quick-lint-js.com/errors/E0356/ [E0357]: https://quick-lint-js.com/errors/E0357/ +[E0361]: https://quick-lint-js.com/errors/E0361/ [E0362]: https://quick-lint-js.com/errors/E0362/ [E0365]: https://quick-lint-js.com/errors/E0365/ [E0369]: https://quick-lint-js.com/errors/E0369/ From 13707f91550d36c745096ea14fc6788cb9edf1ce Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Thu, 26 Oct 2023 21:23:31 -0400 Subject: [PATCH 016/117] chore(docs): update links to Deno and TypeScript codebases Ensure our debounce comments are up to date. --- website/public/benchmarks/index.ejs.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/public/benchmarks/index.ejs.html b/website/public/benchmarks/index.ejs.html index 631aa98bd1..afd75fa51e 100644 --- a/website/public/benchmarks/index.ejs.html +++ b/website/public/benchmarks/index.ejs.html @@ -296,7 +296,7 @@

Deno

Deno's LSP server (and thus its Visual Studio Code extension) delays processing by 200 milliseconds. This means that Deno appears to be much slower than it actually is, but this artificial latency does affect the editing experience. @@ -306,12 +306,12 @@

TypeScript

TypeScript's LSP server (but not its Visual Studio Code extension) delays processing by 200 milliseconds + 50 milliseconds. This means that TypeScript appears to be much slower than it actually is, but this artificial latency does affect the editing From 4e5d9cbe34d603a078c54107e5534912c06acd1d Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Thu, 26 Oct 2023 18:19:59 -0700 Subject: [PATCH 017/117] feat(benchmark-lsp): enable JSX benchmarking for Biome --- benchmark/benchmark-lsp/benchmark-config.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/benchmark/benchmark-lsp/benchmark-config.cpp b/benchmark/benchmark-lsp/benchmark-config.cpp index f7d79f58e7..826e2645ce 100644 --- a/benchmark/benchmark-lsp/benchmark-config.cpp +++ b/benchmark/benchmark-lsp/benchmark-config.cpp @@ -308,6 +308,7 @@ Benchmark_Config Benchmark_Config::load() { .program_name = "Biome", .command = {"./run.sh"}, .cwd = "biome/", + .supports_jsx = true, }, Benchmark_Config_Server{ From 640b5e7d8a8999228cdc55c99a0cad33324871dc Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Thu, 26 Oct 2023 21:23:32 -0400 Subject: [PATCH 018/117] feat(website): update benchmark results Re-run benchmarks and publish results to the website. --- .../full-change-wait-express-router-js.json | 384 +++++++++++++++++- ...emental-change-wait-express-router-js.json | 376 ++++++++++++++++- ...al-change-wait-react-quickly-ch10-jsx.json | 344 +++++++++++++++- website/public/benchmarks/index.ejs.html | 13 +- 4 files changed, 1107 insertions(+), 10 deletions(-) diff --git a/website/public/benchmarks/full-change-wait-express-router-js.json b/website/public/benchmarks/full-change-wait-express-router-js.json index a4f5211d57..46a52ea73b 100644 --- a/website/public/benchmarks/full-change-wait-express-router-js.json +++ b/website/public/benchmarks/full-change-wait-express-router-js.json @@ -1 +1,383 @@ -{"data":[{"benchmarkName":"vscode-eslint-airbnb/full-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[1.204731072E-1,1.202739335E-1,1.349880686E-1,1.2477910889999999E-1,1.269307281E-1,1.277781037E-1,1.2470824350000001E-1,1.2796222399999999E-1,1.357691918E-1,1.380926224E-1]}},{"benchmarkName":"vscode-eslint-react/full-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[5.5719334499999995E-2,5.43059371E-2,5.5151234800000004E-2,5.7533948599999996E-2,5.45659632E-2,5.636322419999999E-2,5.58939014E-2,5.19708315E-2,5.33453724E-2,5.51664339E-2]}},{"benchmarkName":"vscode-eslint-typescript/full-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[6.4518358E-2,6.10288763E-2,6.004704600000001E-2,5.9444427300000005E-2,6.0562461899999996E-2,6.623526739999999E-2,6.19323237E-2,6.65845987E-2,6.30553363E-2,6.21956536E-2]}},{"benchmarkName":"vscode-eslint-vanilla/full-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[4.2429602500000003E-2,3.93138772E-2,4.1790716E-2,3.92597219E-2,4.0011950000000004E-2,3.94516333E-2,3.91750467E-2,3.940985E-2,4.12214636E-2,3.91508725E-2]}},{"benchmarkName":"vscode-eslint-vue/full-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[4.3658812899999996E-2,4.65603339E-2,4.7723816200000005E-2,4.47290692E-2,4.51950272E-2,5.28392937E-2,4.72624835E-2,4.64006391E-2,4.67050569E-2,4.76157583E-2]}},{"benchmarkName":"Deno/full-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[2.833673716E-1,2.839980195E-1,2.830082015E-1,2.809802473E-1,2.815241007E-1,2.818740726E-1,2.811916122E-1,2.825959686E-1,2.785872169E-1,2.8346163729999996E-1]}},{"benchmarkName":"Deno-nolint/full-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[2.789737338E-1,2.826592995E-1,2.7994670990000003E-1,2.788414027E-1,2.811700109E-1,2.811740498E-1,2.795701461E-1,2.80737729E-1,2.793055201E-1,2.80264741E-1]}},{"benchmarkName":"Flow/full-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[7.27020525E-2,7.19702656E-2,7.47173064E-2,7.55707237E-2,7.504175360000001E-2,7.91892015E-2,7.07086274E-2,7.547186780000001E-2,7.15823174E-2,7.09522426E-2]}},{"benchmarkName":"quick-lint-js/full-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[3.143285E-4,3.421767E-4,3.402009E-4,2.808582E-4,4.433696E-4,3.248777E-4,4.059735E-4,2.973761E-4,3.6059389999999996E-4,3.23434E-4]}},{"benchmarkName":"RSLint/full-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[2.32940533E-2,2.26410097E-2,2.3114657E-2,2.14383316E-2,2.27335717E-2,2.17158244E-2,2.18963024E-2,2.20055597E-2,2.10880636E-2,2.23511223E-2]}},{"benchmarkName":"Rome/full-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[3.9749208E-3,4.4257461E-3,5.0482739E-3,3.8602289999999997E-3,4.4946687E-3,4.0753098E-3,4.0458462E-3,4.5292536E-3,4.0129828E-3,4.8057247E-3]}},{"benchmarkName":"TypeScript/full-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[1.359073854E-1,1.590805193E-1,1.668749592E-1,1.887922543E-1,1.664493407E-1,1.602697153E-1,1.866151657E-1,1.582566345E-1,1.3445219749999998E-1,1.889624178E-1]}},{"benchmarkName":"TypeScript-JSX/full-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[1.65903497E-1,1.8863548089999999E-1,1.911658698E-1,2.1442333530000002E-1,1.897071663E-1,1.3365002720000002E-1,1.416890613E-1,1.725738046E-1,1.452330143E-1,1.59152979E-1]}}],"metadata":{"ESLint":{"@eslint/eslintrc":"1.3.0","@humanwhocodes/config-array":"0.9.5","@humanwhocodes/object-schema":"1.2.1","@nodelib/fs.scandir":"2.1.5","@nodelib/fs.stat":"2.0.5","@nodelib/fs.walk":"1.2.8","@types/json-schema":"7.0.11","@types/json5":"0.0.29","@typescript-eslint/eslint-plugin":"5.26.0","@typescript-eslint/parser":"5.26.0","@typescript-eslint/scope-manager":"5.26.0","@typescript-eslint/type-utils":"5.26.0","@typescript-eslint/types":"5.26.0","@typescript-eslint/typescript-estree":"5.26.0","@typescript-eslint/utils":"5.26.0","@typescript-eslint/visitor-keys":"5.26.0","acorn":"8.7.1","acorn-jsx":"5.3.2","ajv":"6.12.6","ansi-regex":"5.0.1","ansi-styles":"4.3.0","argparse":"2.0.1","array-includes":"3.1.5","array-union":"2.1.0","array.prototype.flat":"1.3.0","array.prototype.flatmap":"1.3.0","balanced-match":"1.0.2","boolbase":"1.0.0","brace-expansion":"1.1.11","braces":"3.0.2","call-bind":"1.0.2","callsites":"3.1.0","chalk":"4.1.2","color-convert":"2.0.1","color-name":"1.1.4","concat-map":"0.0.1","confusing-browser-globals":"1.0.11","cross-spawn":"7.0.3","cssesc":"3.0.0","debug":"4.3.4","deep-is":"0.1.4","define-properties":"1.1.4","dir-glob":"3.0.1","doctrine":"2.1.0","es-abstract":"1.20.1","es-shim-unscopables":"1.0.0","es-to-primitive":"1.2.1","escape-string-regexp":"4.0.0","eslint":"8.16.0","eslint-config-airbnb-base":"15.0.0","eslint-import-resolver-node":"0.3.6","eslint-module-utils":"2.7.3","eslint-plugin-import":"2.26.0","eslint-plugin-react":"7.30.0","eslint-plugin-vue":"9.0.1","eslint-scope":"7.1.1","eslint-utils":"3.0.0","eslint-visitor-keys":"3.3.0","espree":"9.3.2","esquery":"1.4.0","esrecurse":"4.3.0","estraverse":"5.3.0","esutils":"2.0.3","fast-deep-equal":"3.1.3","fast-glob":"3.2.11","fast-json-stable-stringify":"2.1.0","fast-levenshtein":"2.0.6","fastq":"1.13.0","file-entry-cache":"6.0.1","fill-range":"7.0.1","find-up":"2.1.0","flat-cache":"3.0.4","flatted":"3.2.5","fs.realpath":"1.0.0","function-bind":"1.1.1","function.prototype.name":"1.1.5","functional-red-black-tree":"1.0.1","functions-have-names":"1.2.3","get-intrinsic":"1.1.1","get-symbol-description":"1.0.0","glob":"7.2.3","glob-parent":"6.0.2","globals":"13.15.0","globby":"11.1.0","has":"1.0.3","has-bigints":"1.0.2","has-flag":"4.0.0","has-property-descriptors":"1.0.0","has-symbols":"1.0.3","has-tostringtag":"1.0.0","ignore":"5.2.0","import-fresh":"3.3.0","imurmurhash":"0.1.4","inflight":"1.0.6","inherits":"2.0.4","internal-slot":"1.0.3","is-bigint":"1.0.4","is-boolean-object":"1.1.2","is-callable":"1.2.4","is-core-module":"2.9.0","is-date-object":"1.0.5","is-extglob":"2.1.1","is-glob":"4.0.3","is-negative-zero":"2.0.2","is-number":"7.0.0","is-number-object":"1.0.7","is-regex":"1.1.4","is-shared-array-buffer":"1.0.2","is-string":"1.0.7","is-symbol":"1.0.4","is-weakref":"1.0.2","isexe":"2.0.0","js-tokens":"4.0.0","js-yaml":"4.1.0","json-schema-traverse":"0.4.1","json-stable-stringify-without-jsonify":"1.0.1","json5":"1.0.1","jsx-ast-utils":"3.3.0","levn":"0.4.1","locate-path":"2.0.0","lodash":"4.17.21","lodash.merge":"4.6.2","loose-envify":"1.4.0","lru-cache":"6.0.0","merge2":"1.4.1","micromatch":"4.0.5","minimatch":"3.1.2","minimist":"1.2.6","ms":"2.1.2","natural-compare":"1.4.0","node":"v18.2.0","nth-check":"2.1.1","object-assign":"4.1.1","object-inspect":"1.12.2","object-keys":"1.1.1","object.assign":"4.1.2","object.entries":"1.1.5","object.fromentries":"2.0.5","object.hasown":"1.1.1","object.values":"1.1.5","once":"1.4.0","optionator":"0.9.1","p-limit":"1.3.0","p-locate":"2.0.0","p-try":"1.0.0","parent-module":"1.0.1","path-exists":"3.0.0","path-is-absolute":"1.0.1","path-key":"3.1.1","path-parse":"1.0.7","path-type":"4.0.0","picomatch":"2.3.1","postcss-selector-parser":"6.0.10","prelude-ls":"1.2.1","prop-types":"15.8.1","punycode":"2.1.1","queue-microtask":"1.2.3","react-is":"16.13.1","regexp.prototype.flags":"1.4.3","regexpp":"3.2.0","resolve":"1.22.0","resolve-from":"4.0.0","reusify":"1.0.4","rimraf":"3.0.2","run-parallel":"1.2.0","semver":"7.3.7","shebang-command":"2.0.0","shebang-regex":"3.0.0","side-channel":"1.0.4","slash":"3.0.0","string.prototype.matchall":"4.0.7","string.prototype.trimend":"1.0.5","string.prototype.trimstart":"1.0.5","strip-ansi":"6.0.1","strip-bom":"3.0.0","strip-json-comments":"3.1.1","supports-color":"7.2.0","supports-preserve-symlinks-flag":"1.0.0","text-table":"0.2.0","to-regex-range":"5.0.1","tsconfig-paths":"3.14.1","tslib":"1.14.1","tsutils":"3.21.0","type-check":"0.4.0","type-fest":"0.20.2","typescript":"4.7.2","unbox-primitive":"1.0.2","uri-js":"4.4.1","util-deprecate":"1.0.2","v8-compile-cache":"2.3.0","vscode-eslint":"https://github.com/microsoft/vscode-eslint/archive/d3c7703cd11dc6752c96edf0f140d50156d72dd7.tar.gz","vue-eslint-parser":"9.0.2","which":"2.0.2","which-boxed-primitive":"1.0.2","word-wrap":"1.2.3","wrappy":"1.0.2","xml-name-validator":"4.0.0","yallist":"4.0.0"},"Deno":{"deno":"1.22.0","typescript":"4.6.2","v8":"10.0.139.17"},"Flow":{"flow-bin":"0.179.0"},"quick-lint-js":{"version":"2.5.0"},"Rome":{},"TypeScript":{"@nodelib/fs.scandir":"2.1.5","@nodelib/fs.stat":"2.0.5","@nodelib/fs.walk":"1.2.8","aggregate-error":"3.1.0","array-union":"2.1.0","balanced-match":"1.0.2","brace-expansion":"1.1.11","braces":"3.0.2","clean-stack":"2.2.0","commander":"9.2.0","concat-map":"0.0.1","crypto-random-string":"2.0.0","del":"6.1.1","dir-glob":"3.0.1","fast-glob":"3.2.11","fastq":"1.13.0","fill-range":"7.0.1","find-up":"3.0.0","fs-extra":"10.1.0","fs.realpath":"1.0.0","glob":"7.2.3","glob-parent":"5.1.2","globby":"11.1.0","graceful-fs":"4.2.10","ignore":"5.2.0","indent-string":"4.0.0","inflight":"1.0.6","inherits":"2.0.4","is-extglob":"2.1.1","is-glob":"4.0.3","is-number":"7.0.0","is-path-cwd":"2.2.0","is-path-inside":"3.0.3","is-stream":"2.0.1","isexe":"2.0.0","jsonfile":"6.1.0","locate-path":"3.0.0","lru-cache":"6.0.0","merge2":"1.4.1","micromatch":"4.0.5","minimatch":"3.1.2","node":"v18.2.0","once":"1.4.0","p-debounce":"2.1.0","p-limit":"2.3.0","p-locate":"3.0.0","p-map":"4.0.0","p-try":"2.2.0","path-exists":"3.0.0","path-is-absolute":"1.0.1","path-type":"4.0.0","picomatch":"2.3.1","pkg-up":"3.1.0","queue-microtask":"1.2.3","reusify":"1.0.4","rimraf":"3.0.2","run-parallel":"1.2.0","semver":"7.3.7","slash":"3.0.0","temp-dir":"2.0.0","tempy":"1.0.1","to-regex-range":"5.0.1","type-fest":"0.16.0","typescript":"4.7.2","typescript-language-server":"0.10.1","unique-string":"2.0.0","universalify":"2.0.0","vscode-jsonrpc":"6.0.0","vscode-languageserver":"7.0.0","vscode-languageserver-protocol":"3.16.0","vscode-languageserver-textdocument":"1.0.4","vscode-languageserver-types":"3.16.0","vscode-uri":"3.0.3","which":"2.0.2","wrappy":"1.0.2","yallist":"4.0.0"}}} \ No newline at end of file +{ + "data": [ + { + "benchmarkName": "vscode-eslint-airbnb/full-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.081235141900000002, 0.079754813999999993, 0.079091266600000001, 0.0817240152, 0.079301651700000003, 0.081251066400000002, 0.080536069299999999, 0.079472934100000003, 0.0807643943, 0.079288524100000007] + } + }, + { + "benchmarkName": "vscode-eslint-react/full-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.038716876099999999, 0.038568138799999999, 0.037869746199999998, 0.039114095599999996, 0.038862341000000002, 0.037502515100000001, 0.0386350648, 0.0379395524, 0.038644702699999998, 0.038633588000000003] + } + }, + { + "benchmarkName": "vscode-eslint-typescript/full-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.050848559000000002, 0.050023333500000003, 0.051320273600000001, 0.050697789800000004, 0.051351601999999996, 0.050541708900000003, 0.048952186100000003, 0.048873840000000002, 0.053814236599999996, 0.0533455335] + } + }, + { + "benchmarkName": "vscode-eslint-vanilla/full-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.030186629399999998, 0.0305953419, 0.029708535299999998, 0.030383590999999998, 0.0302013808, 0.0292650715, 0.031107308900000002, 0.029937414200000002, 0.029720228500000001, 0.0298693282] + } + }, + { + "benchmarkName": "vscode-eslint-vue/full-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.033457495900000002, 0.0340038602, 0.033954781699999999, 0.034117368699999998, 0.033525287199999997, 0.033785621299999999, 0.033035438799999997, 0.032719964800000001, 0.032872356499999998, 0.032717810999999999] + } + }, + { + "benchmarkName": "Deno/full-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.258849041, 0.25915074500000002, 0.2583835712, 0.25990978600000003, 0.25885255169999999, 0.2600132657, 0.25981336669999999, 0.25892458939999996, 0.25880275209999998, 0.25760798699999998] + } + }, + { + "benchmarkName": "Deno-nolint/full-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.25961686089999997, 0.25921899320000003, 0.25962364980000002, 0.25918260449999997, 0.258038033, 0.25839416850000002, 0.25844451460000001, 0.25932008670000001, 0.25886115639999996, 0.25921981440000003] + } + }, + { + "benchmarkName": "Flow/full-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.033092246199999995, 0.033927880100000002, 0.033226016800000001, 0.033749545300000003, 0.034055127599999999, 0.033129185999999998, 0.033024339899999998, 0.032798102699999998, 0.0343630095, 0.033100315899999996] + } + }, + { + "benchmarkName": "quick-lint-js/full-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.00037970629999999999, 0.00033722590000000001, 0.00028636349999999999, 0.0002934352, 0.00032444489999999999, 0.00032534760000000002, 0.00029748489999999997, 0.00028572799999999996, 0.00028850070000000004, 0.00033568790000000002] + } + }, + { + "benchmarkName": "RSLint/full-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.020154790200000001, 0.020135320500000001, 0.0202114592, 0.020122145000000001, 0.0202031269, 0.020143493300000002, 0.020140075599999998, 0.020128758099999998, 0.020231819000000002, 0.0202118409] + } + }, + { + "benchmarkName": "Biome/full-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.14527574869999998, 0.1458446642, 0.1465179811, 0.1444381133, 0.1463421795, 0.14532735349999998, 0.1486199004, 0.14504906000000001, 0.1438784642, 0.1449687949] + } + }, + { + "benchmarkName": "TypeScript/full-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.22495201269999998, 0.30968759559999998, 0.25570656270000003, 0.28492991109999999, 0.28523362720000001, 0.25610876529999999, 0.27846333479999996, 0.28505085220000004, 0.28541998020000003, 0.2550881203] + } + }, + { + "benchmarkName": "TypeScript-JSX/full-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.25584137610000002, 0.25584581950000002, 0.24963368120000001, 0.25604167769999997, 0.25481280960000002, 0.25498456400000002, 0.224560965, 0.28537806389999998, 0.25622361500000002, 0.28469608059999996] + } + } + ], + "metadata": { + "Biome": { + "@biomejs/biome": "1.3.1", + "@biomejs/cli-darwin-arm64": "1.3.1", + "@biomejs/cli-darwin-x64": "1.3.1", + "@biomejs/cli-linux-arm64": "1.3.1", + "@biomejs/cli-linux-x64": "1.3.1", + "@biomejs/cli-win32-arm64": "1.3.1", + "@biomejs/cli-win32-x64": "1.3.1" + } +, + "Deno": { + "deno": "1.37.2", + "typescript": "5.2.2", + "v8": "11.8.172.13" + } +, + "ESLint": { + "@aashutoshrathi/word-wrap": "1.2.6", + "@eslint-community/eslint-utils": "4.4.0", + "@eslint-community/regexpp": "4.10.0", + "@eslint/eslintrc": "2.1.2", + "@eslint/js": "8.52.0", + "@humanwhocodes/config-array": "0.11.13", + "@humanwhocodes/module-importer": "1.0.1", + "@humanwhocodes/object-schema": "2.0.1", + "@nodelib/fs.scandir": "2.1.5", + "@nodelib/fs.stat": "2.0.5", + "@nodelib/fs.walk": "1.2.8", + "@types/json-schema": "7.0.14", + "@types/json5": "0.0.29", + "@types/semver": "7.5.4", + "@typescript-eslint/eslint-plugin": "6.9.0", + "@typescript-eslint/parser": "6.9.0", + "@typescript-eslint/scope-manager": "6.9.0", + "@typescript-eslint/type-utils": "6.9.0", + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/typescript-estree": "6.9.0", + "@typescript-eslint/utils": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0", + "@ungap/structured-clone": "1.2.0", + "acorn": "8.11.1", + "acorn-jsx": "5.3.2", + "ajv": "6.12.6", + "ansi-regex": "5.0.1", + "ansi-styles": "4.3.0", + "argparse": "2.0.1", + "array-buffer-byte-length": "1.0.0", + "array-includes": "3.1.7", + "array-union": "2.1.0", + "array.prototype.findlastindex": "1.2.3", + "array.prototype.flat": "1.3.2", + "array.prototype.flatmap": "1.3.2", + "array.prototype.tosorted": "1.1.2", + "arraybuffer.prototype.slice": "1.0.2", + "asynciterator.prototype": "1.0.0", + "available-typed-arrays": "1.0.5", + "balanced-match": "1.0.2", + "boolbase": "1.0.0", + "brace-expansion": "1.1.11", + "braces": "3.0.2", + "call-bind": "1.0.5", + "callsites": "3.1.0", + "chalk": "4.1.2", + "color-convert": "2.0.1", + "color-name": "1.1.4", + "concat-map": "0.0.1", + "confusing-browser-globals": "1.0.11", + "cross-spawn": "7.0.3", + "cssesc": "3.0.0", + "debug": "4.3.4", + "deep-is": "0.1.4", + "define-data-property": "1.1.1", + "define-properties": "1.2.1", + "dir-glob": "3.0.1", + "doctrine": "2.1.0", + "es-abstract": "1.22.3", + "es-iterator-helpers": "1.0.15", + "es-set-tostringtag": "2.0.2", + "es-shim-unscopables": "1.0.2", + "es-to-primitive": "1.2.1", + "escape-string-regexp": "4.0.0", + "eslint": "8.52.0", + "eslint-config-airbnb-base": "15.0.0", + "eslint-import-resolver-node": "0.3.9", + "eslint-module-utils": "2.8.0", + "eslint-plugin-import": "2.29.0", + "eslint-plugin-react": "7.33.2", + "eslint-plugin-vue": "9.18.0", + "eslint-scope": "7.2.2", + "eslint-visitor-keys": "3.4.3", + "espree": "9.6.1", + "esquery": "1.5.0", + "esrecurse": "4.3.0", + "estraverse": "5.3.0", + "esutils": "2.0.3", + "fast-deep-equal": "3.1.3", + "fast-glob": "3.3.1", + "fast-json-stable-stringify": "2.1.0", + "fast-levenshtein": "2.0.6", + "fastq": "1.15.0", + "file-entry-cache": "6.0.1", + "fill-range": "7.0.1", + "find-up": "5.0.0", + "flat-cache": "3.1.1", + "flatted": "3.2.9", + "for-each": "0.3.3", + "fs.realpath": "1.0.0", + "function-bind": "1.1.2", + "function.prototype.name": "1.1.6", + "functions-have-names": "1.2.3", + "get-intrinsic": "1.2.2", + "get-symbol-description": "1.0.0", + "glob": "7.2.3", + "glob-parent": "6.0.2", + "globals": "13.23.0", + "globalthis": "1.0.3", + "globby": "11.1.0", + "gopd": "1.0.1", + "graphemer": "1.4.0", + "has-bigints": "1.0.2", + "has-flag": "4.0.0", + "has-property-descriptors": "1.0.1", + "has-proto": "1.0.1", + "has-symbols": "1.0.3", + "has-tostringtag": "1.0.0", + "hasown": "2.0.0", + "ignore": "5.2.4", + "import-fresh": "3.3.0", + "imurmurhash": "0.1.4", + "inflight": "1.0.6", + "inherits": "2.0.4", + "internal-slot": "1.0.6", + "is-array-buffer": "3.0.2", + "is-async-function": "2.0.0", + "is-bigint": "1.0.4", + "is-boolean-object": "1.1.2", + "is-callable": "1.2.7", + "is-core-module": "2.13.1", + "is-date-object": "1.0.5", + "is-extglob": "2.1.1", + "is-finalizationregistry": "1.0.2", + "is-generator-function": "1.0.10", + "is-glob": "4.0.3", + "is-map": "2.0.2", + "is-negative-zero": "2.0.2", + "is-number": "7.0.0", + "is-number-object": "1.0.7", + "is-path-inside": "3.0.3", + "is-regex": "1.1.4", + "is-set": "2.0.2", + "is-shared-array-buffer": "1.0.2", + "is-string": "1.0.7", + "is-symbol": "1.0.4", + "is-typed-array": "1.1.12", + "is-weakmap": "2.0.1", + "is-weakref": "1.0.2", + "is-weakset": "2.0.2", + "isarray": "2.0.5", + "isexe": "2.0.0", + "iterator.prototype": "1.1.2", + "js-tokens": "4.0.0", + "js-yaml": "4.1.0", + "json-buffer": "3.0.1", + "json-schema-traverse": "0.4.1", + "json-stable-stringify-without-jsonify": "1.0.1", + "json5": "1.0.2", + "jsx-ast-utils": "3.3.5", + "keyv": "4.5.4", + "levn": "0.4.1", + "locate-path": "6.0.0", + "lodash": "4.17.21", + "lodash.merge": "4.6.2", + "loose-envify": "1.4.0", + "lru-cache": "6.0.0", + "merge2": "1.4.1", + "micromatch": "4.0.5", + "minimatch": "3.1.2", + "minimist": "1.2.8", + "ms": "2.1.2", + "natural-compare": "1.4.0", + "node": "v21.1.0", + "nth-check": "2.1.1", + "object-assign": "4.1.1", + "object-inspect": "1.13.1", + "object-keys": "1.1.1", + "object.assign": "4.1.4", + "object.entries": "1.1.7", + "object.fromentries": "2.0.7", + "object.groupby": "1.0.1", + "object.hasown": "1.1.3", + "object.values": "1.1.7", + "once": "1.4.0", + "optionator": "0.9.3", + "p-limit": "3.1.0", + "p-locate": "5.0.0", + "parent-module": "1.0.1", + "path-exists": "4.0.0", + "path-is-absolute": "1.0.1", + "path-key": "3.1.1", + "path-parse": "1.0.7", + "path-type": "4.0.0", + "picomatch": "2.3.1", + "postcss-selector-parser": "6.0.13", + "prelude-ls": "1.2.1", + "prop-types": "15.8.1", + "punycode": "2.3.0", + "queue-microtask": "1.2.3", + "react-is": "16.13.1", + "reflect.getprototypeof": "1.0.4", + "regexp.prototype.flags": "1.5.1", + "resolve": "2.0.0-next.5", + "resolve-from": "4.0.0", + "reusify": "1.0.4", + "rimraf": "3.0.2", + "run-parallel": "1.2.0", + "safe-array-concat": "1.0.1", + "safe-regex-test": "1.0.0", + "semver": "7.5.4", + "set-function-length": "1.1.1", + "set-function-name": "2.0.1", + "shebang-command": "2.0.0", + "shebang-regex": "3.0.0", + "side-channel": "1.0.4", + "slash": "3.0.0", + "string.prototype.matchall": "4.0.10", + "string.prototype.trim": "1.2.8", + "string.prototype.trimend": "1.0.7", + "string.prototype.trimstart": "1.0.7", + "strip-ansi": "6.0.1", + "strip-bom": "3.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "7.2.0", + "supports-preserve-symlinks-flag": "1.0.0", + "text-table": "0.2.0", + "to-regex-range": "5.0.1", + "ts-api-utils": "1.0.3", + "tsconfig-paths": "3.14.2", + "type-check": "0.4.0", + "type-fest": "0.20.2", + "typed-array-buffer": "1.0.0", + "typed-array-byte-length": "1.0.0", + "typed-array-byte-offset": "1.0.0", + "typed-array-length": "1.0.4", + "typescript": "5.2.2", + "unbox-primitive": "1.0.2", + "uri-js": "4.4.1", + "util-deprecate": "1.0.2", + "vscode-eslint": "https://github.com/microsoft/vscode-eslint/archive/d3c7703cd11dc6752c96edf0f140d50156d72dd7.tar.gz", + "vue-eslint-parser": "9.3.2", + "which": "2.0.2", + "which-boxed-primitive": "1.0.2", + "which-builtin-type": "1.1.3", + "which-collection": "1.0.1", + "which-typed-array": "1.1.13", + "wrappy": "1.0.2", + "xml-name-validator": "4.0.0", + "yallist": "4.0.0", + "yocto-queue": "0.1.0" + } +, + "Flow": { + "flow-bin": "0.219.5" + } +, + "TypeScript": { + "node": "v21.1.0", + "typescript": "5.2.2", + "typescript-language-server": "4.0.0" + } +, + "quick-lint-js": { + "version": "2.17.0" + } + } +} diff --git a/website/public/benchmarks/incremental-change-wait-express-router-js.json b/website/public/benchmarks/incremental-change-wait-express-router-js.json index 59c34968fd..3e6a769470 100644 --- a/website/public/benchmarks/incremental-change-wait-express-router-js.json +++ b/website/public/benchmarks/incremental-change-wait-express-router-js.json @@ -1 +1,375 @@ -{"data":[{"benchmarkName":"vscode-eslint-airbnb/incremental-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[1.344999128E-1,1.326614628E-1,1.337210711E-1,1.342604922E-1,1.334579033E-1,1.282596043E-1,1.2830227030000002E-1,1.309632053E-1,1.359143658E-1,1.431013126E-1]}},{"benchmarkName":"vscode-eslint-react/incremental-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[5.37693451E-2,5.7199537099999996E-2,5.6800092700000006E-2,5.74649268E-2,5.62821621E-2,5.80837372E-2,5.91867233E-2,5.66719812E-2,5.70491592E-2,5.41997459E-2]}},{"benchmarkName":"vscode-eslint-typescript/incremental-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[6.368974200000001E-2,6.1266829099999996E-2,6.1267111900000004E-2,6.66129488E-2,6.03637526E-2,6.639914599999999E-2,6.24053179E-2,5.9106789199999996E-2,6.4239261E-2,6.63280312E-2]}},{"benchmarkName":"vscode-eslint-vanilla/incremental-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[4.10350212E-2,3.91273267E-2,3.95438364E-2,4.00371217E-2,4.01310157E-2,4.0343777600000005E-2,4.04604203E-2,4.07270006E-2,4.04734504E-2,3.97273708E-2]}},{"benchmarkName":"vscode-eslint-vue/incremental-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[4.57344276E-2,4.72918958E-2,4.69841099E-2,4.54756937E-2,4.49361224E-2,4.5110517E-2,4.68601836E-2,5.08305076E-2,5.31979999E-2,5.2629302700000005E-2]}},{"benchmarkName":"Deno/incremental-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[2.932458934E-1,2.792692726E-1,2.8183424279999997E-1,2.810318768E-1,2.79527112E-1,2.822420861E-1,2.81224682E-1,2.807578082E-1,2.8026135750000003E-1,2.816514603E-1]}},{"benchmarkName":"Deno-nolint/incremental-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[2.792158508E-1,2.773728527E-1,2.70704179E-1,2.707497022E-1,2.716429339E-1,2.708732883E-1,2.704817141E-1,2.7007121079999996E-1,2.6971440950000003E-1,2.704322427E-1]}},{"benchmarkName":"Flow/incremental-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[6.2005756599999996E-2,6.1145493100000003E-2,6.17963771E-2,6.15275877E-2,6.20716087E-2,6.15448466E-2,6.145445980000001E-2,6.11459984E-2,6.1033873599999997E-2,6.112229030000001E-2]}},{"benchmarkName":"quick-lint-js/incremental-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[2.549089E-4,2.4442E-4,2.666053E-4,2.6007199999999997E-4,2.377354E-4,2.6060609999999996E-4,2.358145E-4,2.6337539999999997E-4,2.370017E-4,2.514844E-4]}},{"benchmarkName":"TypeScript/incremental-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[2.0411335849999998E-1,2.0518196400000002E-1,1.761251092E-1,2.0420380800000001E-1,1.759377205E-1,2.058455171E-1,2.048389608E-1,2.04918959E-1,1.983177582E-1,1.752554478E-1]}},{"benchmarkName":"TypeScript-JSX/incremental-change-wait/express-router.js","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[2.02517928E-1,2.577366445E-1,2.0480038450000002E-1,2.2898797050000003E-1,2.282714791E-1,2.04858806E-1,2.035171117E-1,2.043989482E-1,2.040208129E-1,2.283527941E-1]}}],"metadata":{"ESLint":{"@eslint/eslintrc":"1.3.0","@humanwhocodes/config-array":"0.9.5","@humanwhocodes/object-schema":"1.2.1","@nodelib/fs.scandir":"2.1.5","@nodelib/fs.stat":"2.0.5","@nodelib/fs.walk":"1.2.8","@types/json-schema":"7.0.11","@types/json5":"0.0.29","@typescript-eslint/eslint-plugin":"5.26.0","@typescript-eslint/parser":"5.26.0","@typescript-eslint/scope-manager":"5.26.0","@typescript-eslint/type-utils":"5.26.0","@typescript-eslint/types":"5.26.0","@typescript-eslint/typescript-estree":"5.26.0","@typescript-eslint/utils":"5.26.0","@typescript-eslint/visitor-keys":"5.26.0","acorn":"8.7.1","acorn-jsx":"5.3.2","ajv":"6.12.6","ansi-regex":"5.0.1","ansi-styles":"4.3.0","argparse":"2.0.1","array-includes":"3.1.5","array-union":"2.1.0","array.prototype.flat":"1.3.0","array.prototype.flatmap":"1.3.0","balanced-match":"1.0.2","boolbase":"1.0.0","brace-expansion":"1.1.11","braces":"3.0.2","call-bind":"1.0.2","callsites":"3.1.0","chalk":"4.1.2","color-convert":"2.0.1","color-name":"1.1.4","concat-map":"0.0.1","confusing-browser-globals":"1.0.11","cross-spawn":"7.0.3","cssesc":"3.0.0","debug":"4.3.4","deep-is":"0.1.4","define-properties":"1.1.4","dir-glob":"3.0.1","doctrine":"2.1.0","es-abstract":"1.20.1","es-shim-unscopables":"1.0.0","es-to-primitive":"1.2.1","escape-string-regexp":"4.0.0","eslint":"8.16.0","eslint-config-airbnb-base":"15.0.0","eslint-import-resolver-node":"0.3.6","eslint-module-utils":"2.7.3","eslint-plugin-import":"2.26.0","eslint-plugin-react":"7.30.0","eslint-plugin-vue":"9.0.1","eslint-scope":"7.1.1","eslint-utils":"3.0.0","eslint-visitor-keys":"3.3.0","espree":"9.3.2","esquery":"1.4.0","esrecurse":"4.3.0","estraverse":"5.3.0","esutils":"2.0.3","fast-deep-equal":"3.1.3","fast-glob":"3.2.11","fast-json-stable-stringify":"2.1.0","fast-levenshtein":"2.0.6","fastq":"1.13.0","file-entry-cache":"6.0.1","fill-range":"7.0.1","find-up":"2.1.0","flat-cache":"3.0.4","flatted":"3.2.5","fs.realpath":"1.0.0","function-bind":"1.1.1","function.prototype.name":"1.1.5","functional-red-black-tree":"1.0.1","functions-have-names":"1.2.3","get-intrinsic":"1.1.1","get-symbol-description":"1.0.0","glob":"7.2.3","glob-parent":"6.0.2","globals":"13.15.0","globby":"11.1.0","has":"1.0.3","has-bigints":"1.0.2","has-flag":"4.0.0","has-property-descriptors":"1.0.0","has-symbols":"1.0.3","has-tostringtag":"1.0.0","ignore":"5.2.0","import-fresh":"3.3.0","imurmurhash":"0.1.4","inflight":"1.0.6","inherits":"2.0.4","internal-slot":"1.0.3","is-bigint":"1.0.4","is-boolean-object":"1.1.2","is-callable":"1.2.4","is-core-module":"2.9.0","is-date-object":"1.0.5","is-extglob":"2.1.1","is-glob":"4.0.3","is-negative-zero":"2.0.2","is-number":"7.0.0","is-number-object":"1.0.7","is-regex":"1.1.4","is-shared-array-buffer":"1.0.2","is-string":"1.0.7","is-symbol":"1.0.4","is-weakref":"1.0.2","isexe":"2.0.0","js-tokens":"4.0.0","js-yaml":"4.1.0","json-schema-traverse":"0.4.1","json-stable-stringify-without-jsonify":"1.0.1","json5":"1.0.1","jsx-ast-utils":"3.3.0","levn":"0.4.1","locate-path":"2.0.0","lodash":"4.17.21","lodash.merge":"4.6.2","loose-envify":"1.4.0","lru-cache":"6.0.0","merge2":"1.4.1","micromatch":"4.0.5","minimatch":"3.1.2","minimist":"1.2.6","ms":"2.1.2","natural-compare":"1.4.0","node":"v18.2.0","nth-check":"2.1.1","object-assign":"4.1.1","object-inspect":"1.12.2","object-keys":"1.1.1","object.assign":"4.1.2","object.entries":"1.1.5","object.fromentries":"2.0.5","object.hasown":"1.1.1","object.values":"1.1.5","once":"1.4.0","optionator":"0.9.1","p-limit":"1.3.0","p-locate":"2.0.0","p-try":"1.0.0","parent-module":"1.0.1","path-exists":"3.0.0","path-is-absolute":"1.0.1","path-key":"3.1.1","path-parse":"1.0.7","path-type":"4.0.0","picomatch":"2.3.1","postcss-selector-parser":"6.0.10","prelude-ls":"1.2.1","prop-types":"15.8.1","punycode":"2.1.1","queue-microtask":"1.2.3","react-is":"16.13.1","regexp.prototype.flags":"1.4.3","regexpp":"3.2.0","resolve":"1.22.0","resolve-from":"4.0.0","reusify":"1.0.4","rimraf":"3.0.2","run-parallel":"1.2.0","semver":"7.3.7","shebang-command":"2.0.0","shebang-regex":"3.0.0","side-channel":"1.0.4","slash":"3.0.0","string.prototype.matchall":"4.0.7","string.prototype.trimend":"1.0.5","string.prototype.trimstart":"1.0.5","strip-ansi":"6.0.1","strip-bom":"3.0.0","strip-json-comments":"3.1.1","supports-color":"7.2.0","supports-preserve-symlinks-flag":"1.0.0","text-table":"0.2.0","to-regex-range":"5.0.1","tsconfig-paths":"3.14.1","tslib":"1.14.1","tsutils":"3.21.0","type-check":"0.4.0","type-fest":"0.20.2","typescript":"4.7.2","unbox-primitive":"1.0.2","uri-js":"4.4.1","util-deprecate":"1.0.2","v8-compile-cache":"2.3.0","vscode-eslint":"https://github.com/microsoft/vscode-eslint/archive/d3c7703cd11dc6752c96edf0f140d50156d72dd7.tar.gz","vue-eslint-parser":"9.0.2","which":"2.0.2","which-boxed-primitive":"1.0.2","word-wrap":"1.2.3","wrappy":"1.0.2","xml-name-validator":"4.0.0","yallist":"4.0.0"},"Deno":{"deno":"1.22.0","typescript":"4.6.2","v8":"10.0.139.17"},"Flow":{"flow-bin":"0.179.0"},"quick-lint-js":{"version":"2.5.0"},"TypeScript":{"@nodelib/fs.scandir":"2.1.5","@nodelib/fs.stat":"2.0.5","@nodelib/fs.walk":"1.2.8","aggregate-error":"3.1.0","array-union":"2.1.0","balanced-match":"1.0.2","brace-expansion":"1.1.11","braces":"3.0.2","clean-stack":"2.2.0","commander":"9.2.0","concat-map":"0.0.1","crypto-random-string":"2.0.0","del":"6.1.1","dir-glob":"3.0.1","fast-glob":"3.2.11","fastq":"1.13.0","fill-range":"7.0.1","find-up":"3.0.0","fs-extra":"10.1.0","fs.realpath":"1.0.0","glob":"7.2.3","glob-parent":"5.1.2","globby":"11.1.0","graceful-fs":"4.2.10","ignore":"5.2.0","indent-string":"4.0.0","inflight":"1.0.6","inherits":"2.0.4","is-extglob":"2.1.1","is-glob":"4.0.3","is-number":"7.0.0","is-path-cwd":"2.2.0","is-path-inside":"3.0.3","is-stream":"2.0.1","isexe":"2.0.0","jsonfile":"6.1.0","locate-path":"3.0.0","lru-cache":"6.0.0","merge2":"1.4.1","micromatch":"4.0.5","minimatch":"3.1.2","node":"v18.2.0","once":"1.4.0","p-debounce":"2.1.0","p-limit":"2.3.0","p-locate":"3.0.0","p-map":"4.0.0","p-try":"2.2.0","path-exists":"3.0.0","path-is-absolute":"1.0.1","path-type":"4.0.0","picomatch":"2.3.1","pkg-up":"3.1.0","queue-microtask":"1.2.3","reusify":"1.0.4","rimraf":"3.0.2","run-parallel":"1.2.0","semver":"7.3.7","slash":"3.0.0","temp-dir":"2.0.0","tempy":"1.0.1","to-regex-range":"5.0.1","type-fest":"0.16.0","typescript":"4.7.2","typescript-language-server":"0.10.1","unique-string":"2.0.0","universalify":"2.0.0","vscode-jsonrpc":"6.0.0","vscode-languageserver":"7.0.0","vscode-languageserver-protocol":"3.16.0","vscode-languageserver-textdocument":"1.0.4","vscode-languageserver-types":"3.16.0","vscode-uri":"3.0.3","which":"2.0.2","wrappy":"1.0.2","yallist":"4.0.0"}}} \ No newline at end of file +{ + "data": [ + { + "benchmarkName": "vscode-eslint-airbnb/incremental-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.080007399600000001, 0.080841913200000004, 0.079629582300000001, 0.080495002999999996, 0.079773361000000001, 0.079380821899999995, 0.080225165000000001, 0.080441927100000005, 0.079646187800000004, 0.079113543699999997] + } + }, + { + "benchmarkName": "vscode-eslint-react/incremental-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.038691865499999999, 0.038655744300000003, 0.038449397199999999, 0.038737264300000004, 0.038356977599999995, 0.039391519299999997, 0.0381255104, 0.038504698999999996, 0.038540657900000004, 0.039093378400000003] + } + }, + { + "benchmarkName": "vscode-eslint-typescript/incremental-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.051744906599999994, 0.052234176, 0.050959122199999998, 0.053339161000000003, 0.053948090400000002, 0.054553362000000008, 0.055780807600000003, 0.050758407699999994, 0.053980444299999999, 0.053112331599999993] + } + }, + { + "benchmarkName": "vscode-eslint-vanilla/incremental-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.030170591300000001, 0.030023424399999998, 0.031630001599999999, 0.029919527600000002, 0.030310692500000003, 0.031378826300000003, 0.031199882899999996, 0.031292829100000003, 0.031435956899999999, 0.029312135900000001] + } + }, + { + "benchmarkName": "vscode-eslint-vue/incremental-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.035196708799999997, 0.034268154199999998, 0.033500185199999997, 0.033736164999999999, 0.033552698399999997, 0.0335159207, 0.034037945899999998, 0.033990329100000001, 0.033238771399999999, 0.033629954199999999] + } + }, + { + "benchmarkName": "Deno/incremental-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.25941814660000001, 0.25980429760000001, 0.25949527159999997, 0.25857653869999997, 0.25880831269999999, 0.25913468370000003, 0.25958821659999998, 0.25895961249999999, 0.25962544669999998, 0.25917545679999998] + } + }, + { + "benchmarkName": "Deno-nolint/incremental-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.2587464223, 0.25808179819999999, 0.25850494699999998, 0.25989122779999996, 0.25853128149999999, 0.25816698189999998, 0.25898231169999997, 0.2589742236, 0.2587340085, 0.2586971132] + } + }, + { + "benchmarkName": "Flow/incremental-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.068198022400000002, 0.069117900799999993, 0.067759694999999995, 0.068102210799999993, 0.068660672800000003, 0.067855485000000007, 0.068442583500000001, 0.067611306999999995, 0.067902525300000002, 0.06800584979999999] + } + }, + { + "benchmarkName": "quick-lint-js/incremental-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.00023649919999999997, 0.0002523688, 0.00024945490000000001, 0.00028746290000000003, 0.00025924630000000003, 0.00026132740000000003, 0.00025472679999999999, 0.00028593830000000001, 0.00025177620000000001, 0.0002439424] + } + }, + { + "benchmarkName": "Biome/incremental-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.14795365830000001, 0.14562194319999999, 0.14712110949999999, 0.1455002474, 0.14623844079999998, 0.14348266000000001, 0.14418519329999999, 0.1454520839, 0.14756245060000001, 0.14385641830000001] + } + }, + { + "benchmarkName": "TypeScript/incremental-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.27768067159999998, 0.27730327980000002, 0.27739209780000001, 0.27724256530000002, 0.2770002023, 0.27781415919999997, 0.27761450339999999, 0.2485616259, 0.27812771340000003, 0.27779114800000004] + } + }, + { + "benchmarkName": "TypeScript-JSX/incremental-change-wait/express-router.js", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.24791289230000002, 0.27751808320000004, 0.27802154820000002, 0.27755427160000001, 0.2780543318, 0.27675317040000003, 0.27776203269999999, 0.27712559390000002, 0.24895709739999999, 0.27827021439999999] + } + } + ], + "metadata": { + "Biome": { + "@biomejs/biome": "1.3.1", + "@biomejs/cli-darwin-arm64": "1.3.1", + "@biomejs/cli-darwin-x64": "1.3.1", + "@biomejs/cli-linux-arm64": "1.3.1", + "@biomejs/cli-linux-x64": "1.3.1", + "@biomejs/cli-win32-arm64": "1.3.1", + "@biomejs/cli-win32-x64": "1.3.1" + } +, + "Deno": { + "deno": "1.37.2", + "typescript": "5.2.2", + "v8": "11.8.172.13" + } +, + "ESLint": { + "@aashutoshrathi/word-wrap": "1.2.6", + "@eslint-community/eslint-utils": "4.4.0", + "@eslint-community/regexpp": "4.10.0", + "@eslint/eslintrc": "2.1.2", + "@eslint/js": "8.52.0", + "@humanwhocodes/config-array": "0.11.13", + "@humanwhocodes/module-importer": "1.0.1", + "@humanwhocodes/object-schema": "2.0.1", + "@nodelib/fs.scandir": "2.1.5", + "@nodelib/fs.stat": "2.0.5", + "@nodelib/fs.walk": "1.2.8", + "@types/json-schema": "7.0.14", + "@types/json5": "0.0.29", + "@types/semver": "7.5.4", + "@typescript-eslint/eslint-plugin": "6.9.0", + "@typescript-eslint/parser": "6.9.0", + "@typescript-eslint/scope-manager": "6.9.0", + "@typescript-eslint/type-utils": "6.9.0", + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/typescript-estree": "6.9.0", + "@typescript-eslint/utils": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0", + "@ungap/structured-clone": "1.2.0", + "acorn": "8.11.1", + "acorn-jsx": "5.3.2", + "ajv": "6.12.6", + "ansi-regex": "5.0.1", + "ansi-styles": "4.3.0", + "argparse": "2.0.1", + "array-buffer-byte-length": "1.0.0", + "array-includes": "3.1.7", + "array-union": "2.1.0", + "array.prototype.findlastindex": "1.2.3", + "array.prototype.flat": "1.3.2", + "array.prototype.flatmap": "1.3.2", + "array.prototype.tosorted": "1.1.2", + "arraybuffer.prototype.slice": "1.0.2", + "asynciterator.prototype": "1.0.0", + "available-typed-arrays": "1.0.5", + "balanced-match": "1.0.2", + "boolbase": "1.0.0", + "brace-expansion": "1.1.11", + "braces": "3.0.2", + "call-bind": "1.0.5", + "callsites": "3.1.0", + "chalk": "4.1.2", + "color-convert": "2.0.1", + "color-name": "1.1.4", + "concat-map": "0.0.1", + "confusing-browser-globals": "1.0.11", + "cross-spawn": "7.0.3", + "cssesc": "3.0.0", + "debug": "4.3.4", + "deep-is": "0.1.4", + "define-data-property": "1.1.1", + "define-properties": "1.2.1", + "dir-glob": "3.0.1", + "doctrine": "2.1.0", + "es-abstract": "1.22.3", + "es-iterator-helpers": "1.0.15", + "es-set-tostringtag": "2.0.2", + "es-shim-unscopables": "1.0.2", + "es-to-primitive": "1.2.1", + "escape-string-regexp": "4.0.0", + "eslint": "8.52.0", + "eslint-config-airbnb-base": "15.0.0", + "eslint-import-resolver-node": "0.3.9", + "eslint-module-utils": "2.8.0", + "eslint-plugin-import": "2.29.0", + "eslint-plugin-react": "7.33.2", + "eslint-plugin-vue": "9.18.0", + "eslint-scope": "7.2.2", + "eslint-visitor-keys": "3.4.3", + "espree": "9.6.1", + "esquery": "1.5.0", + "esrecurse": "4.3.0", + "estraverse": "5.3.0", + "esutils": "2.0.3", + "fast-deep-equal": "3.1.3", + "fast-glob": "3.3.1", + "fast-json-stable-stringify": "2.1.0", + "fast-levenshtein": "2.0.6", + "fastq": "1.15.0", + "file-entry-cache": "6.0.1", + "fill-range": "7.0.1", + "find-up": "5.0.0", + "flat-cache": "3.1.1", + "flatted": "3.2.9", + "for-each": "0.3.3", + "fs.realpath": "1.0.0", + "function-bind": "1.1.2", + "function.prototype.name": "1.1.6", + "functions-have-names": "1.2.3", + "get-intrinsic": "1.2.2", + "get-symbol-description": "1.0.0", + "glob": "7.2.3", + "glob-parent": "6.0.2", + "globals": "13.23.0", + "globalthis": "1.0.3", + "globby": "11.1.0", + "gopd": "1.0.1", + "graphemer": "1.4.0", + "has-bigints": "1.0.2", + "has-flag": "4.0.0", + "has-property-descriptors": "1.0.1", + "has-proto": "1.0.1", + "has-symbols": "1.0.3", + "has-tostringtag": "1.0.0", + "hasown": "2.0.0", + "ignore": "5.2.4", + "import-fresh": "3.3.0", + "imurmurhash": "0.1.4", + "inflight": "1.0.6", + "inherits": "2.0.4", + "internal-slot": "1.0.6", + "is-array-buffer": "3.0.2", + "is-async-function": "2.0.0", + "is-bigint": "1.0.4", + "is-boolean-object": "1.1.2", + "is-callable": "1.2.7", + "is-core-module": "2.13.1", + "is-date-object": "1.0.5", + "is-extglob": "2.1.1", + "is-finalizationregistry": "1.0.2", + "is-generator-function": "1.0.10", + "is-glob": "4.0.3", + "is-map": "2.0.2", + "is-negative-zero": "2.0.2", + "is-number": "7.0.0", + "is-number-object": "1.0.7", + "is-path-inside": "3.0.3", + "is-regex": "1.1.4", + "is-set": "2.0.2", + "is-shared-array-buffer": "1.0.2", + "is-string": "1.0.7", + "is-symbol": "1.0.4", + "is-typed-array": "1.1.12", + "is-weakmap": "2.0.1", + "is-weakref": "1.0.2", + "is-weakset": "2.0.2", + "isarray": "2.0.5", + "isexe": "2.0.0", + "iterator.prototype": "1.1.2", + "js-tokens": "4.0.0", + "js-yaml": "4.1.0", + "json-buffer": "3.0.1", + "json-schema-traverse": "0.4.1", + "json-stable-stringify-without-jsonify": "1.0.1", + "json5": "1.0.2", + "jsx-ast-utils": "3.3.5", + "keyv": "4.5.4", + "levn": "0.4.1", + "locate-path": "6.0.0", + "lodash": "4.17.21", + "lodash.merge": "4.6.2", + "loose-envify": "1.4.0", + "lru-cache": "6.0.0", + "merge2": "1.4.1", + "micromatch": "4.0.5", + "minimatch": "3.1.2", + "minimist": "1.2.8", + "ms": "2.1.2", + "natural-compare": "1.4.0", + "node": "v21.1.0", + "nth-check": "2.1.1", + "object-assign": "4.1.1", + "object-inspect": "1.13.1", + "object-keys": "1.1.1", + "object.assign": "4.1.4", + "object.entries": "1.1.7", + "object.fromentries": "2.0.7", + "object.groupby": "1.0.1", + "object.hasown": "1.1.3", + "object.values": "1.1.7", + "once": "1.4.0", + "optionator": "0.9.3", + "p-limit": "3.1.0", + "p-locate": "5.0.0", + "parent-module": "1.0.1", + "path-exists": "4.0.0", + "path-is-absolute": "1.0.1", + "path-key": "3.1.1", + "path-parse": "1.0.7", + "path-type": "4.0.0", + "picomatch": "2.3.1", + "postcss-selector-parser": "6.0.13", + "prelude-ls": "1.2.1", + "prop-types": "15.8.1", + "punycode": "2.3.0", + "queue-microtask": "1.2.3", + "react-is": "16.13.1", + "reflect.getprototypeof": "1.0.4", + "regexp.prototype.flags": "1.5.1", + "resolve": "2.0.0-next.5", + "resolve-from": "4.0.0", + "reusify": "1.0.4", + "rimraf": "3.0.2", + "run-parallel": "1.2.0", + "safe-array-concat": "1.0.1", + "safe-regex-test": "1.0.0", + "semver": "7.5.4", + "set-function-length": "1.1.1", + "set-function-name": "2.0.1", + "shebang-command": "2.0.0", + "shebang-regex": "3.0.0", + "side-channel": "1.0.4", + "slash": "3.0.0", + "string.prototype.matchall": "4.0.10", + "string.prototype.trim": "1.2.8", + "string.prototype.trimend": "1.0.7", + "string.prototype.trimstart": "1.0.7", + "strip-ansi": "6.0.1", + "strip-bom": "3.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "7.2.0", + "supports-preserve-symlinks-flag": "1.0.0", + "text-table": "0.2.0", + "to-regex-range": "5.0.1", + "ts-api-utils": "1.0.3", + "tsconfig-paths": "3.14.2", + "type-check": "0.4.0", + "type-fest": "0.20.2", + "typed-array-buffer": "1.0.0", + "typed-array-byte-length": "1.0.0", + "typed-array-byte-offset": "1.0.0", + "typed-array-length": "1.0.4", + "typescript": "5.2.2", + "unbox-primitive": "1.0.2", + "uri-js": "4.4.1", + "util-deprecate": "1.0.2", + "vscode-eslint": "https://github.com/microsoft/vscode-eslint/archive/d3c7703cd11dc6752c96edf0f140d50156d72dd7.tar.gz", + "vue-eslint-parser": "9.3.2", + "which": "2.0.2", + "which-boxed-primitive": "1.0.2", + "which-builtin-type": "1.1.3", + "which-collection": "1.0.1", + "which-typed-array": "1.1.13", + "wrappy": "1.0.2", + "xml-name-validator": "4.0.0", + "yallist": "4.0.0", + "yocto-queue": "0.1.0" + } +, + "Flow": { + "flow-bin": "0.219.5" + } +, + "TypeScript": { + "node": "v21.1.0", + "typescript": "5.2.2", + "typescript-language-server": "4.0.0" + } +, + "quick-lint-js": { + "version": "2.17.0" + } + } +} diff --git a/website/public/benchmarks/incremental-change-wait-react-quickly-ch10-jsx.json b/website/public/benchmarks/incremental-change-wait-react-quickly-ch10-jsx.json index 9486dc3b5d..2a18e0f284 100644 --- a/website/public/benchmarks/incremental-change-wait-react-quickly-ch10-jsx.json +++ b/website/public/benchmarks/incremental-change-wait-react-quickly-ch10-jsx.json @@ -1 +1,343 @@ -{"data":[{"benchmarkName":"vscode-eslint-react/incremental-change-wait/react-quickly-ch10.jsx","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[2.9616989399999998E-2,3.0906313E-2,2.97330284E-2,2.93800522E-2,2.9767356000000002E-2,3.0520240599999998E-2,3.09438893E-2,3.0081267099999996E-2,3.50090699E-2,3.12738366E-2]}},{"benchmarkName":"vscode-eslint-typescript/incremental-change-wait/react-quickly-ch10.jsx","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[3.46823809E-2,3.3703789299999995E-2,3.53555151E-2,3.6331638E-2,3.39277449E-2,3.17493136E-2,3.5709715600000004E-2,3.46106499E-2,3.45102366E-2,3.4289009999999995E-2]}},{"benchmarkName":"Deno/incremental-change-wait/react-quickly-ch10.jsx","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[2.326778359E-1,2.3297900980000003E-1,2.337524749E-1,2.321367688E-1,2.323656467E-1,2.312726659E-1,2.3286347150000003E-1,2.3195961390000003E-1,2.322322615E-1,2.32583326E-1]}},{"benchmarkName":"Deno-nolint/incremental-change-wait/react-quickly-ch10.jsx","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[2.323870704E-1,2.3333364969999998E-1,2.319987693E-1,2.3258173499999998E-1,2.3339447409999997E-1,2.3269766230000002E-1,2.3306062430000002E-1,2.324597507E-1,2.331325201E-1,2.323590667E-1]}},{"benchmarkName":"Flow/incremental-change-wait/react-quickly-ch10.jsx","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[2.99559072E-2,2.95961412E-2,3.01362484E-2,3.00468241E-2,2.99923147E-2,2.99760615E-2,2.9955746999999998E-2,3.0014692599999997E-2,2.98518315E-2,2.9909199400000003E-2]}},{"benchmarkName":"quick-lint-js/incremental-change-wait/react-quickly-ch10.jsx","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[1.133436E-4,8.38852E-5,1.075423E-4,8.30371E-5,1.098356E-4,1.0788860000000001E-4,8.36436E-5,9.405620000000001E-5,1.103722E-4,9.136800000000001E-5]}},{"benchmarkName":"TypeScript-JSX/incremental-change-wait/react-quickly-ch10.jsx","warmupIterations":1,"measurementIterations":10,"samples":{"durationPerIteration":[2.753204903E-1,2.75508635E-1,2.756507492E-1,2.75017346E-1,2.756514605E-1,2.760580123E-1,2.761261202E-1,2.756010562E-1,2.754164491E-1,2.758652665E-1]}}],"metadata":{"ESLint":{"@eslint/eslintrc":"1.3.0","@humanwhocodes/config-array":"0.9.5","@humanwhocodes/object-schema":"1.2.1","@nodelib/fs.scandir":"2.1.5","@nodelib/fs.stat":"2.0.5","@nodelib/fs.walk":"1.2.8","@types/json-schema":"7.0.11","@types/json5":"0.0.29","@typescript-eslint/eslint-plugin":"5.26.0","@typescript-eslint/parser":"5.26.0","@typescript-eslint/scope-manager":"5.26.0","@typescript-eslint/type-utils":"5.26.0","@typescript-eslint/types":"5.26.0","@typescript-eslint/typescript-estree":"5.26.0","@typescript-eslint/utils":"5.26.0","@typescript-eslint/visitor-keys":"5.26.0","acorn":"8.7.1","acorn-jsx":"5.3.2","ajv":"6.12.6","ansi-regex":"5.0.1","ansi-styles":"4.3.0","argparse":"2.0.1","array-includes":"3.1.5","array-union":"2.1.0","array.prototype.flat":"1.3.0","array.prototype.flatmap":"1.3.0","balanced-match":"1.0.2","boolbase":"1.0.0","brace-expansion":"1.1.11","braces":"3.0.2","call-bind":"1.0.2","callsites":"3.1.0","chalk":"4.1.2","color-convert":"2.0.1","color-name":"1.1.4","concat-map":"0.0.1","confusing-browser-globals":"1.0.11","cross-spawn":"7.0.3","cssesc":"3.0.0","debug":"4.3.4","deep-is":"0.1.4","define-properties":"1.1.4","dir-glob":"3.0.1","doctrine":"2.1.0","es-abstract":"1.20.1","es-shim-unscopables":"1.0.0","es-to-primitive":"1.2.1","escape-string-regexp":"4.0.0","eslint":"8.16.0","eslint-config-airbnb-base":"15.0.0","eslint-import-resolver-node":"0.3.6","eslint-module-utils":"2.7.3","eslint-plugin-import":"2.26.0","eslint-plugin-react":"7.30.0","eslint-plugin-vue":"9.0.1","eslint-scope":"7.1.1","eslint-utils":"3.0.0","eslint-visitor-keys":"3.3.0","espree":"9.3.2","esquery":"1.4.0","esrecurse":"4.3.0","estraverse":"5.3.0","esutils":"2.0.3","fast-deep-equal":"3.1.3","fast-glob":"3.2.11","fast-json-stable-stringify":"2.1.0","fast-levenshtein":"2.0.6","fastq":"1.13.0","file-entry-cache":"6.0.1","fill-range":"7.0.1","find-up":"2.1.0","flat-cache":"3.0.4","flatted":"3.2.5","fs.realpath":"1.0.0","function-bind":"1.1.1","function.prototype.name":"1.1.5","functional-red-black-tree":"1.0.1","functions-have-names":"1.2.3","get-intrinsic":"1.1.1","get-symbol-description":"1.0.0","glob":"7.2.3","glob-parent":"6.0.2","globals":"13.15.0","globby":"11.1.0","has":"1.0.3","has-bigints":"1.0.2","has-flag":"4.0.0","has-property-descriptors":"1.0.0","has-symbols":"1.0.3","has-tostringtag":"1.0.0","ignore":"5.2.0","import-fresh":"3.3.0","imurmurhash":"0.1.4","inflight":"1.0.6","inherits":"2.0.4","internal-slot":"1.0.3","is-bigint":"1.0.4","is-boolean-object":"1.1.2","is-callable":"1.2.4","is-core-module":"2.9.0","is-date-object":"1.0.5","is-extglob":"2.1.1","is-glob":"4.0.3","is-negative-zero":"2.0.2","is-number":"7.0.0","is-number-object":"1.0.7","is-regex":"1.1.4","is-shared-array-buffer":"1.0.2","is-string":"1.0.7","is-symbol":"1.0.4","is-weakref":"1.0.2","isexe":"2.0.0","js-tokens":"4.0.0","js-yaml":"4.1.0","json-schema-traverse":"0.4.1","json-stable-stringify-without-jsonify":"1.0.1","json5":"1.0.1","jsx-ast-utils":"3.3.0","levn":"0.4.1","locate-path":"2.0.0","lodash":"4.17.21","lodash.merge":"4.6.2","loose-envify":"1.4.0","lru-cache":"6.0.0","merge2":"1.4.1","micromatch":"4.0.5","minimatch":"3.1.2","minimist":"1.2.6","ms":"2.1.2","natural-compare":"1.4.0","node":"v18.2.0","nth-check":"2.1.1","object-assign":"4.1.1","object-inspect":"1.12.2","object-keys":"1.1.1","object.assign":"4.1.2","object.entries":"1.1.5","object.fromentries":"2.0.5","object.hasown":"1.1.1","object.values":"1.1.5","once":"1.4.0","optionator":"0.9.1","p-limit":"1.3.0","p-locate":"2.0.0","p-try":"1.0.0","parent-module":"1.0.1","path-exists":"3.0.0","path-is-absolute":"1.0.1","path-key":"3.1.1","path-parse":"1.0.7","path-type":"4.0.0","picomatch":"2.3.1","postcss-selector-parser":"6.0.10","prelude-ls":"1.2.1","prop-types":"15.8.1","punycode":"2.1.1","queue-microtask":"1.2.3","react-is":"16.13.1","regexp.prototype.flags":"1.4.3","regexpp":"3.2.0","resolve":"1.22.0","resolve-from":"4.0.0","reusify":"1.0.4","rimraf":"3.0.2","run-parallel":"1.2.0","semver":"7.3.7","shebang-command":"2.0.0","shebang-regex":"3.0.0","side-channel":"1.0.4","slash":"3.0.0","string.prototype.matchall":"4.0.7","string.prototype.trimend":"1.0.5","string.prototype.trimstart":"1.0.5","strip-ansi":"6.0.1","strip-bom":"3.0.0","strip-json-comments":"3.1.1","supports-color":"7.2.0","supports-preserve-symlinks-flag":"1.0.0","text-table":"0.2.0","to-regex-range":"5.0.1","tsconfig-paths":"3.14.1","tslib":"1.14.1","tsutils":"3.21.0","type-check":"0.4.0","type-fest":"0.20.2","typescript":"4.7.2","unbox-primitive":"1.0.2","uri-js":"4.4.1","util-deprecate":"1.0.2","v8-compile-cache":"2.3.0","vscode-eslint":"https://github.com/microsoft/vscode-eslint/archive/d3c7703cd11dc6752c96edf0f140d50156d72dd7.tar.gz","vue-eslint-parser":"9.0.2","which":"2.0.2","which-boxed-primitive":"1.0.2","word-wrap":"1.2.3","wrappy":"1.0.2","xml-name-validator":"4.0.0","yallist":"4.0.0"},"Deno":{"deno":"1.22.0","typescript":"4.6.2","v8":"10.0.139.17"},"Flow":{"flow-bin":"0.179.0"},"quick-lint-js":{"version":"2.5.0"},"TypeScript":{"@nodelib/fs.scandir":"2.1.5","@nodelib/fs.stat":"2.0.5","@nodelib/fs.walk":"1.2.8","aggregate-error":"3.1.0","array-union":"2.1.0","balanced-match":"1.0.2","brace-expansion":"1.1.11","braces":"3.0.2","clean-stack":"2.2.0","commander":"9.2.0","concat-map":"0.0.1","crypto-random-string":"2.0.0","del":"6.1.1","dir-glob":"3.0.1","fast-glob":"3.2.11","fastq":"1.13.0","fill-range":"7.0.1","find-up":"3.0.0","fs-extra":"10.1.0","fs.realpath":"1.0.0","glob":"7.2.3","glob-parent":"5.1.2","globby":"11.1.0","graceful-fs":"4.2.10","ignore":"5.2.0","indent-string":"4.0.0","inflight":"1.0.6","inherits":"2.0.4","is-extglob":"2.1.1","is-glob":"4.0.3","is-number":"7.0.0","is-path-cwd":"2.2.0","is-path-inside":"3.0.3","is-stream":"2.0.1","isexe":"2.0.0","jsonfile":"6.1.0","locate-path":"3.0.0","lru-cache":"6.0.0","merge2":"1.4.1","micromatch":"4.0.5","minimatch":"3.1.2","node":"v18.2.0","once":"1.4.0","p-debounce":"2.1.0","p-limit":"2.3.0","p-locate":"3.0.0","p-map":"4.0.0","p-try":"2.2.0","path-exists":"3.0.0","path-is-absolute":"1.0.1","path-type":"4.0.0","picomatch":"2.3.1","pkg-up":"3.1.0","queue-microtask":"1.2.3","reusify":"1.0.4","rimraf":"3.0.2","run-parallel":"1.2.0","semver":"7.3.7","slash":"3.0.0","temp-dir":"2.0.0","tempy":"1.0.1","to-regex-range":"5.0.1","type-fest":"0.16.0","typescript":"4.7.2","typescript-language-server":"0.10.1","unique-string":"2.0.0","universalify":"2.0.0","vscode-jsonrpc":"6.0.0","vscode-languageserver":"7.0.0","vscode-languageserver-protocol":"3.16.0","vscode-languageserver-textdocument":"1.0.4","vscode-languageserver-types":"3.16.0","vscode-uri":"3.0.3","which":"2.0.2","wrappy":"1.0.2","yallist":"4.0.0"}}} \ No newline at end of file +{ + "data": [ + { + "benchmarkName": "vscode-eslint-react/incremental-change-wait/react-quickly-ch10.jsx", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.028326022200000002, 0.028971017700000001, 0.028707292299999999, 0.028031168699999998, 0.028292447999999998, 0.027977067100000003, 0.028810104499999999, 0.028072638800000001, 0.028351704599999999, 0.028803048799999998] + } + }, + { + "benchmarkName": "vscode-eslint-typescript/incremental-change-wait/react-quickly-ch10.jsx", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.027484611599999997, 0.0329994885, 0.029657482800000003, 0.030562508400000001, 0.027375305900000001, 0.027109677199999998, 0.0269627489, 0.030409597999999999, 0.027806746, 0.028941062600000001] + } + }, + { + "benchmarkName": "Deno/incremental-change-wait/react-quickly-ch10.jsx", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.22808051900000001, 0.22827811670000001, 0.22716637119999999, 0.22810540000000001, 0.22697278609999999, 0.22721900079999999, 0.2280747876, 0.22810339289999998, 0.22802150469999999, 0.22855549480000001] + } + }, + { + "benchmarkName": "Deno-nolint/incremental-change-wait/react-quickly-ch10.jsx", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.22823450319999999, 0.22803036579999997, 0.22833113669999999, 0.22770449089999997, 0.22836831839999999, 0.22858028840000003, 0.22791984730000001, 0.2277381111, 0.2286643807, 0.22834685299999999] + } + }, + { + "benchmarkName": "Flow/incremental-change-wait/react-quickly-ch10.jsx", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.027616465299999997, 0.027766066900000004, 0.027469262000000001, 0.027492451499999997, 0.0277389361, 0.027576739199999999, 0.027208145999999999, 0.027582515699999997, 0.027560980200000001, 0.027511159400000002] + } + }, + { + "benchmarkName": "quick-lint-js/incremental-change-wait/react-quickly-ch10.jsx", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.00011206549999999999, 0.0001060999, 8.2210200000000001e-05, 0.00010652949999999999, 0.0001336718, 0.00010241860000000001, 9.7639099999999998e-05, 0.0001127124, 0.00010151789999999999, 0.00011310319999999999] + } + }, + { + "benchmarkName": "Biome/incremental-change-wait/react-quickly-ch10.jsx", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.006454022299999999, 0.0065713868999999992, 0.0065744386000000004, 0.0063631857999999998, 0.0072668536000000004, 0.0066480651999999999, 0.0059689962999999995, 0.0059698557999999999, 0.0060185125999999995, 0.0068829312000000002] + } + }, + { + "benchmarkName": "TypeScript-JSX/incremental-change-wait/react-quickly-ch10.jsx", + "warmupIterations": 1, + "measurementIterations": 10, + "samples": { + "durationPerIteration": [0.27576081159999999, 0.27445261379999997, 0.27527971810000001, 0.27559375050000001, 0.27515887100000003, 0.27536663290000002, 0.27543966609999998, 0.27595772829999998, 0.27543417739999998, 0.27522114949999998] + } + } + ], + "metadata": { + "Biome": { + "@biomejs/biome": "1.3.1", + "@biomejs/cli-darwin-arm64": "1.3.1", + "@biomejs/cli-darwin-x64": "1.3.1", + "@biomejs/cli-linux-arm64": "1.3.1", + "@biomejs/cli-linux-x64": "1.3.1", + "@biomejs/cli-win32-arm64": "1.3.1", + "@biomejs/cli-win32-x64": "1.3.1" + } +, + "Deno": { + "deno": "1.37.2", + "typescript": "5.2.2", + "v8": "11.8.172.13" + } +, + "ESLint": { + "@aashutoshrathi/word-wrap": "1.2.6", + "@eslint-community/eslint-utils": "4.4.0", + "@eslint-community/regexpp": "4.10.0", + "@eslint/eslintrc": "2.1.2", + "@eslint/js": "8.52.0", + "@humanwhocodes/config-array": "0.11.13", + "@humanwhocodes/module-importer": "1.0.1", + "@humanwhocodes/object-schema": "2.0.1", + "@nodelib/fs.scandir": "2.1.5", + "@nodelib/fs.stat": "2.0.5", + "@nodelib/fs.walk": "1.2.8", + "@types/json-schema": "7.0.14", + "@types/json5": "0.0.29", + "@types/semver": "7.5.4", + "@typescript-eslint/eslint-plugin": "6.9.0", + "@typescript-eslint/parser": "6.9.0", + "@typescript-eslint/scope-manager": "6.9.0", + "@typescript-eslint/type-utils": "6.9.0", + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/typescript-estree": "6.9.0", + "@typescript-eslint/utils": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0", + "@ungap/structured-clone": "1.2.0", + "acorn": "8.11.1", + "acorn-jsx": "5.3.2", + "ajv": "6.12.6", + "ansi-regex": "5.0.1", + "ansi-styles": "4.3.0", + "argparse": "2.0.1", + "array-buffer-byte-length": "1.0.0", + "array-includes": "3.1.7", + "array-union": "2.1.0", + "array.prototype.findlastindex": "1.2.3", + "array.prototype.flat": "1.3.2", + "array.prototype.flatmap": "1.3.2", + "array.prototype.tosorted": "1.1.2", + "arraybuffer.prototype.slice": "1.0.2", + "asynciterator.prototype": "1.0.0", + "available-typed-arrays": "1.0.5", + "balanced-match": "1.0.2", + "boolbase": "1.0.0", + "brace-expansion": "1.1.11", + "braces": "3.0.2", + "call-bind": "1.0.5", + "callsites": "3.1.0", + "chalk": "4.1.2", + "color-convert": "2.0.1", + "color-name": "1.1.4", + "concat-map": "0.0.1", + "confusing-browser-globals": "1.0.11", + "cross-spawn": "7.0.3", + "cssesc": "3.0.0", + "debug": "4.3.4", + "deep-is": "0.1.4", + "define-data-property": "1.1.1", + "define-properties": "1.2.1", + "dir-glob": "3.0.1", + "doctrine": "2.1.0", + "es-abstract": "1.22.3", + "es-iterator-helpers": "1.0.15", + "es-set-tostringtag": "2.0.2", + "es-shim-unscopables": "1.0.2", + "es-to-primitive": "1.2.1", + "escape-string-regexp": "4.0.0", + "eslint": "8.52.0", + "eslint-config-airbnb-base": "15.0.0", + "eslint-import-resolver-node": "0.3.9", + "eslint-module-utils": "2.8.0", + "eslint-plugin-import": "2.29.0", + "eslint-plugin-react": "7.33.2", + "eslint-plugin-vue": "9.18.0", + "eslint-scope": "7.2.2", + "eslint-visitor-keys": "3.4.3", + "espree": "9.6.1", + "esquery": "1.5.0", + "esrecurse": "4.3.0", + "estraverse": "5.3.0", + "esutils": "2.0.3", + "fast-deep-equal": "3.1.3", + "fast-glob": "3.3.1", + "fast-json-stable-stringify": "2.1.0", + "fast-levenshtein": "2.0.6", + "fastq": "1.15.0", + "file-entry-cache": "6.0.1", + "fill-range": "7.0.1", + "find-up": "5.0.0", + "flat-cache": "3.1.1", + "flatted": "3.2.9", + "for-each": "0.3.3", + "fs.realpath": "1.0.0", + "function-bind": "1.1.2", + "function.prototype.name": "1.1.6", + "functions-have-names": "1.2.3", + "get-intrinsic": "1.2.2", + "get-symbol-description": "1.0.0", + "glob": "7.2.3", + "glob-parent": "6.0.2", + "globals": "13.23.0", + "globalthis": "1.0.3", + "globby": "11.1.0", + "gopd": "1.0.1", + "graphemer": "1.4.0", + "has-bigints": "1.0.2", + "has-flag": "4.0.0", + "has-property-descriptors": "1.0.1", + "has-proto": "1.0.1", + "has-symbols": "1.0.3", + "has-tostringtag": "1.0.0", + "hasown": "2.0.0", + "ignore": "5.2.4", + "import-fresh": "3.3.0", + "imurmurhash": "0.1.4", + "inflight": "1.0.6", + "inherits": "2.0.4", + "internal-slot": "1.0.6", + "is-array-buffer": "3.0.2", + "is-async-function": "2.0.0", + "is-bigint": "1.0.4", + "is-boolean-object": "1.1.2", + "is-callable": "1.2.7", + "is-core-module": "2.13.1", + "is-date-object": "1.0.5", + "is-extglob": "2.1.1", + "is-finalizationregistry": "1.0.2", + "is-generator-function": "1.0.10", + "is-glob": "4.0.3", + "is-map": "2.0.2", + "is-negative-zero": "2.0.2", + "is-number": "7.0.0", + "is-number-object": "1.0.7", + "is-path-inside": "3.0.3", + "is-regex": "1.1.4", + "is-set": "2.0.2", + "is-shared-array-buffer": "1.0.2", + "is-string": "1.0.7", + "is-symbol": "1.0.4", + "is-typed-array": "1.1.12", + "is-weakmap": "2.0.1", + "is-weakref": "1.0.2", + "is-weakset": "2.0.2", + "isarray": "2.0.5", + "isexe": "2.0.0", + "iterator.prototype": "1.1.2", + "js-tokens": "4.0.0", + "js-yaml": "4.1.0", + "json-buffer": "3.0.1", + "json-schema-traverse": "0.4.1", + "json-stable-stringify-without-jsonify": "1.0.1", + "json5": "1.0.2", + "jsx-ast-utils": "3.3.5", + "keyv": "4.5.4", + "levn": "0.4.1", + "locate-path": "6.0.0", + "lodash": "4.17.21", + "lodash.merge": "4.6.2", + "loose-envify": "1.4.0", + "lru-cache": "6.0.0", + "merge2": "1.4.1", + "micromatch": "4.0.5", + "minimatch": "3.1.2", + "minimist": "1.2.8", + "ms": "2.1.2", + "natural-compare": "1.4.0", + "node": "v21.1.0", + "nth-check": "2.1.1", + "object-assign": "4.1.1", + "object-inspect": "1.13.1", + "object-keys": "1.1.1", + "object.assign": "4.1.4", + "object.entries": "1.1.7", + "object.fromentries": "2.0.7", + "object.groupby": "1.0.1", + "object.hasown": "1.1.3", + "object.values": "1.1.7", + "once": "1.4.0", + "optionator": "0.9.3", + "p-limit": "3.1.0", + "p-locate": "5.0.0", + "parent-module": "1.0.1", + "path-exists": "4.0.0", + "path-is-absolute": "1.0.1", + "path-key": "3.1.1", + "path-parse": "1.0.7", + "path-type": "4.0.0", + "picomatch": "2.3.1", + "postcss-selector-parser": "6.0.13", + "prelude-ls": "1.2.1", + "prop-types": "15.8.1", + "punycode": "2.3.0", + "queue-microtask": "1.2.3", + "react-is": "16.13.1", + "reflect.getprototypeof": "1.0.4", + "regexp.prototype.flags": "1.5.1", + "resolve": "2.0.0-next.5", + "resolve-from": "4.0.0", + "reusify": "1.0.4", + "rimraf": "3.0.2", + "run-parallel": "1.2.0", + "safe-array-concat": "1.0.1", + "safe-regex-test": "1.0.0", + "semver": "7.5.4", + "set-function-length": "1.1.1", + "set-function-name": "2.0.1", + "shebang-command": "2.0.0", + "shebang-regex": "3.0.0", + "side-channel": "1.0.4", + "slash": "3.0.0", + "string.prototype.matchall": "4.0.10", + "string.prototype.trim": "1.2.8", + "string.prototype.trimend": "1.0.7", + "string.prototype.trimstart": "1.0.7", + "strip-ansi": "6.0.1", + "strip-bom": "3.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "7.2.0", + "supports-preserve-symlinks-flag": "1.0.0", + "text-table": "0.2.0", + "to-regex-range": "5.0.1", + "ts-api-utils": "1.0.3", + "tsconfig-paths": "3.14.2", + "type-check": "0.4.0", + "type-fest": "0.20.2", + "typed-array-buffer": "1.0.0", + "typed-array-byte-length": "1.0.0", + "typed-array-byte-offset": "1.0.0", + "typed-array-length": "1.0.4", + "typescript": "5.2.2", + "unbox-primitive": "1.0.2", + "uri-js": "4.4.1", + "util-deprecate": "1.0.2", + "vscode-eslint": "https://github.com/microsoft/vscode-eslint/archive/d3c7703cd11dc6752c96edf0f140d50156d72dd7.tar.gz", + "vue-eslint-parser": "9.3.2", + "which": "2.0.2", + "which-boxed-primitive": "1.0.2", + "which-builtin-type": "1.1.3", + "which-collection": "1.0.1", + "which-typed-array": "1.1.13", + "wrappy": "1.0.2", + "xml-name-validator": "4.0.0", + "yallist": "4.0.0", + "yocto-queue": "0.1.0" + } +, + "Flow": { + "flow-bin": "0.219.5" + } +, + "TypeScript": { + "node": "v21.1.0", + "typescript": "5.2.2", + "typescript-language-server": "4.0.0" + } +, + "quick-lint-js": { + "version": "2.17.0" + } + } +} diff --git a/website/public/benchmarks/index.ejs.html b/website/public/benchmarks/index.ejs.html index afd75fa51e..93c2e9b267 100644 --- a/website/public/benchmarks/index.ejs.html +++ b/website/public/benchmarks/index.ejs.html @@ -24,7 +24,7 @@ "vscode-eslint-vanilla": {hue: 70.0, name: "ESLint"}, "vscode-eslint-typescript": {hue: 80.0, name: "ESLint + TypeScript plugin"}, RSLint: {hue: 120.0}, - Rome: {hue: 160.0}, + Biome: {hue: 160.0}, Flow: {hue: 180.0}, Deno: {hue: 240.0}, "Deno-nolint": {hue: 260.0, name: "Deno (no linting)"}, @@ -225,13 +225,12 @@

Methodology

version <%= versions["quick-lint-js"]["version"] %> (Debian package)
  • - Rome - version 9be13cac83320929a949­201ca462015d5a446dbc (with rustc - version 1.61.1) + Biome + version <%= versions["Biome"]["version"] %> (npm package)
  • RSLint - version v0.3.2 (with rustc version 1.61.1) + version v0.3.2 (with rustc version 1.73.0)
  • Flow @@ -283,8 +282,8 @@

    Methodology

  • strager's "straglum"; Purism Librem 13 Version 4 laptop
  • CPU: Intel Core i7-7500U CPU @ 2.70 GHz (2 cores, 4 threads)
  • - OS: Linux Mint 20 Ulyana; Linux 5.4.0-42-generic #46-Ubuntu SMP - x86_64 GNU/Linux + OS: Linux Mint 20 Ulyana; 5.4.0-165-generic #182-Ubuntu SMP Mon Oct + 2 19:43:28 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
  • Performance governor: performance; 400 MHz - 3.50 GHz
  • From b74b691640f98ff9c547e57d5d773c9781f924be Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Thu, 26 Oct 2023 23:31:14 -0400 Subject: [PATCH 019/117] fix(website): change 130x faster claim to match benchmarks Our benchmarks now claim that quick-lint-js is only ~117.7x faster than ESLint. Update the marketing on the home page accordingly to avoid being dishonest. --- website/public/index.ejs.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/public/index.ejs.html b/website/public/index.ejs.html index cd8550c6c7..569b0feb7b 100755 --- a/website/public/index.ejs.html +++ b/website/public/index.ejs.html @@ -423,7 +423,7 @@

    - Over 130× faster than ESLint, + Over 90× faster than ESLint, quick-lint-js gives you instant feedback as you code. Find bugs in your JavaScript before your finger leaves the keyboard. Lint any JavaScript file with From b738de6639b9035272b97b8fc8b2e600160fdafd Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 02:54:46 -0400 Subject: [PATCH 020/117] feat(io): add Output_Stream::append_padded_decimal_integer I want to port some std::ostream-using code to Output_Stream. That code uses set::setw, but Output_Stream has no equivalent. Implement Output_Stream::append_padded_decimal_integer for unsigned integers so we can port that code properly. --- src/quick-lint-js/io/output-stream.h | 32 ++++++++++++++++++ test/test-output-stream.cpp | 49 ++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/src/quick-lint-js/io/output-stream.h b/src/quick-lint-js/io/output-stream.h index 01904511e7..480ed7e2c1 100644 --- a/src/quick-lint-js/io/output-stream.h +++ b/src/quick-lint-js/io/output-stream.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,37 @@ class Output_Stream { }); } + // Write pad_character then write a decimal integer. The total number of + // characters written is at least pad_width. + // + // append_padded_decimal_integer(42, 4, '0') + // => u8"0042" + template + void append_padded_decimal_integer( + T value, int pad_width, + std::enable_if_t, Char8> pad_character) { + int max_width = std::max(integer_string_length, pad_width); + this->append(max_width, [&](Char8* out) -> int { + Char8* integer_end = write_integer(value, out); + int integer_width = narrow_cast(integer_end - out); + bool need_padding = pad_width > integer_width; + if (!need_padding) { + return integer_width; + } + + Char8* out_end = out + pad_width; + Char8* integer_start = std::copy_backward(out, integer_end, out_end); + QLJS_ASSERT(out < integer_start && + "should pad with at least one character"); + QLJS_ASSERT(integer_start < out_end && + "integer should consume at least one character"); + for (Char8* c = out; c != integer_start; ++c) { + *c = pad_character; + } + return pad_width; + }); + } + template void append_fixed_hexadecimal_integer(T value, int width) { this->append(width, [&](Char8* out) -> int { diff --git a/test/test-output-stream.cpp b/test/test-output-stream.cpp index 8b3f3f076c..72a6ddffa1 100644 --- a/test/test-output-stream.cpp +++ b/test/test-output-stream.cpp @@ -145,6 +145,55 @@ TEST(Test_Memory_Output_Stream, append_fixed_hexadecimal_integer) { } } +TEST(Test_Memory_Output_Stream, append_padded_decimal_integer_exact_width) { + { + Memory_Output_Stream s(/*buffer_size=*/16); + s.append_padded_decimal_integer(1234u, 4, u8'x'); + s.flush(); + EXPECT_EQ(s.get_flushed_string8(), u8"1234"_sv); + } + + { + Memory_Output_Stream s(/*buffer_size=*/16); + s.append_padded_decimal_integer(0u, 1, u8'x'); + s.flush(); + EXPECT_EQ(s.get_flushed_string8(), u8"0"_sv); + } +} + +TEST(Test_Memory_Output_Stream, append_padded_decimal_integer_over_width) { + { + Memory_Output_Stream s(/*buffer_size=*/16); + s.append_padded_decimal_integer(1234u, 5, u8'x'); + s.flush(); + EXPECT_EQ(s.get_flushed_string8(), u8"x1234"_sv); + } + + { + Memory_Output_Stream s(/*buffer_size=*/16); + s.append_padded_decimal_integer(0u, 20, u8' '); + s.flush(); + EXPECT_EQ(s.get_flushed_string8(), u8" 0"_sv); + } +} + +TEST(Test_Memory_Output_Stream, + append_padded_decimal_integer_under_width_behaves_as_exact_width) { + { + Memory_Output_Stream s(/*buffer_size=*/16); + s.append_padded_decimal_integer(1234u, 1, u8'x'); + s.flush(); + EXPECT_EQ(s.get_flushed_string8(), u8"1234"_sv); + } + + { + Memory_Output_Stream s(/*buffer_size=*/16); + s.append_padded_decimal_integer(0u, 0, u8' '); + s.flush(); + EXPECT_EQ(s.get_flushed_string8(), u8"0"_sv); + } +} + #if defined(__EMSCRIPTEN__) // No filesystem on web. #else From 44d06b20f1c8158e4ba6e7e1ee21756bce72f6fd Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 14:41:43 -0400 Subject: [PATCH 021/117] refactor(container): std::ostream -> Output_Stream for profile dumps The vector profiling code uses std::ostream. I want us to use our memory streams more consistently. Switch the vector profile dumping code to use Output_Stream instead of std::ostream. --- .../container/vector-profiler-debug.cpp | 88 ++++++++----- src/quick-lint-js/container/vector-profiler.h | 7 +- test/test-vector-profiler.cpp | 120 ++++++++++-------- 3 files changed, 128 insertions(+), 87 deletions(-) diff --git a/src/quick-lint-js/container/vector-profiler-debug.cpp b/src/quick-lint-js/container/vector-profiler-debug.cpp index 1452adfbef..aebd4252a1 100644 --- a/src/quick-lint-js/container/vector-profiler-debug.cpp +++ b/src/quick-lint-js/container/vector-profiler-debug.cpp @@ -21,10 +21,6 @@ #include #include -#if QLJS_FEATURE_VECTOR_PROFILING -#include -#endif - QLJS_WARNING_IGNORE_MSVC(4996) // Function or variable may be unsafe. namespace quick_lint_js { @@ -94,31 +90,42 @@ void Vector_Instrumentation::register_dump_on_exit_if_requested() { const char *dump_vectors_value = std::getenv("QLJS_DUMP_VECTORS"); bool should_dump_on_exit = dump_vectors_value && *dump_vectors_value != '\0'; if (should_dump_on_exit) { + // HACK(strager): Force the stderr File_Output_Stream to be destructed + // *after* our std::atexit callback is called. + // + // Without this dummy call, the File_Output_Stream is destructed before our + // callback, causing uses of the File_Output_Stream to likely crash due to + // the vtable being wiped during destruction. + (void)File_Output_Stream::get_stderr(); + std::atexit([]() -> void { auto entries = instance.entries(); + Output_Stream &out = *File_Output_Stream::get_stderr(); { Vector_Max_Size_Histogram_By_Owner hist; hist.add_entries(entries); Monotonic_Allocator memory("Vector_Instrumentation dump_on_exit"); Vector_Max_Size_Histogram_By_Owner::dump( - hist.histogram(&memory), std::cerr, + hist.histogram(&memory), out, Vector_Max_Size_Histogram_By_Owner::Dump_Options{ .maximum_line_length = 80, .max_adjacent_empty_rows = 5, }); } - std::cerr << '\n'; + out.append_copy(u8'\n'); { Vector_Capacity_Change_Histogram_By_Owner hist; hist.add_entries(entries); Vector_Capacity_Change_Histogram_By_Owner::dump( - hist.histogram(), std::cerr, + hist.histogram(), out, Vector_Capacity_Change_Histogram_By_Owner::Dump_Options{ .maximum_line_length = 80, }); } + + out.flush(); }); } } @@ -196,23 +203,25 @@ Vector_Max_Size_Histogram_By_Owner::histogram( void Vector_Max_Size_Histogram_By_Owner::dump( Span histogram, - std::ostream &out) { + Output_Stream &out) { return dump(histogram, out, Dump_Options()); } void Vector_Max_Size_Histogram_By_Owner::dump( Span histogram, - std::ostream &out, const Dump_Options &options) { + Output_Stream &out, const Dump_Options &options) { bool need_blank_line = false; for (const auto &[group_name, object_size_histogram] : histogram) { QLJS_ASSERT(!object_size_histogram.empty()); if (need_blank_line) { - out << '\n'; + out.append_copy(u8'\n'); } need_blank_line = true; - out << "Max sizes for " << out_string8(group_name) << ":\n"; + out.append_literal(u8"Max sizes for "_sv); + out.append_copy(group_name); + out.append_literal(u8":\n"_sv); std::uint64_t max_count = 0; std::uint64_t total_count = 0; @@ -239,35 +248,42 @@ void Vector_Max_Size_Histogram_By_Owner::dump( QLJS_ASSERT(options.max_adjacent_empty_rows > 0); if (object_size - next_object_size > narrow_cast(options.max_adjacent_empty_rows)) { - out << "...\n"; + out.append_literal(u8"...\n"_sv); } else { for (std::size_t i = next_object_size; i < object_size; ++i) { - out << std::setw(max_digits_in_legend) << i << " ( 0%)\n"; + out.append_padded_decimal_integer(i, max_digits_in_legend, u8' '); + out.append_literal(u8" ( 0%)\n"_sv); } } - out << std::setw(max_digits_in_legend) << object_size << " ("; + out.append_padded_decimal_integer(object_size, max_digits_in_legend, + u8' '); + out.append_literal(u8" ("_sv); if (count == total_count) { - out << "ALL"; + out.append_literal(u8"ALL"_sv); } else { double count_fraction = static_cast(count) / static_cast(total_count); - out << std::setw(2) << std::round(count_fraction * 100) << "%"; + out.append_padded_decimal_integer( + static_cast(std::round(count_fraction * 100)), 2, u8' '); + out.append_literal(u8"%"_sv); } - out << ')'; + out.append_copy(u8')'); int bar_width = std::max(1, static_cast(std::floor(static_cast(count) * bar_scale_factor))); - out << " "; + out.append_literal(u8" "_sv); for (int i = 0; i < bar_width; ++i) { - out << '*'; + out.append_copy(u8'*'); } - out << '\n'; + out.append_copy(u8'\n'); next_object_size = object_size + 1; } } + + out.flush(); } Vector_Capacity_Change_Histogram_By_Owner:: @@ -307,10 +323,11 @@ Vector_Capacity_Change_Histogram_By_Owner::histogram() const { void Vector_Capacity_Change_Histogram_By_Owner::dump( const std::map &histogram, - std::ostream &out, const Dump_Options &options) { - out << R"(vector capacity changes: + Output_Stream &out, const Dump_Options &options) { + out.append_literal( + u8R"(vector capacity changes: (C=copied; z=initial alloc; -=used internal capacity) -)"; +)"_sv); int count_width = 1; for (auto &[owner, h] : histogram) { @@ -330,13 +347,20 @@ void Vector_Capacity_Change_Histogram_By_Owner::dump( continue; } - out << owner << ":\n"; + out.append_copy(to_string8_view(owner)); + out.append_literal(u8":\n"_sv); // Example: // 5C 0z 15_ |CCCCC_______________| - out << std::setw(count_width) << h.appends_growing_capacity << "C " - << std::setw(count_width) << h.appends_initial_capacity << "z " - << std::setw(count_width) << h.appends_reusing_capacity << "_ |"; + out.append_padded_decimal_integer(h.appends_growing_capacity, count_width, + u8' '); + out.append_literal(u8"C "_sv); + out.append_padded_decimal_integer(h.appends_initial_capacity, count_width, + u8' '); + out.append_literal(u8"z "_sv); + out.append_padded_decimal_integer(h.appends_reusing_capacity, count_width, + u8' '); + out.append_literal(u8"_ |"_sv); int graph_columns = options.maximum_line_length - (count_width * 3 + narrow_cast(std::strlen("C z _ ||"))); @@ -344,24 +368,24 @@ void Vector_Capacity_Change_Histogram_By_Owner::dump( narrow_cast(narrow_cast(graph_columns) * h.appends_growing_capacity / append_count); // 'C' for (int i = 0; i < columns_growing_capacity; ++i) { - out << 'C'; + out.append_copy(u8'C'); } int columns_initial_capacity = narrow_cast(narrow_cast(graph_columns) * h.appends_initial_capacity / append_count); // 'z' for (int i = 0; i < columns_initial_capacity; ++i) { - out << 'z'; + out.append_copy(u8'z'); } int columns_reusing_capacity = graph_columns - (columns_growing_capacity + columns_initial_capacity); // '_' for (int i = 0; i < columns_reusing_capacity; ++i) { - out << '_'; + out.append_copy(u8'_'); } - out << "|\n"; + out.append_copy(u8"|\n"_sv); } + out.flush(); } - } // quick-lint-js finds bugs in JavaScript programs. diff --git a/src/quick-lint-js/container/vector-profiler.h b/src/quick-lint-js/container/vector-profiler.h index 8e81451583..a84bdf78b6 100644 --- a/src/quick-lint-js/container/vector-profiler.h +++ b/src/quick-lint-js/container/vector-profiler.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -97,9 +98,9 @@ class Vector_Max_Size_Histogram_By_Owner { }; static void dump(Span, - std::ostream &); + Output_Stream &); static void dump(Span, - std::ostream &, const Dump_Options &options); + Output_Stream &, const Dump_Options &options); private: Hash_Map> histogram_; @@ -138,7 +139,7 @@ class Vector_Capacity_Change_Histogram_By_Owner { static void dump( const std::map &, - std::ostream &, const Dump_Options &); + Output_Stream &, const Dump_Options &); private: struct Vector_Info { diff --git a/test/test-vector-profiler.cpp b/test/test-vector-profiler.cpp index 00d4219846..c35ecfe705 100644 --- a/test/test-vector-profiler.cpp +++ b/test/test-vector-profiler.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -578,15 +579,15 @@ TEST_F(Test_Vector_Instrumentation_Max_Size_Histogram_By_Owner, TEST(Test_Vector_Instrumentation_Dump_Max_Size_Histogram, dump_empty_histogram) { - std::ostringstream stream; + Memory_Output_Stream stream; Vector_Max_Size_Histogram_By_Owner::dump( Span(), stream); - EXPECT_EQ(stream.str(), ""); + EXPECT_EQ(stream.get_flushed_string8(), u8""_sv); } TEST(Test_Vector_Instrumentation_Dump_Max_Size_Histogram, dump_histogram_with_one_group) { - std::ostringstream stream; + Memory_Output_Stream stream; Vector_Max_Size_Histogram_By_Owner::dump( Span({ Trace_Vector_Max_Size_Histogram_By_Owner_Entry{ @@ -600,16 +601,17 @@ TEST(Test_Vector_Instrumentation_Dump_Max_Size_Histogram, }, }), stream); - EXPECT_EQ(stream.str(), R"(Max sizes for test group: + EXPECT_EQ(stream.get_flushed_string8(), + u8R"(Max sizes for test group: 0 (50%) *** 1 (33%) ** 2 (17%) * -)"); +)"_sv); } TEST(Test_Vector_Instrumentation_Dump_Max_Size_Histogram, dump_histogram_with_one_data_point_per_group) { - std::ostringstream stream; + Memory_Output_Stream stream; Vector_Max_Size_Histogram_By_Owner::dump( Span({ Trace_Vector_Max_Size_Histogram_By_Owner_Entry{ @@ -621,14 +623,15 @@ TEST(Test_Vector_Instrumentation_Dump_Max_Size_Histogram, }, }), stream); - EXPECT_EQ(stream.str(), R"(Max sizes for test group: + EXPECT_EQ(stream.get_flushed_string8(), + u8R"(Max sizes for test group: 0 (ALL) ** -)"); +)"_sv); } TEST(Test_Vector_Instrumentation_Dump_Max_Size_Histogram, dump_histogram_with_multiple_groups) { - std::ostringstream stream; + Memory_Output_Stream stream; Vector_Max_Size_Histogram_By_Owner::dump( Span({ Trace_Vector_Max_Size_Histogram_By_Owner_Entry{ @@ -649,19 +652,20 @@ TEST(Test_Vector_Instrumentation_Dump_Max_Size_Histogram, }, }), stream); - EXPECT_EQ(stream.str(), R"(Max sizes for group A: + EXPECT_EQ(stream.get_flushed_string8(), + u8R"(Max sizes for group A: 0 (50%) *** 1 (50%) *** Max sizes for group B: 0 (50%) ** 1 (50%) ** -)"); +)"_sv); } TEST(Test_Vector_Instrumentation_Dump_Max_Size_Histogram, dump_sparse_histogram) { - std::ostringstream stream; + Memory_Output_Stream stream; Vector_Max_Size_Histogram_By_Owner::dump( Span({ Trace_Vector_Max_Size_Histogram_By_Owner_Entry{ @@ -676,7 +680,8 @@ TEST(Test_Vector_Instrumentation_Dump_Max_Size_Histogram, }, }), stream); - EXPECT_EQ(stream.str(), R"(Max sizes for test group: + EXPECT_EQ(stream.get_flushed_string8(), + u8R"(Max sizes for test group: 0 ( 0%) 1 (25%) * 2 ( 0%) @@ -687,12 +692,12 @@ TEST(Test_Vector_Instrumentation_Dump_Max_Size_Histogram, 7 ( 0%) 8 ( 0%) 9 (25%) * -)"); +)"_sv); } TEST(Test_Vector_Instrumentation_Dump_Max_Size_Histogram, histogram_legend_is_padded_with_spaces) { - std::ostringstream stream; + Memory_Output_Stream stream; Vector_Max_Size_Histogram_By_Owner::dump( Span({ Trace_Vector_Max_Size_Histogram_By_Owner_Entry{ @@ -705,8 +710,8 @@ TEST(Test_Vector_Instrumentation_Dump_Max_Size_Histogram, }, }), stream); - EXPECT_THAT(stream.str(), HasSubstr("\n 3 (")); - EXPECT_THAT(stream.str(), HasSubstr("\n100 (")); + EXPECT_THAT(to_string(stream.get_flushed_string8()), HasSubstr("\n 3 (")); + EXPECT_THAT(to_string(stream.get_flushed_string8()), HasSubstr("\n100 (")); } TEST(Test_Vector_Instrumentation_Dump_Max_Size_Histogram, @@ -716,7 +721,7 @@ TEST(Test_Vector_Instrumentation_Dump_Max_Size_Histogram, histogram["test group"][1] = 50; histogram["test group"][2] = 25; histogram["test group"][3] = 1; - std::ostringstream stream; + Memory_Output_Stream stream; Vector_Max_Size_Histogram_By_Owner::dump( Span({ Trace_Vector_Max_Size_Histogram_By_Owner_Entry{ @@ -734,17 +739,18 @@ TEST(Test_Vector_Instrumentation_Dump_Max_Size_Histogram, Vector_Max_Size_Histogram_By_Owner::Dump_Options{ .maximum_line_length = 20, }); - EXPECT_EQ(stream.str(), R"(Max sizes for test group: + EXPECT_EQ(stream.get_flushed_string8(), + u8R"(Max sizes for test group: 0 (57%) ********** 1 (28%) ***** 2 (14%) ** 3 ( 1%) * -)"); +)"_sv); } TEST(Test_Vector_Instrumentation_Dump_Max_Size_Histogram, histogram_skips_many_empty_rows) { - std::ostringstream stream; + Memory_Output_Stream stream; Vector_Max_Size_Histogram_By_Owner::dump( Span({ Trace_Vector_Max_Size_Histogram_By_Owner_Entry{ @@ -762,18 +768,19 @@ TEST(Test_Vector_Instrumentation_Dump_Max_Size_Histogram, Vector_Max_Size_Histogram_By_Owner::Dump_Options{ .max_adjacent_empty_rows = 3, }); - EXPECT_EQ(stream.str(), R"(Max sizes for test group: + EXPECT_EQ(stream.get_flushed_string8(), + u8R"(Max sizes for test group: 0 (20%) * 1 (40%) ** 2 (20%) * ... 8 (20%) * -)"); +)"_sv); } TEST(Test_Vector_Instrumentation_Dump_Max_Size_Histogram, histogram_including_legend_is_limited_to_max_screen_width) { - std::ostringstream stream; + Memory_Output_Stream stream; Vector_Max_Size_Histogram_By_Owner::dump( Span({ Trace_Vector_Max_Size_Histogram_By_Owner_Entry{ @@ -788,7 +795,8 @@ TEST(Test_Vector_Instrumentation_Dump_Max_Size_Histogram, Vector_Max_Size_Histogram_By_Owner::Dump_Options{ .maximum_line_length = 20, }); - EXPECT_THAT(stream.str(), HasSubstr("\n100 (ALL) ********\n")); + EXPECT_THAT(to_string(stream.get_flushed_string8()), + HasSubstr("\n100 (ALL) ********\n")); } TEST(Test_Vector_Instrumentation_Capacity_Change_Histogram_By_Owner, @@ -1084,20 +1092,21 @@ TEST(Test_Vector_Instrumentation_Capacity_Change_Histogram_By_Owner, EXPECT_EQ(hist["myvector"].appends_growing_capacity, 1) << "first vector"; } -std::string dump_capacity_change_header = R"(vector capacity changes: +constexpr String8_View dump_capacity_change_header = + u8R"(vector capacity changes: (C=copied; z=initial alloc; -=used internal capacity) -)"; +)"_sv; TEST(Test_Vector_Instrumentation_Dump_Capacity_Change_Histogram, dump_empty_histogram) { std::map histogram; - std::ostringstream stream; + Memory_Output_Stream stream; Vector_Capacity_Change_Histogram_By_Owner::dump( histogram, stream, Vector_Capacity_Change_Histogram_By_Owner::Dump_Options{}); - EXPECT_EQ(stream.str(), dump_capacity_change_header); + EXPECT_EQ(stream.get_flushed_string8(), dump_capacity_change_header); } TEST(Test_Vector_Instrumentation_Dump_Capacity_Change_Histogram, @@ -1106,15 +1115,16 @@ TEST(Test_Vector_Instrumentation_Dump_Capacity_Change_Histogram, Vector_Capacity_Change_Histogram_By_Owner::Capacity_Change_Histogram> histogram; histogram["myvector"].appends_reusing_capacity = 10; - std::ostringstream stream; + Memory_Output_Stream stream; Vector_Capacity_Change_Histogram_By_Owner::dump( histogram, stream, Vector_Capacity_Change_Histogram_By_Owner::Dump_Options{ .maximum_line_length = 34, }); - EXPECT_EQ(stream.str(), dump_capacity_change_header + R"(myvector: + EXPECT_EQ(stream.get_flushed_string8(), concat(dump_capacity_change_header, + u8R"(myvector: 0C 0z 10_ |____________________| -)"); +)"_sv)); } TEST(Test_Vector_Instrumentation_Dump_Capacity_Change_Histogram, @@ -1123,15 +1133,16 @@ TEST(Test_Vector_Instrumentation_Dump_Capacity_Change_Histogram, Vector_Capacity_Change_Histogram_By_Owner::Capacity_Change_Histogram> histogram; histogram["myvector"].appends_growing_capacity = 10; - std::ostringstream stream; + Memory_Output_Stream stream; Vector_Capacity_Change_Histogram_By_Owner::dump( histogram, stream, Vector_Capacity_Change_Histogram_By_Owner::Dump_Options{ .maximum_line_length = 34, }); - EXPECT_EQ(stream.str(), dump_capacity_change_header + R"(myvector: + EXPECT_EQ(stream.get_flushed_string8(), concat(dump_capacity_change_header, + u8R"(myvector: 10C 0z 0_ |CCCCCCCCCCCCCCCCCCCC| -)"); +)"_sv)); } TEST(Test_Vector_Instrumentation_Dump_Capacity_Change_Histogram, @@ -1140,15 +1151,16 @@ TEST(Test_Vector_Instrumentation_Dump_Capacity_Change_Histogram, Vector_Capacity_Change_Histogram_By_Owner::Capacity_Change_Histogram> histogram; histogram["myvector"].appends_initial_capacity = 10; - std::ostringstream stream; + Memory_Output_Stream stream; Vector_Capacity_Change_Histogram_By_Owner::dump( histogram, stream, Vector_Capacity_Change_Histogram_By_Owner::Dump_Options{ .maximum_line_length = 34, }); - EXPECT_EQ(stream.str(), dump_capacity_change_header + R"(myvector: + EXPECT_EQ(stream.get_flushed_string8(), concat(dump_capacity_change_header, + u8R"(myvector: 0C 10z 0_ |zzzzzzzzzzzzzzzzzzzz| -)"); +)"_sv)); } TEST(Test_Vector_Instrumentation_Dump_Capacity_Change_Histogram, @@ -1159,15 +1171,16 @@ TEST(Test_Vector_Instrumentation_Dump_Capacity_Change_Histogram, histogram["myvector"].appends_growing_capacity = 5; histogram["myvector"].appends_initial_capacity = 5; histogram["myvector"].appends_reusing_capacity = 10; - std::ostringstream stream; + Memory_Output_Stream stream; Vector_Capacity_Change_Histogram_By_Owner::dump( histogram, stream, Vector_Capacity_Change_Histogram_By_Owner::Dump_Options{ .maximum_line_length = 34, }); - EXPECT_EQ(stream.str(), dump_capacity_change_header + R"(myvector: + EXPECT_EQ(stream.get_flushed_string8(), concat(dump_capacity_change_header, + u8R"(myvector: 5C 5z 10_ |CCCCCzzzzz__________| -)"); +)"_sv)); } TEST(Test_Vector_Instrumentation_Dump_Capacity_Change_Histogram, @@ -1178,27 +1191,29 @@ TEST(Test_Vector_Instrumentation_Dump_Capacity_Change_Histogram, histogram["myvector"].appends_growing_capacity = 9001; { - std::ostringstream stream; + Memory_Output_Stream stream; Vector_Capacity_Change_Histogram_By_Owner::dump( histogram, stream, Vector_Capacity_Change_Histogram_By_Owner::Dump_Options{ .maximum_line_length = 30, }); - EXPECT_EQ(stream.str(), dump_capacity_change_header + R"(myvector: + EXPECT_EQ(stream.get_flushed_string8(), concat(dump_capacity_change_header, + u8R"(myvector: 9001C 0z 0_ |CCCCCCCCCC| -)"); +)"_sv)); } { - std::ostringstream stream; + Memory_Output_Stream stream; Vector_Capacity_Change_Histogram_By_Owner::dump( histogram, stream, Vector_Capacity_Change_Histogram_By_Owner::Dump_Options{ .maximum_line_length = 50, }); - EXPECT_EQ(stream.str(), dump_capacity_change_header + R"(myvector: + EXPECT_EQ(stream.get_flushed_string8(), concat(dump_capacity_change_header, + u8R"(myvector: 9001C 0z 0_ |CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC| -)"); +)"_sv)); } } @@ -1211,17 +1226,18 @@ TEST(Test_Vector_Instrumentation_Dump_Capacity_Change_Histogram, histogram["first"].appends_reusing_capacity = 1; histogram["second"].appends_growing_capacity = 30; histogram["second"].appends_reusing_capacity = 30; - std::ostringstream stream; + Memory_Output_Stream stream; Vector_Capacity_Change_Histogram_By_Owner::dump( histogram, stream, Vector_Capacity_Change_Histogram_By_Owner::Dump_Options{ .maximum_line_length = 30, }); - EXPECT_EQ(stream.str(), dump_capacity_change_header + R"(first: + EXPECT_EQ(stream.get_flushed_string8(), concat(dump_capacity_change_header, + u8R"(first: 1C 0z 1_ |CCCCCCCC________| second: 30C 0z 30_ |CCCCCCCC________| -)"); +)"_sv)); } TEST(Test_Vector_Instrumentation_Dump_Capacity_Change_Histogram, @@ -1231,11 +1247,11 @@ TEST(Test_Vector_Instrumentation_Dump_Capacity_Change_Histogram, histogram; histogram["first"]; // Zeroes. histogram["second"]; // Zeroes. - std::ostringstream stream; + Memory_Output_Stream stream; Vector_Capacity_Change_Histogram_By_Owner::dump( histogram, stream, Vector_Capacity_Change_Histogram_By_Owner::Dump_Options{}); - EXPECT_EQ(stream.str(), dump_capacity_change_header); + EXPECT_EQ(stream.get_flushed_string8(), dump_capacity_change_header); } } } From 051e57d1575d2f805e441f283f53360becd1886a Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 14:54:31 -0400 Subject: [PATCH 022/117] refactor(container): put vector profiler code into non-debug All the vector profiling code lives in quick-lint-js-lib-debug. quick-lint-js-lib-debug depends on quick-lint-js-lib. This is awkward because it means that, if vector profiling is enabled, quick-lint-js-lib depends on quick-lint-js-lib-debug. This is a dependency cycle, but for some reason CMake doesn't complain. Break the dependency cycle by putting the main vector profiler code into quick-lint-js-lib, keeping the -using code (used by tests only) in quick-lint-js-lib-debug. --- src/CMakeLists.txt | 5 +- .../container/vector-profiler-debug.cpp | 352 ---------------- .../container/vector-profiler.cpp | 376 ++++++++++++++++++ 3 files changed, 378 insertions(+), 355 deletions(-) create mode 100644 src/quick-lint-js/container/vector-profiler.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 88e561c365..8d02f34fc2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -294,6 +294,8 @@ quick_lint_js_add_library( quick-lint-js/container/linked-vector.h quick-lint-js/container/optional.h quick-lint-js/container/result.h + quick-lint-js/container/vector-profiler.cpp + quick-lint-js/container/vector-profiler.h quick-lint-js/container/vector.h quick-lint-js/debug/debug-probe.cpp quick-lint-js/debug/debug-probe.h @@ -507,9 +509,6 @@ else () QLJS_FEATURE_VECTOR_PROFILING=0 ) endif () -if (QUICK_LINT_JS_FEATURE_VECTOR_PROFILING) - target_link_libraries(quick-lint-js-lib PRIVATE quick-lint-js-lib-debug) -endif () # quick-lint-js-lib-debug should be dead-code stripped from production builds. # It is a separate library from quick-lint-js-lib to increase the chance that diff --git a/src/quick-lint-js/container/vector-profiler-debug.cpp b/src/quick-lint-js/container/vector-profiler-debug.cpp index aebd4252a1..cbc02f2d21 100644 --- a/src/quick-lint-js/container/vector-profiler-debug.cpp +++ b/src/quick-lint-js/container/vector-profiler-debug.cpp @@ -1,27 +1,9 @@ // Copyright (C) 2020 Matthew "strager" Glazar // See end of file for extended copyright information. -#include -#include -#include -#include -#include -#include #include -#include -#include #include -#include -#include -#include #include -#include -#include -#include -#include -#include - -QLJS_WARNING_IGNORE_MSVC(4996) // Function or variable may be unsafe. namespace quick_lint_js { std::ostream &operator<<(std::ostream &out, @@ -52,340 +34,6 @@ std::ostream &operator<<(std::ostream &out, << ", .size = " << e.size << ", .capacity = " << e.capacity << "}"; return out; } - -#if QLJS_FEATURE_VECTOR_PROFILING -Vector_Instrumentation Vector_Instrumentation::instance; -#endif - -void Vector_Instrumentation::clear() { this->entries_.lock()->clear(); } - -std::vector Vector_Instrumentation::entries() { - return *this->entries_.lock(); -} - -std::vector -Vector_Instrumentation::take_entries() { - std::vector result; - swap(result, *this->entries_.lock()); - return result; -} - -void Vector_Instrumentation::add_entry(std::uintptr_t object_id, - const char *owner, - Vector_Instrumentation::Event event, - std::uintptr_t data_pointer, - std::size_t size, std::size_t capacity) { - this->entries_.lock()->emplace_back(Entry{ - .object_id = object_id, - .owner = owner, - .event = event, - .data_pointer = data_pointer, - .size = size, - .capacity = capacity, - }); -} - -#if QLJS_FEATURE_VECTOR_PROFILING -void Vector_Instrumentation::register_dump_on_exit_if_requested() { - const char *dump_vectors_value = std::getenv("QLJS_DUMP_VECTORS"); - bool should_dump_on_exit = dump_vectors_value && *dump_vectors_value != '\0'; - if (should_dump_on_exit) { - // HACK(strager): Force the stderr File_Output_Stream to be destructed - // *after* our std::atexit callback is called. - // - // Without this dummy call, the File_Output_Stream is destructed before our - // callback, causing uses of the File_Output_Stream to likely crash due to - // the vtable being wiped during destruction. - (void)File_Output_Stream::get_stderr(); - - std::atexit([]() -> void { - auto entries = instance.entries(); - Output_Stream &out = *File_Output_Stream::get_stderr(); - - { - Vector_Max_Size_Histogram_By_Owner hist; - hist.add_entries(entries); - Monotonic_Allocator memory("Vector_Instrumentation dump_on_exit"); - Vector_Max_Size_Histogram_By_Owner::dump( - hist.histogram(&memory), out, - Vector_Max_Size_Histogram_By_Owner::Dump_Options{ - .maximum_line_length = 80, - .max_adjacent_empty_rows = 5, - }); - } - out.append_copy(u8'\n'); - - { - Vector_Capacity_Change_Histogram_By_Owner hist; - hist.add_entries(entries); - Vector_Capacity_Change_Histogram_By_Owner::dump( - hist.histogram(), out, - Vector_Capacity_Change_Histogram_By_Owner::Dump_Options{ - .maximum_line_length = 80, - }); - } - - out.flush(); - }); - } -} -#endif - -Vector_Max_Size_Histogram_By_Owner::Vector_Max_Size_Histogram_By_Owner() = - default; - -Vector_Max_Size_Histogram_By_Owner::~Vector_Max_Size_Histogram_By_Owner() = - default; - -void Vector_Max_Size_Histogram_By_Owner::add_entries( - const std::vector &entries) { - for (const Vector_Instrumentation::Entry &entry : entries) { - std::pair key(entry.owner, entry.object_id); - std::size_t &object_size = this->object_sizes_[key]; - object_size = std::max(entry.size, object_size); - - if (entry.event == Vector_Instrumentation::Event::destroy) { - this->histogram_[entry.owner][object_size] += 1; - this->object_sizes_.erase(key); - } - } -} - -Span -Vector_Max_Size_Histogram_By_Owner::histogram( - Monotonic_Allocator *memory) const { - // TODO(strager): Avoid this copy. - Hash_Map> histogram = - this->histogram_; - - for (auto &[owner_and_object_id, size] : this->object_sizes_) { - histogram[owner_and_object_id.first][size] += 1; - } - - // Convert Hash_Map into std::map. - // TODO(strager): Avoid this conversion. Convert straight into vectors. - // NOTE(strager): We might need to merge some inner maps because we built the - // Hash_Map with pointer comparison but we're building the std::map with - // string comparison. - std::map> stable_histogram; - for (auto &[owner, counts] : histogram) { - auto &stable_counts = stable_histogram[owner]; - for (auto &[size, count] : counts) { - stable_counts[size] += count; - } - } - - // NOTE(strager): We use Raw_Bump_Vector to prevent vector profiling code from - // emitting events itself. - Raw_Bump_Vector - out_entries_by_owner(memory); - out_entries_by_owner.reserve( - narrow_cast(stable_histogram.size())); - for (auto &[owner, counts] : stable_histogram) { - Raw_Bump_Vector - out_entries(memory); - out_entries.reserve(narrow_cast(counts.size())); - for (auto &[size, count] : counts) { - out_entries.push_back(Trace_Vector_Max_Size_Histogram_Entry{ - .max_size = narrow_cast(size), - .count = narrow_cast(count), - }); - } - out_entries_by_owner.push_back( - Trace_Vector_Max_Size_Histogram_By_Owner_Entry{ - .owner = to_string8_view(owner), - .max_size_entries = out_entries.release_to_span(), - }); - } - return out_entries_by_owner.release_to_span(); -} - -void Vector_Max_Size_Histogram_By_Owner::dump( - Span histogram, - Output_Stream &out) { - return dump(histogram, out, Dump_Options()); -} - -void Vector_Max_Size_Histogram_By_Owner::dump( - Span histogram, - Output_Stream &out, const Dump_Options &options) { - bool need_blank_line = false; - for (const auto &[group_name, object_size_histogram] : histogram) { - QLJS_ASSERT(!object_size_histogram.empty()); - - if (need_blank_line) { - out.append_copy(u8'\n'); - } - need_blank_line = true; - - out.append_literal(u8"Max sizes for "_sv); - out.append_copy(group_name); - out.append_literal(u8":\n"_sv); - - std::uint64_t max_count = 0; - std::uint64_t total_count = 0; - for (const auto &[_object_size, count] : object_size_histogram) { - total_count += count; - max_count = std::max(max_count, count); - } - std::uint64_t max_object_size = object_size_histogram.back().max_size; - - int max_digits_in_legend = static_cast( - std::ceil(std::log10(static_cast(max_object_size + 1)))); - int legend_length = max_digits_in_legend + 9; - int maximum_bar_length = options.maximum_line_length - legend_length; - double bar_scale_factor = - max_count > narrow_cast(maximum_bar_length) - ? static_cast(maximum_bar_length) / - static_cast(max_count) - : 1.0; - - std::size_t next_object_size = 0; - for (auto &[object_size, count] : object_size_histogram) { - QLJS_ASSERT(count != 0); - - QLJS_ASSERT(options.max_adjacent_empty_rows > 0); - if (object_size - next_object_size > - narrow_cast(options.max_adjacent_empty_rows)) { - out.append_literal(u8"...\n"_sv); - } else { - for (std::size_t i = next_object_size; i < object_size; ++i) { - out.append_padded_decimal_integer(i, max_digits_in_legend, u8' '); - out.append_literal(u8" ( 0%)\n"_sv); - } - } - - out.append_padded_decimal_integer(object_size, max_digits_in_legend, - u8' '); - out.append_literal(u8" ("_sv); - if (count == total_count) { - out.append_literal(u8"ALL"_sv); - } else { - double count_fraction = - static_cast(count) / static_cast(total_count); - out.append_padded_decimal_integer( - static_cast(std::round(count_fraction * 100)), 2, u8' '); - out.append_literal(u8"%"_sv); - } - out.append_copy(u8')'); - - int bar_width = - std::max(1, static_cast(std::floor(static_cast(count) * - bar_scale_factor))); - out.append_literal(u8" "_sv); - for (int i = 0; i < bar_width; ++i) { - out.append_copy(u8'*'); - } - out.append_copy(u8'\n'); - - next_object_size = object_size + 1; - } - } - - out.flush(); -} - -Vector_Capacity_Change_Histogram_By_Owner:: - Vector_Capacity_Change_Histogram_By_Owner() = default; - -Vector_Capacity_Change_Histogram_By_Owner:: - ~Vector_Capacity_Change_Histogram_By_Owner() = default; - -void Vector_Capacity_Change_Histogram_By_Owner::add_entries( - const std::vector &entries) { - for (const Vector_Instrumentation::Entry &entry : entries) { - Capacity_Change_Histogram &h = this->histogram_[entry.owner]; - if (entry.event == Vector_Instrumentation::Event::append) { - auto old_object_it = this->objects_.find(entry.object_id); - QLJS_ASSERT(old_object_it != this->objects_.end()); - Vector_Info &old_object = old_object_it->second; - if (old_object.data_pointer == entry.data_pointer) { - h.appends_reusing_capacity += 1; - } else if (old_object.size == 0) { - h.appends_initial_capacity += 1; - } else { - h.appends_growing_capacity += 1; - } - } - this->objects_[entry.object_id] = Vector_Info{ - .data_pointer = entry.data_pointer, - .size = entry.size, - }; - } -} - -std::map -Vector_Capacity_Change_Histogram_By_Owner::histogram() const { - return this->histogram_; -} - -void Vector_Capacity_Change_Histogram_By_Owner::dump( - const std::map &histogram, - Output_Stream &out, const Dump_Options &options) { - out.append_literal( - u8R"(vector capacity changes: -(C=copied; z=initial alloc; -=used internal capacity) -)"_sv); - - int count_width = 1; - for (auto &[owner, h] : histogram) { - count_width = std::max( - count_width, - narrow_cast(std::max( - std::max(std::to_string(h.appends_growing_capacity).size(), - std::to_string(h.appends_initial_capacity).size()), - std::to_string(h.appends_reusing_capacity).size()))); - } - - for (auto &[owner, h] : histogram) { - std::size_t append_count = h.appends_growing_capacity + - h.appends_initial_capacity + - h.appends_reusing_capacity; - if (append_count == 0) { - continue; - } - - out.append_copy(to_string8_view(owner)); - out.append_literal(u8":\n"_sv); - - // Example: - // 5C 0z 15_ |CCCCC_______________| - out.append_padded_decimal_integer(h.appends_growing_capacity, count_width, - u8' '); - out.append_literal(u8"C "_sv); - out.append_padded_decimal_integer(h.appends_initial_capacity, count_width, - u8' '); - out.append_literal(u8"z "_sv); - out.append_padded_decimal_integer(h.appends_reusing_capacity, count_width, - u8' '); - out.append_literal(u8"_ |"_sv); - int graph_columns = - options.maximum_line_length - - (count_width * 3 + narrow_cast(std::strlen("C z _ ||"))); - int columns_growing_capacity = - narrow_cast(narrow_cast(graph_columns) * - h.appends_growing_capacity / append_count); // 'C' - for (int i = 0; i < columns_growing_capacity; ++i) { - out.append_copy(u8'C'); - } - int columns_initial_capacity = - narrow_cast(narrow_cast(graph_columns) * - h.appends_initial_capacity / append_count); // 'z' - for (int i = 0; i < columns_initial_capacity; ++i) { - out.append_copy(u8'z'); - } - int columns_reusing_capacity = - graph_columns - - (columns_growing_capacity + columns_initial_capacity); // '_' - for (int i = 0; i < columns_reusing_capacity; ++i) { - out.append_copy(u8'_'); - } - out.append_copy(u8"|\n"_sv); - } - out.flush(); -} } // quick-lint-js finds bugs in JavaScript programs. diff --git a/src/quick-lint-js/container/vector-profiler.cpp b/src/quick-lint-js/container/vector-profiler.cpp new file mode 100644 index 0000000000..fa600c12ec --- /dev/null +++ b/src/quick-lint-js/container/vector-profiler.cpp @@ -0,0 +1,376 @@ +// Copyright (C) 2020 Matthew "strager" Glazar +// See end of file for extended copyright information. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QLJS_WARNING_IGNORE_MSVC(4996) // Function or variable may be unsafe. + +namespace quick_lint_js { +#if QLJS_FEATURE_VECTOR_PROFILING +Vector_Instrumentation Vector_Instrumentation::instance; +#endif + +void Vector_Instrumentation::clear() { this->entries_.lock()->clear(); } + +std::vector Vector_Instrumentation::entries() { + return *this->entries_.lock(); +} + +std::vector +Vector_Instrumentation::take_entries() { + std::vector result; + swap(result, *this->entries_.lock()); + return result; +} + +void Vector_Instrumentation::add_entry(std::uintptr_t object_id, + const char *owner, + Vector_Instrumentation::Event event, + std::uintptr_t data_pointer, + std::size_t size, std::size_t capacity) { + this->entries_.lock()->emplace_back(Entry{ + .object_id = object_id, + .owner = owner, + .event = event, + .data_pointer = data_pointer, + .size = size, + .capacity = capacity, + }); +} + +#if QLJS_FEATURE_VECTOR_PROFILING +void Vector_Instrumentation::register_dump_on_exit_if_requested() { + const char *dump_vectors_value = std::getenv("QLJS_DUMP_VECTORS"); + bool should_dump_on_exit = dump_vectors_value && *dump_vectors_value != '\0'; + if (should_dump_on_exit) { + // HACK(strager): Force the stderr File_Output_Stream to be destructed + // *after* our std::atexit callback is called. + // + // Without this dummy call, the File_Output_Stream is destructed before our + // callback, causing uses of the File_Output_Stream to likely crash due to + // the vtable being wiped during destruction. + (void)File_Output_Stream::get_stderr(); + + std::atexit([]() -> void { + auto entries = instance.entries(); + Output_Stream &out = *File_Output_Stream::get_stderr(); + + { + Vector_Max_Size_Histogram_By_Owner hist; + hist.add_entries(entries); + Monotonic_Allocator memory("Vector_Instrumentation dump_on_exit"); + Vector_Max_Size_Histogram_By_Owner::dump( + hist.histogram(&memory), out, + Vector_Max_Size_Histogram_By_Owner::Dump_Options{ + .maximum_line_length = 80, + .max_adjacent_empty_rows = 5, + }); + } + out.append_copy(u8'\n'); + + { + Vector_Capacity_Change_Histogram_By_Owner hist; + hist.add_entries(entries); + Vector_Capacity_Change_Histogram_By_Owner::dump( + hist.histogram(), out, + Vector_Capacity_Change_Histogram_By_Owner::Dump_Options{ + .maximum_line_length = 80, + }); + } + + out.flush(); + }); + } +} +#endif + +Vector_Max_Size_Histogram_By_Owner::Vector_Max_Size_Histogram_By_Owner() = + default; + +Vector_Max_Size_Histogram_By_Owner::~Vector_Max_Size_Histogram_By_Owner() = + default; + +void Vector_Max_Size_Histogram_By_Owner::add_entries( + const std::vector &entries) { + for (const Vector_Instrumentation::Entry &entry : entries) { + std::pair key(entry.owner, entry.object_id); + std::size_t &object_size = this->object_sizes_[key]; + object_size = std::max(entry.size, object_size); + + if (entry.event == Vector_Instrumentation::Event::destroy) { + this->histogram_[entry.owner][object_size] += 1; + this->object_sizes_.erase(key); + } + } +} + +Span +Vector_Max_Size_Histogram_By_Owner::histogram( + Monotonic_Allocator *memory) const { + // TODO(strager): Avoid this copy. + Hash_Map> histogram = + this->histogram_; + + for (auto &[owner_and_object_id, size] : this->object_sizes_) { + histogram[owner_and_object_id.first][size] += 1; + } + + // Convert Hash_Map into std::map. + // TODO(strager): Avoid this conversion. Convert straight into vectors. + // NOTE(strager): We might need to merge some inner maps because we built the + // Hash_Map with pointer comparison but we're building the std::map with + // string comparison. + std::map> stable_histogram; + for (auto &[owner, counts] : histogram) { + auto &stable_counts = stable_histogram[owner]; + for (auto &[size, count] : counts) { + stable_counts[size] += count; + } + } + + // NOTE(strager): We use Raw_Bump_Vector to prevent vector profiling code from + // emitting events itself. + Raw_Bump_Vector + out_entries_by_owner(memory); + out_entries_by_owner.reserve( + narrow_cast(stable_histogram.size())); + for (auto &[owner, counts] : stable_histogram) { + Raw_Bump_Vector + out_entries(memory); + out_entries.reserve(narrow_cast(counts.size())); + for (auto &[size, count] : counts) { + out_entries.push_back(Trace_Vector_Max_Size_Histogram_Entry{ + .max_size = narrow_cast(size), + .count = narrow_cast(count), + }); + } + out_entries_by_owner.push_back( + Trace_Vector_Max_Size_Histogram_By_Owner_Entry{ + .owner = to_string8_view(owner), + .max_size_entries = out_entries.release_to_span(), + }); + } + return out_entries_by_owner.release_to_span(); +} + +void Vector_Max_Size_Histogram_By_Owner::dump( + Span histogram, + Output_Stream &out) { + return dump(histogram, out, Dump_Options()); +} + +void Vector_Max_Size_Histogram_By_Owner::dump( + Span histogram, + Output_Stream &out, const Dump_Options &options) { + bool need_blank_line = false; + for (const auto &[group_name, object_size_histogram] : histogram) { + QLJS_ASSERT(!object_size_histogram.empty()); + + if (need_blank_line) { + out.append_copy(u8'\n'); + } + need_blank_line = true; + + out.append_literal(u8"Max sizes for "_sv); + out.append_copy(group_name); + out.append_literal(u8":\n"_sv); + + std::uint64_t max_count = 0; + std::uint64_t total_count = 0; + for (const auto &[_object_size, count] : object_size_histogram) { + total_count += count; + max_count = std::max(max_count, count); + } + std::uint64_t max_object_size = object_size_histogram.back().max_size; + + int max_digits_in_legend = static_cast( + std::ceil(std::log10(static_cast(max_object_size + 1)))); + int legend_length = max_digits_in_legend + 9; + int maximum_bar_length = options.maximum_line_length - legend_length; + double bar_scale_factor = + max_count > narrow_cast(maximum_bar_length) + ? static_cast(maximum_bar_length) / + static_cast(max_count) + : 1.0; + + std::size_t next_object_size = 0; + for (auto &[object_size, count] : object_size_histogram) { + QLJS_ASSERT(count != 0); + + QLJS_ASSERT(options.max_adjacent_empty_rows > 0); + if (object_size - next_object_size > + narrow_cast(options.max_adjacent_empty_rows)) { + out.append_literal(u8"...\n"_sv); + } else { + for (std::size_t i = next_object_size; i < object_size; ++i) { + out.append_padded_decimal_integer(i, max_digits_in_legend, u8' '); + out.append_literal(u8" ( 0%)\n"_sv); + } + } + + out.append_padded_decimal_integer(object_size, max_digits_in_legend, + u8' '); + out.append_literal(u8" ("_sv); + if (count == total_count) { + out.append_literal(u8"ALL"_sv); + } else { + double count_fraction = + static_cast(count) / static_cast(total_count); + out.append_padded_decimal_integer( + static_cast(std::round(count_fraction * 100)), 2, u8' '); + out.append_literal(u8"%"_sv); + } + out.append_copy(u8')'); + + int bar_width = + std::max(1, static_cast(std::floor(static_cast(count) * + bar_scale_factor))); + out.append_literal(u8" "_sv); + for (int i = 0; i < bar_width; ++i) { + out.append_copy(u8'*'); + } + out.append_copy(u8'\n'); + + next_object_size = object_size + 1; + } + } + + out.flush(); +} + +Vector_Capacity_Change_Histogram_By_Owner:: + Vector_Capacity_Change_Histogram_By_Owner() = default; + +Vector_Capacity_Change_Histogram_By_Owner:: + ~Vector_Capacity_Change_Histogram_By_Owner() = default; + +void Vector_Capacity_Change_Histogram_By_Owner::add_entries( + const std::vector &entries) { + for (const Vector_Instrumentation::Entry &entry : entries) { + Capacity_Change_Histogram &h = this->histogram_[entry.owner]; + if (entry.event == Vector_Instrumentation::Event::append) { + auto old_object_it = this->objects_.find(entry.object_id); + QLJS_ASSERT(old_object_it != this->objects_.end()); + Vector_Info &old_object = old_object_it->second; + if (old_object.data_pointer == entry.data_pointer) { + h.appends_reusing_capacity += 1; + } else if (old_object.size == 0) { + h.appends_initial_capacity += 1; + } else { + h.appends_growing_capacity += 1; + } + } + this->objects_[entry.object_id] = Vector_Info{ + .data_pointer = entry.data_pointer, + .size = entry.size, + }; + } +} + +std::map +Vector_Capacity_Change_Histogram_By_Owner::histogram() const { + return this->histogram_; +} + +void Vector_Capacity_Change_Histogram_By_Owner::dump( + const std::map &histogram, + Output_Stream &out, const Dump_Options &options) { + out.append_literal( + u8R"(vector capacity changes: +(C=copied; z=initial alloc; -=used internal capacity) +)"_sv); + + int count_width = 1; + for (auto &[owner, h] : histogram) { + count_width = std::max( + count_width, + narrow_cast(std::max( + std::max(std::to_string(h.appends_growing_capacity).size(), + std::to_string(h.appends_initial_capacity).size()), + std::to_string(h.appends_reusing_capacity).size()))); + } + + for (auto &[owner, h] : histogram) { + std::size_t append_count = h.appends_growing_capacity + + h.appends_initial_capacity + + h.appends_reusing_capacity; + if (append_count == 0) { + continue; + } + + out.append_copy(to_string8_view(owner)); + out.append_literal(u8":\n"_sv); + + // Example: + // 5C 0z 15_ |CCCCC_______________| + out.append_padded_decimal_integer(h.appends_growing_capacity, count_width, + u8' '); + out.append_literal(u8"C "_sv); + out.append_padded_decimal_integer(h.appends_initial_capacity, count_width, + u8' '); + out.append_literal(u8"z "_sv); + out.append_padded_decimal_integer(h.appends_reusing_capacity, count_width, + u8' '); + out.append_literal(u8"_ |"_sv); + int graph_columns = + options.maximum_line_length - + (count_width * 3 + narrow_cast(std::strlen("C z _ ||"))); + int columns_growing_capacity = + narrow_cast(narrow_cast(graph_columns) * + h.appends_growing_capacity / append_count); // 'C' + for (int i = 0; i < columns_growing_capacity; ++i) { + out.append_copy(u8'C'); + } + int columns_initial_capacity = + narrow_cast(narrow_cast(graph_columns) * + h.appends_initial_capacity / append_count); // 'z' + for (int i = 0; i < columns_initial_capacity; ++i) { + out.append_copy(u8'z'); + } + int columns_reusing_capacity = + graph_columns - + (columns_growing_capacity + columns_initial_capacity); // '_' + for (int i = 0; i < columns_reusing_capacity; ++i) { + out.append_copy(u8'_'); + } + out.append_copy(u8"|\n"_sv); + } + out.flush(); +} +} + +// quick-lint-js finds bugs in JavaScript programs. +// Copyright (C) 2020 Matthew "strager" Glazar +// +// This file is part of quick-lint-js. +// +// quick-lint-js is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// quick-lint-js is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with quick-lint-js. If not, see . From 6c080d8939fa298041e94d6b5163c706fdaf6fdc Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 15:01:53 -0400 Subject: [PATCH 023/117] refactor(build): allow tools to use Bump_Vector Build tools cannot use Bump_Vector. Bump_Vector lives in quick-lint-js-lib which is not usable by build tools. There are actually some tool users of Bump_Vector right now, but this only happens to work because QUICK_LINT_JS_FEATURE_VECTOR_PROFILING is not defined for those tools. If QUICK_LINT_JS_FEATURE_VECTOR_PROFILING is defined as intended, compilation breaks. Move Bump_Vector into quick-lint-js-tool-lib so tools can use it safely. --- src/CMakeLists.txt | 15 ++++++++------- src/quick-lint-js/container/vector-profiler.cpp | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8d02f34fc2..fc5df2a340 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -207,6 +207,10 @@ quick_lint_js_add_library( quick-lint-js/i18n/po-parser.cpp quick-lint-js/i18n/po-parser.h quick-lint-js/i18n/translation-table-compiler.cpp + quick-lint-js/container/vector-profiler.cpp + quick-lint-js/container/vector-profiler.h + quick-lint-js/container/vector.h + quick-lint-js/container/winkable.h quick-lint-js/i18n/translation-table-compiler.h quick-lint-js/io/file-handle-posix.cpp quick-lint-js/io/file-handle-win32.cpp @@ -227,6 +231,8 @@ quick_lint_js_add_library( quick-lint-js/port/memory-resource.cpp quick-lint-js/port/memory-resource.h quick-lint-js/port/source-location.h + quick-lint-js/port/thread.cpp + quick-lint-js/port/thread.h quick-lint-js/port/type-traits.h quick-lint-js/port/warning.h quick-lint-js/port/windows-error.cpp @@ -294,9 +300,6 @@ quick_lint_js_add_library( quick-lint-js/container/linked-vector.h quick-lint-js/container/optional.h quick-lint-js/container/result.h - quick-lint-js/container/vector-profiler.cpp - quick-lint-js/container/vector-profiler.h - quick-lint-js/container/vector.h quick-lint-js/debug/debug-probe.cpp quick-lint-js/debug/debug-probe.h quick-lint-js/debug/debug-server-fs.cpp @@ -431,8 +434,6 @@ quick_lint_js_add_library( quick-lint-js/port/span.h quick-lint-js/port/thread-name.cpp quick-lint-js/port/thread-name.h - quick-lint-js/port/thread.cpp - quick-lint-js/port/thread.h quick-lint-js/port/unreachable.h quick-lint-js/simdjson.cpp quick-lint-js/simdjson.h @@ -498,13 +499,13 @@ endif () if (QUICK_LINT_JS_FEATURE_VECTOR_PROFILING) target_compile_definitions( - quick-lint-js-lib + quick-lint-js-tool-lib PUBLIC QLJS_FEATURE_VECTOR_PROFILING=1 ) else () target_compile_definitions( - quick-lint-js-lib + quick-lint-js-tool-lib PUBLIC QLJS_FEATURE_VECTOR_PROFILING=0 ) diff --git a/src/quick-lint-js/container/vector-profiler.cpp b/src/quick-lint-js/container/vector-profiler.cpp index fa600c12ec..40bfc1b729 100644 --- a/src/quick-lint-js/container/vector-profiler.cpp +++ b/src/quick-lint-js/container/vector-profiler.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include From 5bb77f33ea2ad584c639d27e0aa55a635c20950a Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 15:01:10 -0400 Subject: [PATCH 024/117] refactor(reflection): prefer Bump_Vector over std::vector Reduce our use of std::vector to reduce binary bloat: https://github.com/quick-lint/quick-lint-js/issues/689 --- src/quick-lint-js/reflection/cxx-parser.cpp | 1 - src/quick-lint-js/reflection/cxx-parser.h | 9 ++++++--- test/quick-lint-js/diagnostic-assertion.cpp | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/quick-lint-js/reflection/cxx-parser.cpp b/src/quick-lint-js/reflection/cxx-parser.cpp index 6e1c0537fc..437ed5c7ab 100644 --- a/src/quick-lint-js/reflection/cxx-parser.cpp +++ b/src/quick-lint-js/reflection/cxx-parser.cpp @@ -19,7 +19,6 @@ #include #include #include -#include using namespace std::literals::string_view_literals; diff --git a/src/quick-lint-js/reflection/cxx-parser.h b/src/quick-lint-js/reflection/cxx-parser.h index af0160805c..fc0defe907 100644 --- a/src/quick-lint-js/reflection/cxx-parser.h +++ b/src/quick-lint-js/reflection/cxx-parser.h @@ -9,10 +9,10 @@ #include #include #include +#include #include #include #include -#include namespace quick_lint_js { class CLI_Locator; @@ -197,8 +197,11 @@ class CXX_Diagnostic_Types_Parser : private CXX_Parser_Base { using Base::fatal_at; - std::vector parsed_types; - std::vector reserved_codes; + Monotonic_Allocator allocator_{"CXX_Diagnostic_Types_Parser"}; + Bump_Vector parsed_types{ + "parsed_types", &this->allocator_}; + Bump_Vector reserved_codes{ + "reserved_codes", &this->allocator_}; }; // Precondition: variables.size() <= 4 diff --git a/test/quick-lint-js/diagnostic-assertion.cpp b/test/quick-lint-js/diagnostic-assertion.cpp index 24897b62a0..6a5e8b40ac 100644 --- a/test/quick-lint-js/diagnostic-assertion.cpp +++ b/test/quick-lint-js/diagnostic-assertion.cpp @@ -629,7 +629,7 @@ const Diagnostic_Info_Debug& get_diagnostic_info_debug(Diag_Type type) { parser.parse_file(); std::vector infos; - infos.reserve(parser.parsed_types.size()); + infos.reserve(narrow_cast(parser.parsed_types.size())); for (CXX_Diagnostic_Type& diag_type : parser.parsed_types) { Diagnostic_Info_Debug& info = infos.emplace_back(); Fixed_Vector variable_offsets = layout_offsets( From 742fabf97a565c5a1f11f7ea40e22143b9af5727 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 15:01:10 -0400 Subject: [PATCH 025/117] refactor(reflection): avoid String8 Reduce our use of std::string/String8 to reduce binary bloat: https://github.com/quick-lint/quick-lint-js/issues/689 --- src/quick-lint-js/reflection/cxx-parser.cpp | 12 +++++++----- src/quick-lint-js/reflection/cxx-parser.h | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/quick-lint-js/reflection/cxx-parser.cpp b/src/quick-lint-js/reflection/cxx-parser.cpp index 437ed5c7ab..da63ad5a14 100644 --- a/src/quick-lint-js/reflection/cxx-parser.cpp +++ b/src/quick-lint-js/reflection/cxx-parser.cpp @@ -673,11 +673,13 @@ bool CXX_Diagnostic_Types_Parser::is_valid_code_string( this->lexer_.is_digit(code_string[4]); } -String8 CXX_Diagnostic_Types_Parser::next_unused_diag_code_string() { +String8_View CXX_Diagnostic_Types_Parser::next_unused_diag_code_string() { + Span code_string_raw = + this->allocator_.allocate_uninitialized_span(8); for (int i = 1; i <= 9999; ++i) { - char code_string_raw[8]; - std::snprintf(code_string_raw, sizeof(code_string_raw), "E%04d", i); - String8_View code_string = to_string8_view(code_string_raw); + std::snprintf(code_string_raw.data(), + narrow_cast(code_string_raw.size()), "E%04d", i); + String8_View code_string = to_string8_view(code_string_raw.data()); bool in_use = any_of(this->parsed_types, [&](const CXX_Diagnostic_Type& type) { return code_string == type.code_string; @@ -687,7 +689,7 @@ String8 CXX_Diagnostic_Types_Parser::next_unused_diag_code_string() { return code_string == reserved_code.code; }); if (!in_use) { - return String8(code_string); + return code_string; } } QLJS_UNIMPLEMENTED(); diff --git a/src/quick-lint-js/reflection/cxx-parser.h b/src/quick-lint-js/reflection/cxx-parser.h index fc0defe907..6b92d99b2d 100644 --- a/src/quick-lint-js/reflection/cxx-parser.h +++ b/src/quick-lint-js/reflection/cxx-parser.h @@ -193,7 +193,7 @@ class CXX_Diagnostic_Types_Parser : private CXX_Parser_Base { bool is_valid_code_string(String8_View code_string); - String8 next_unused_diag_code_string(); + String8_View next_unused_diag_code_string(); using Base::fatal_at; From ecfb809d7d65ea05aa7598559f6bfc814ae6a40a Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 15:01:10 -0400 Subject: [PATCH 026/117] refactor(container): delete unused function --- src/quick-lint-js/container/byte-buffer.cpp | 4 ---- src/quick-lint-js/container/byte-buffer.h | 1 - 2 files changed, 5 deletions(-) diff --git a/src/quick-lint-js/container/byte-buffer.cpp b/src/quick-lint-js/container/byte-buffer.cpp index 50f14706eb..bfb66ba0f4 100644 --- a/src/quick-lint-js/container/byte-buffer.cpp +++ b/src/quick-lint-js/container/byte-buffer.cpp @@ -83,10 +83,6 @@ void* Byte_Buffer::append(Size_Type byte_count) { return std::exchange(this->cursor_, this->cursor_ + byte_count); } -void Byte_Buffer::append_copy(const String8& data) { - return this->append_copy(String8_View(data)); -} - void Byte_Buffer::append_copy(String8_View data) { static_assert(sizeof(data[0]) == 1); void* out = this->append(data.size()); diff --git a/src/quick-lint-js/container/byte-buffer.h b/src/quick-lint-js/container/byte-buffer.h index a311485da0..c1789de051 100644 --- a/src/quick-lint-js/container/byte-buffer.h +++ b/src/quick-lint-js/container/byte-buffer.h @@ -65,7 +65,6 @@ class Byte_Buffer { }); } - void append_copy(const String8& data); void append_copy(String8_View data); void append_copy(Char8 data); From 96937777aa02d70013f6b9259407984eb090525e Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 15:01:10 -0400 Subject: [PATCH 027/117] refactor(container): remove unnecessary constructor overload Padded_String(a_string8) is functionally equivalent to Padded_String(a_string8_view), so implement just the latter instead of both. --- src/quick-lint-js/container/padded-string.cpp | 3 --- src/quick-lint-js/container/padded-string.h | 1 - 2 files changed, 4 deletions(-) diff --git a/src/quick-lint-js/container/padded-string.cpp b/src/quick-lint-js/container/padded-string.cpp index f3b75274eb..f57e1da4ad 100644 --- a/src/quick-lint-js/container/padded-string.cpp +++ b/src/quick-lint-js/container/padded-string.cpp @@ -21,9 +21,6 @@ Padded_String::Padded_String() { this->size_excluding_padding_bytes_ = 0; } -Padded_String::Padded_String(String8&& string) - : Padded_String(String8_View(string)) {} - Padded_String::Padded_String(String8_View string) { this->size_excluding_padding_bytes_ = narrow_cast(string.size()); Size_Type size_including_padding_bytes = diff --git a/src/quick-lint-js/container/padded-string.h b/src/quick-lint-js/container/padded-string.h index 05dac4ca77..878cea8721 100644 --- a/src/quick-lint-js/container/padded-string.h +++ b/src/quick-lint-js/container/padded-string.h @@ -22,7 +22,6 @@ class Padded_String { static constexpr Size_Type padding_size = 64; explicit Padded_String(); - explicit Padded_String(String8 &&); explicit Padded_String(String8_View); explicit Padded_String(const Char8 *) = delete; From be0f40eae6164090d2b025120bd8f6b756aa0f94 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 15:01:10 -0400 Subject: [PATCH 028/117] refactor(c-api): avoid String8 Reduce our use of std::string/String8 to reduce binary bloat: https://github.com/quick-lint/quick-lint-js/issues/689 --- src/quick-lint-js/c-api-diag-reporter.cpp | 9 +++++---- src/quick-lint-js/c-api-diag-reporter.h | 5 ++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/quick-lint-js/c-api-diag-reporter.cpp b/src/quick-lint-js/c-api-diag-reporter.cpp index caa31e87f5..76c0739cfa 100644 --- a/src/quick-lint-js/c-api-diag-reporter.cpp +++ b/src/quick-lint-js/c-api-diag-reporter.cpp @@ -8,13 +8,14 @@ #include #include #include +#include #include #include #include #include #include #include -#include +#include namespace quick_lint_js { template @@ -88,7 +89,7 @@ void C_API_Diag_Formatter::write_message_part( // Don't write notes. Only write the main message. return; } - this->current_message_.append(message); + this->current_message_ += message; } template @@ -123,8 +124,8 @@ void C_API_Diag_Formatter::write_after_message( char *code_end = std::copy(code.begin(), code.end(), &diag.code[0]); *code_end = '\0'; - diag.message = reinterpret_cast( - this->reporter_->allocate_c_string(this->current_message_)); + this->current_message_.push_back(u8'\0'); + diag.message = reinterpret_cast(this->current_message_.data()); diag.severity = diag_severity; } diff --git a/src/quick-lint-js/c-api-diag-reporter.h b/src/quick-lint-js/c-api-diag-reporter.h index ceb7aa3f45..b34182550c 100644 --- a/src/quick-lint-js/c-api-diag-reporter.h +++ b/src/quick-lint-js/c-api-diag-reporter.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -67,7 +68,9 @@ class C_API_Diag_Formatter private: C_API_Diag_Reporter *reporter_; - String8 current_message_; + Bump_Vector current_message_{ + "C_API_Diag_Reporter::current_message_", + &this->reporter_->string_allocator_}; }; QLJS_WARNING_PUSH From 0f1dee50098e2ba015c73e3236ddf5497889cbf0 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 15:01:10 -0400 Subject: [PATCH 029/117] refactor(c-api): prefer Bump_Vector over std::vector Reduce our use of std::vector to reduce binary bloat: https://github.com/quick-lint/quick-lint-js/issues/689 --- src/quick-lint-js/c-api-diag-reporter.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/quick-lint-js/c-api-diag-reporter.h b/src/quick-lint-js/c-api-diag-reporter.h index b34182550c..3e1cfe6f5f 100644 --- a/src/quick-lint-js/c-api-diag-reporter.h +++ b/src/quick-lint-js/c-api-diag-reporter.h @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -16,9 +17,6 @@ #include #include #include -#include - -struct QLJS_Web_Demo_Diagnostic; namespace quick_lint_js { template @@ -43,7 +41,9 @@ class C_API_Diag_Reporter final : public Diag_Reporter { Char8 *allocate_c_string(String8_View); Translator translator_; - std::vector diagnostics_; + Monotonic_Allocator allocator_{"C_API_Diag_Reporter::allocator_"}; + Bump_Vector diagnostics_{ + "C_API_Diag_Reporter::diagnostics_", &this->allocator_}; const Char8 *input_; std::optional locator_; Monotonic_Allocator string_allocator_{ From 0bbe442f58eaaf5bcb095ccf9bc4f9b3dc9c3b55 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 15:01:10 -0400 Subject: [PATCH 030/117] refactor(port): rename Function_Ref -> Async_Function_Ref and document Function_Ref has some quirks. Rename it and document it for clarity. --- src/quick-lint-js/io/temporary-directory.cpp | 8 +++--- src/quick-lint-js/io/temporary-directory.h | 4 +-- src/quick-lint-js/port/function-ref.h | 27 ++++++++++++-------- src/quick-lint-js/util/binary-reader.h | 8 +++--- test/test-debug-server.cpp | 11 ++++---- test/test-function-ref.cpp | 26 ++++++++++--------- 6 files changed, 46 insertions(+), 38 deletions(-) diff --git a/src/quick-lint-js/io/temporary-directory.cpp b/src/quick-lint-js/io/temporary-directory.cpp index a2ee477ccf..4638ce4137 100644 --- a/src/quick-lint-js/io/temporary-directory.cpp +++ b/src/quick-lint-js/io/temporary-directory.cpp @@ -267,7 +267,7 @@ bool is_dot_or_dot_dot(const Char *path) { #if QLJS_HAVE_WINDOWS_H Result list_directory_raw( const char *directory, - Function_Ref visit_entry) { + Async_Function_Ref visit_entry) { std::optional search_pattern = mbstring_to_wstring(directory); if (!search_pattern.has_value()) { QLJS_UNIMPLEMENTED(); @@ -299,7 +299,7 @@ Result list_directory_raw( #if QLJS_HAVE_DIRENT_H Result list_directory_raw( - const char *directory, Function_Ref visit_entry) { + const char *directory, Async_Function_Ref visit_entry) { ::DIR *d = ::opendir(directory); if (d == nullptr) { return failed_result(POSIX_File_IO_Error{ @@ -326,7 +326,7 @@ Result list_directory_raw( } Result list_directory( - const char *directory, Function_Ref visit_file) { + const char *directory, Async_Function_Ref visit_file) { #if QLJS_HAVE_WINDOWS_H auto visit_entry = [&](::WIN32_FIND_DATAW &entry) -> void { // TODO(strager): Reduce allocations. @@ -354,7 +354,7 @@ Result list_directory( Result list_directory( const char *directory, - Function_Ref visit_file) { + Async_Function_Ref visit_file) { #if QLJS_HAVE_WINDOWS_H auto visit_entry = [&](::WIN32_FIND_DATAW &entry) -> void { // TODO(strager): Reduce allocations. diff --git a/src/quick-lint-js/io/temporary-directory.h b/src/quick-lint-js/io/temporary-directory.h index e50adcb6ef..1cb6697053 100644 --- a/src/quick-lint-js/io/temporary-directory.h +++ b/src/quick-lint-js/io/temporary-directory.h @@ -44,10 +44,10 @@ Result make_timestamped_directory( // // visit_file is called with the name (not full path) of the child. Result list_directory( - const char* directory, Function_Ref visit_file); + const char* directory, Async_Function_Ref visit_file); Result list_directory( const char* directory, - Function_Ref visit_file); + Async_Function_Ref visit_file); QLJS_WARNING_PUSH // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69210 diff --git a/src/quick-lint-js/port/function-ref.h b/src/quick-lint-js/port/function-ref.h index 2278c26270..e18f663f26 100644 --- a/src/quick-lint-js/port/function-ref.h +++ b/src/quick-lint-js/port/function-ref.h @@ -9,24 +9,29 @@ namespace quick_lint_js { template -class Function_Ref; +class Async_Function_Ref; QLJS_WARNING_PUSH QLJS_WARNING_IGNORE_CLANG("-Wcast-qual") QLJS_WARNING_IGNORE_CLANG("-Wold-style-cast") QLJS_WARNING_IGNORE_GCC("-Wconditionally-supported") QLJS_WARNING_IGNORE_GCC("-Wold-style-cast") -// Function_Ref is like std::function_ref +// Async_Function_Ref is like std::function_ref // (https://www.open-std.org/JTC1/SC22/WG21/docs/papers/2022/p0792r10.html). // // Deviations from the specification: -// * Our function_ref does not allow construction from rvalue functors. +// * Our Async_Function_Ref does not allow construction from rvalue functors. +// +// Async_Function_Ref is designed for asynchronous or deferred calling. +// Async_Function_Ref is useful for a job queue routine, but not for a +// std::for_each parameter. template -class Function_Ref { +class Async_Function_Ref { public: - // Construct a function_ref which will call a function pointer (no closure). + // Construct an Async_Function_Ref which will call a function pointer (no + // closure). template - /*implicit*/ Function_Ref( + /*implicit*/ Async_Function_Ref( Func&& func, std::enable_if_t>* = nullptr) @@ -34,7 +39,7 @@ class Function_Ref { closure_(reinterpret_cast( static_cast(func))) {} - // Construct a function_ref which will call a functor. + // Construct an Async_Function_Ref which will call a functor. // // This overload is disabled for incoming rvalue references. 'func' must be an // lvalue reference. @@ -42,7 +47,7 @@ class Function_Ref { // This overload is disabled for function pointers and for functors which can // be converted into a function pointer. template - /*implicit*/ Function_Ref( + /*implicit*/ Async_Function_Ref( Func&& func, std::enable_if_t && std::is_lvalue_reference_v && @@ -50,9 +55,9 @@ class Function_Ref { nullptr) : callback_(callback>), closure_(&func) {} - Function_Ref(Function_Ref& func) = default; - Function_Ref(const Function_Ref& func) = default; - Function_Ref(Function_Ref&& func) = default; + Async_Function_Ref(Async_Function_Ref& func) = default; + Async_Function_Ref(const Async_Function_Ref& func) = default; + Async_Function_Ref(Async_Function_Ref&& func) = default; Result operator()(Args... args) { return this->callback_(std::forward(args)..., this->closure_); diff --git a/src/quick-lint-js/util/binary-reader.h b/src/quick-lint-js/util/binary-reader.h index 6b721a5ef8..a94c94bd3c 100644 --- a/src/quick-lint-js/util/binary-reader.h +++ b/src/quick-lint-js/util/binary-reader.h @@ -20,9 +20,9 @@ namespace quick_lint_js { // Invariant: When unexpected_end_of_file is called, it does not return. class Checked_Binary_Reader { public: - explicit Checked_Binary_Reader(const std::uint8_t* data, - std::size_t data_size, - Function_Ref unexpected_end_of_file) + explicit Checked_Binary_Reader( + const std::uint8_t* data, std::size_t data_size, + Async_Function_Ref unexpected_end_of_file) : data_(data), data_end_(data + data_size), unexpected_end_of_file_(unexpected_end_of_file) {} @@ -72,7 +72,7 @@ class Checked_Binary_Reader { private: const std::uint8_t* data_; const std::uint8_t* data_end_; - Function_Ref unexpected_end_of_file_; + Async_Function_Ref unexpected_end_of_file_; }; } diff --git a/test/test-debug-server.cpp b/test/test-debug-server.cpp index f3a4397226..34257e363b 100644 --- a/test/test-debug-server.cpp +++ b/test/test-debug-server.cpp @@ -91,7 +91,7 @@ using Trace_Event_Callback = bool(Debug_Server &, // // test_web_socket keeps running until on_trace_event returns false or until a // timeout elapses, whichever comes first. -void test_web_socket(Function_Ref on_trace_event); +void test_web_socket(Async_Function_Ref on_trace_event); class Test_Debug_Server : public ::testing::Test { public: @@ -707,7 +707,7 @@ HTTP_WebSocket_Client::HTTP_WebSocket_Client( HTTP_WebSocket_Client_Delegate *delegate) : delegate_(delegate) {} -void test_web_socket(Function_Ref on_trace_event) { +void test_web_socket(Async_Function_Ref on_trace_event) { std::shared_ptr server = Debug_Server::create(); server->start_server_thread(); auto wait_result = server->wait_for_server_start(); @@ -715,8 +715,9 @@ void test_web_socket(Function_Ref on_trace_event) { class Test_Delegate : public HTTP_WebSocket_Client_Delegate { public: - explicit Test_Delegate(Debug_Server *server, - Function_Ref on_trace_event) + explicit Test_Delegate( + Debug_Server *server, + Async_Function_Ref on_trace_event) : server(server), on_trace_event(on_trace_event) {} void on_message_binary(HTTP_WebSocket_Client *client, const void *message, @@ -752,7 +753,7 @@ void test_web_socket(Function_Ref on_trace_event) { } Debug_Server *server; - Function_Ref on_trace_event; + Async_Function_Ref on_trace_event; std::map trace_readers; }; Test_Delegate delegate(server.get(), on_trace_event); diff --git a/test/test-function-ref.cpp b/test/test-function-ref.cpp index 6742f398b7..f279d4f997 100644 --- a/test/test-function-ref.cpp +++ b/test/test-function-ref.cpp @@ -7,10 +7,10 @@ namespace quick_lint_js { namespace { -TEST(Test_Function_Ref, references_temporary_lambda_with_no_captures) { +TEST(Test_Async_Function_Ref, references_temporary_lambda_with_no_captures) { static int calls; calls = 0; - Function_Ref f([]() -> std::string { + Async_Function_Ref f([]() -> std::string { calls += 1; return "called"; }); @@ -21,14 +21,15 @@ TEST(Test_Function_Ref, references_temporary_lambda_with_no_captures) { EXPECT_EQ(result, "called"); } -TEST(Test_Function_Ref, references_temporary_lambda_lvalue_with_no_captures) { +TEST(Test_Async_Function_Ref, + references_temporary_lambda_lvalue_with_no_captures) { static int calls; calls = 0; auto functor = []() -> std::string { calls += 1; return "called"; }; - Function_Ref f(functor); + Async_Function_Ref f(functor); EXPECT_EQ(calls, 0); std::string result = f(); @@ -36,11 +37,11 @@ TEST(Test_Function_Ref, references_temporary_lambda_lvalue_with_no_captures) { EXPECT_EQ(result, "called"); } -TEST(Test_Function_Ref, +TEST(Test_Async_Function_Ref, converts_implicitly_from_temporary_lambda_with_no_captures) { static int calls; calls = 0; - auto test = [](Function_Ref f) -> void { + auto test = [](Async_Function_Ref f) -> void { EXPECT_EQ(calls, 0); std::string result = f(); EXPECT_EQ(calls, 1); @@ -52,7 +53,8 @@ TEST(Test_Function_Ref, }); } -TEST(Test_Function_Ref, references_lambda_with_captures_if_stack_allocated) { +TEST(Test_Async_Function_Ref, + references_lambda_with_captures_if_stack_allocated) { static int calls; calls = 0; int captured; @@ -60,7 +62,7 @@ TEST(Test_Function_Ref, references_lambda_with_captures_if_stack_allocated) { calls += 1; return captured; }; - Function_Ref f(functor); + Async_Function_Ref f(functor); EXPECT_EQ(calls, 0); captured = 42; @@ -69,7 +71,7 @@ TEST(Test_Function_Ref, references_lambda_with_captures_if_stack_allocated) { EXPECT_EQ(result, 42); } -TEST(Test_Function_Ref, +TEST(Test_Async_Function_Ref, references_const_lambda_with_captures_if_stack_allocated) { static int calls; calls = 0; @@ -78,7 +80,7 @@ TEST(Test_Function_Ref, calls += 1; return captured; }; - Function_Ref f(functor); + Async_Function_Ref f(functor); EXPECT_EQ(calls, 0); captured = 42; @@ -89,9 +91,9 @@ TEST(Test_Function_Ref, // TODO(strager): Test that the following programs do not compile: #if 0 -TEST(Test_Function_Ref, cannot_reference_lambda_rvalue_with_captures) { +TEST(Test_Async_Function_Ref, cannot_reference_lambda_rvalue_with_captures) { int captured = 0; - Function_Ref f([captured]() -> int { + Async_Function_Ref f([captured]() -> int { return captured; }); f(); // Undefined behavior (if the code compiled). From cb92aedf50eaab25b5e2564811a66e45862fbb1b Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 15:01:10 -0400 Subject: [PATCH 031/117] refactor(port): create Temporary_Function_Ref for parameter passing Functions like list_directory_raw are inconvenient to call because the Async_Function_Ref needs to be created from a named lambda. Simplify calls syntactically by creating and using Temporary_Function_Ref. --- src/quick-lint-js/debug/find-debug-server.cpp | 4 +- src/quick-lint-js/io/temporary-directory.cpp | 32 +++++---- src/quick-lint-js/io/temporary-directory.h | 5 +- src/quick-lint-js/port/function-ref.h | 65 +++++++++++++++++++ test/quick-lint-js/filesystem-test.cpp | 4 +- test/test-function-ref.cpp | 52 +++++++++++++++ test/test-temporary-directory.cpp | 12 ++-- tools/test-typescript/main.cpp | 2 +- 8 files changed, 145 insertions(+), 31 deletions(-) diff --git a/src/quick-lint-js/debug/find-debug-server.cpp b/src/quick-lint-js/debug/find-debug-server.cpp index 2dd37ea812..347e34d9e1 100644 --- a/src/quick-lint-js/debug/find-debug-server.cpp +++ b/src/quick-lint-js/debug/find-debug-server.cpp @@ -240,7 +240,7 @@ void enumerate_all_process_thread_names(Callback&& callback) { /*thread_name=*/thread_name); }; Result list_task = - list_directory(path.c_str(), visit_task_entry); + list_directory(path.c_str(), std::move(visit_task_entry)); if (!list_task.ok()) { path.resize(path_size_without_task_id); QLJS_DEBUG_LOG("%s: ignoring failure to read %s: %s\n", func, @@ -248,7 +248,7 @@ void enumerate_all_process_thread_names(Callback&& callback) { } }; Result list_proc = - list_directory(path.c_str(), visit_proc_entry); + list_directory(path.c_str(), std::move(visit_proc_entry)); if (!list_proc.ok()) { QLJS_DEBUG_LOG("%s: ignoring failure to read /proc: %s\n", func, list_proc.error_to_string().c_str()); diff --git a/src/quick-lint-js/io/temporary-directory.cpp b/src/quick-lint-js/io/temporary-directory.cpp index 4638ce4137..7791c263d5 100644 --- a/src/quick-lint-js/io/temporary-directory.cpp +++ b/src/quick-lint-js/io/temporary-directory.cpp @@ -267,7 +267,7 @@ bool is_dot_or_dot_dot(const Char *path) { #if QLJS_HAVE_WINDOWS_H Result list_directory_raw( const char *directory, - Async_Function_Ref visit_entry) { + Temporary_Function_Ref visit_entry) { std::optional search_pattern = mbstring_to_wstring(directory); if (!search_pattern.has_value()) { QLJS_UNIMPLEMENTED(); @@ -299,7 +299,8 @@ Result list_directory_raw( #if QLJS_HAVE_DIRENT_H Result list_directory_raw( - const char *directory, Async_Function_Ref visit_entry) { + const char *directory, + Temporary_Function_Ref visit_entry) { ::DIR *d = ::opendir(directory); if (d == nullptr) { return failed_result(POSIX_File_IO_Error{ @@ -326,9 +327,10 @@ Result list_directory_raw( } Result list_directory( - const char *directory, Async_Function_Ref visit_file) { + const char *directory, + Temporary_Function_Ref visit_file) { #if QLJS_HAVE_WINDOWS_H - auto visit_entry = [&](::WIN32_FIND_DATAW &entry) -> void { + return list_directory_raw(directory, [&](::WIN32_FIND_DATAW &entry) -> void { // TODO(strager): Reduce allocations. std::optional entry_name = wstring_to_mbstring(entry.cFileName); @@ -338,15 +340,13 @@ Result list_directory( if (!is_dot_or_dot_dot(entry_name->c_str())) { visit_file(entry_name->c_str()); } - }; - return list_directory_raw(directory, visit_entry); + }); #elif QLJS_HAVE_DIRENT_H - auto visit_entry = [&](::dirent *entry) -> void { + return list_directory_raw(directory, [&](::dirent *entry) -> void { if (!is_dot_or_dot_dot(entry->d_name)) { visit_file(entry->d_name); } - }; - return list_directory_raw(directory, visit_entry); + }); #else #error "Unsupported platform" #endif @@ -354,9 +354,9 @@ Result list_directory( Result list_directory( const char *directory, - Async_Function_Ref visit_file) { + Temporary_Function_Ref visit_file) { #if QLJS_HAVE_WINDOWS_H - auto visit_entry = [&](::WIN32_FIND_DATAW &entry) -> void { + return list_directory_raw(directory, [&](::WIN32_FIND_DATAW &entry) -> void { // TODO(strager): Reduce allocations. std::optional entry_name = wstring_to_mbstring(entry.cFileName); @@ -368,11 +368,10 @@ Result list_directory( FILE_ATTRIBUTE_DIRECTORY; visit_file(entry_name->c_str(), is_directory); } - }; - return list_directory_raw(directory, visit_entry); + }); #elif QLJS_HAVE_DIRENT_H std::string temp_path; - auto visit_entry = [&](::dirent *entry) -> void { + return list_directory_raw(directory, [&](::dirent *entry) -> void { if (is_dot_or_dot_dot(entry->d_name)) { return; } @@ -396,8 +395,7 @@ Result list_directory( is_directory = entry->d_type == DT_DIR; } visit_file(entry->d_name, is_directory); - }; - return list_directory_raw(directory, visit_entry); + }); #else #error "Unsupported platform" #endif @@ -438,7 +436,7 @@ void list_directory_recursively(const char *directory, // TODO(strager): Reduce allocations on Windows. Windows uses wchar_t // paths and also needs a "\*" suffix. Result list = - list_directory(this->path.c_str(), visit_child); + list_directory(this->path.c_str(), std::move(visit_child)); if (!list.ok()) { this->visitor.on_error(list.error(), depth); } diff --git a/src/quick-lint-js/io/temporary-directory.h b/src/quick-lint-js/io/temporary-directory.h index 1cb6697053..f582822b83 100644 --- a/src/quick-lint-js/io/temporary-directory.h +++ b/src/quick-lint-js/io/temporary-directory.h @@ -44,10 +44,11 @@ Result make_timestamped_directory( // // visit_file is called with the name (not full path) of the child. Result list_directory( - const char* directory, Async_Function_Ref visit_file); + const char* directory, + Temporary_Function_Ref visit_file); Result list_directory( const char* directory, - Async_Function_Ref visit_file); + Temporary_Function_Ref visit_file); QLJS_WARNING_PUSH // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69210 diff --git a/src/quick-lint-js/port/function-ref.h b/src/quick-lint-js/port/function-ref.h index e18f663f26..df27907fe7 100644 --- a/src/quick-lint-js/port/function-ref.h +++ b/src/quick-lint-js/port/function-ref.h @@ -10,12 +10,76 @@ namespace quick_lint_js { template class Async_Function_Ref; +template +class Temporary_Function_Ref; QLJS_WARNING_PUSH QLJS_WARNING_IGNORE_CLANG("-Wcast-qual") QLJS_WARNING_IGNORE_CLANG("-Wold-style-cast") QLJS_WARNING_IGNORE_GCC("-Wconditionally-supported") QLJS_WARNING_IGNORE_GCC("-Wold-style-cast") + +// Temporary_Function_Ref is like std::function_ref +// (https://www.open-std.org/JTC1/SC22/WG21/docs/papers/2022/p0792r10.html). +// +// Deviations from the specification: +// * Our Temporary_Function_Ref does not allow construction from lvalue +// functors. +// +// Temporary_Function_Ref is designed to work with C++ lifetime extension. +// Temporary_Function_Ref is useful for a std::for_each parameter, but not for a +// job queue routine. +template +class Temporary_Function_Ref { + public: + // Construct an Temporary_Function_Ref which will call a function pointer (no + // closure). + // + // This overload is disabled for incoming lvalue references. 'func' must be an + // rvalue. + template + /*implicit*/ Temporary_Function_Ref( + Func&& func, + std::enable_if_t && + !std::is_lvalue_reference_v>* = nullptr) + : callback_(callback), + closure_(reinterpret_cast( + static_cast(func))) {} + + // Construct an Temporary_Function_Ref which will call a functor. + // + // This overload is disabled for incoming lvalue references. 'func' must be an + // rvalue. + // + // This overload is disabled for function pointers and for functors which can + // be converted into a function pointer. + template + /*implicit*/ Temporary_Function_Ref( + Func&& func, + std::enable_if_t && + !std::is_lvalue_reference_v && + !std::is_convertible_v>* = + nullptr) + : callback_(callback>), closure_(&func) {} + + Temporary_Function_Ref(Temporary_Function_Ref& func) = default; + Temporary_Function_Ref(const Temporary_Function_Ref& func) = default; + Temporary_Function_Ref(Temporary_Function_Ref&& func) = default; + + Result operator()(Args... args) { + return this->callback_(std::forward(args)..., this->closure_); + } + + private: + template + static Result callback(Args... args, const void* closure) { + return (*(const Func*)closure)(std::forward(args)...); + } + + Result (*callback_)(Args..., const void*); + const void* closure_; +}; + // Async_Function_Ref is like std::function_ref // (https://www.open-std.org/JTC1/SC22/WG21/docs/papers/2022/p0792r10.html). // @@ -72,6 +136,7 @@ class Async_Function_Ref { Result (*callback_)(Args..., const void*); const void* closure_; }; + QLJS_WARNING_POP } diff --git a/test/quick-lint-js/filesystem-test.cpp b/test/quick-lint-js/filesystem-test.cpp index f71f2aec71..84355a55a6 100644 --- a/test/quick-lint-js/filesystem-test.cpp +++ b/test/quick-lint-js/filesystem-test.cpp @@ -108,9 +108,9 @@ void delete_directory_recursive(const std::string& path) { std::vector list_files_in_directory(const std::string& directory) { std::vector files; - auto visit_file = [&](const char* name) -> void { files.push_back(name); }; Result error = - list_directory(directory.c_str(), visit_file); + list_directory(directory.c_str(), + [&](const char* name) -> void { files.push_back(name); }); if (!error.ok()) { std::fprintf(stderr, "fatal: failed to read directory %s: %s\n", directory.c_str(), std::strerror(errno)); diff --git a/test/test-function-ref.cpp b/test/test-function-ref.cpp index f279d4f997..7e8fd118cf 100644 --- a/test/test-function-ref.cpp +++ b/test/test-function-ref.cpp @@ -99,6 +99,58 @@ TEST(Test_Async_Function_Ref, cannot_reference_lambda_rvalue_with_captures) { f(); // Undefined behavior (if the code compiled). } #endif + +TEST(Test_Temporary_Function_Ref, references_lambda_argument_with_no_captures) { + static int calls; + calls = 0; + auto test = [](Temporary_Function_Ref f) -> void { + EXPECT_EQ(calls, 0); + std::string result = f(); + EXPECT_EQ(calls, 1); + EXPECT_EQ(result, "called"); + }; + test([]() -> std::string { + calls += 1; + return "called"; + }); +} + +TEST(Test_Temporary_Function_Ref, + references_lambda_with_captures_if_stack_allocated) { + static int calls; + calls = 0; + int captured; + auto test = [&captured](Temporary_Function_Ref f) -> void { + EXPECT_EQ(calls, 0); + captured = 42; + int result = f(); + EXPECT_EQ(calls, 1); + EXPECT_EQ(result, 42); + }; + test([&captured]() -> int { + calls += 1; + return captured; + }); +} + +// TODO(strager): Test that the following programs do not compile: +#if 0 +TEST(Test_Temporary_Function_Ref, cannot_reference_lambda_lvalue_with_no_captures) { + int captured = 0; + Temporary_Function_Ref f([]() -> int { + return captured; + }); + f(); // Bug prune. (See cannot_reference_lambda_lvalue_with_captures test.) +} + +TEST(Test_Temporary_Function_Ref, cannot_reference_lambda_lvalue_with_captures) { + int captured = 0; + Temporary_Function_Ref f([captured]() -> int { + return captured; + }); + f(); // Undefined behavior (if the code compiled). +} +#endif } } diff --git a/test/test-temporary-directory.cpp b/test/test-temporary-directory.cpp index 0e495d2cab..3eb50036c9 100644 --- a/test/test-temporary-directory.cpp +++ b/test/test-temporary-directory.cpp @@ -156,11 +156,9 @@ TEST_F(Test_Directory, list_directory) { write_file_or_exit(temp_dir + "/file-3", u8""_sv); std::vector visited_files; - auto visit_file = [&](const char* path) -> void { - visited_files.push_back(path); - }; - Result list = - list_directory(temp_dir.c_str(), visit_file); + Result list = list_directory( + temp_dir.c_str(), + [&](const char* path) -> void { visited_files.push_back(path); }); ASSERT_TRUE(list.ok()) << list.error_to_string(); EXPECT_THAT(visited_files, ::testing::UnorderedElementsAreArray({ @@ -175,9 +173,9 @@ TEST_F(Test_Directory, list_directory_on_regular_file_fails) { std::string temp_dir = this->make_temporary_directory(); write_file_or_exit(temp_dir + "/testfile", u8""_sv); - auto visit_file = [&](const char* path) -> void { ADD_FAILURE() << path; }; Result list = - list_directory((temp_dir + "/testfile").c_str(), visit_file); + list_directory((temp_dir + "/testfile").c_str(), + [&](const char* path) -> void { ADD_FAILURE() << path; }); ASSERT_FALSE(list.ok()); SCOPED_TRACE(list.error_to_string()); EXPECT_TRUE(list.error().is_not_a_directory_error()); diff --git a/tools/test-typescript/main.cpp b/tools/test-typescript/main.cpp index 5268e8da7e..d5b81a860a 100644 --- a/tools/test-typescript/main.cpp +++ b/tools/test-typescript/main.cpp @@ -76,7 +76,7 @@ class Expected_Test_Results { Result list = list_directory( concat(std::string_view(baselines_path), "/baselines/reference/"sv) .c_str(), - visit_entry); + std::move(visit_entry)); if (!list.ok()) { return list.propagate(); } From 53d9fbd16d86661f5dcf38917d01e2774e7c2932 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 15:01:10 -0400 Subject: [PATCH 032/117] refactor(lsp): use Async_Function_Ref instead of Heap_Function for callbacks LSP_Workspace_Configuration stores Heap_Function objects. This feels a tiny bit weird, and the Heap_Function destructor prevents LSP_Workspace_Configuration::items_ from being a Bump_Vector (which does not support non-trivial destructors). Refactor LSP_Workspace_Configuration to use Async_Function_Ref instead. This makes the heap allocation in Linting_LSP_Server_Handler explicit, which is both good (explicit) and bad (verbose). --- .../container/linked-bump-allocator.h | 5 + src/quick-lint-js/lsp/lsp-server.cpp | 50 +++++----- src/quick-lint-js/lsp/lsp-server.h | 3 + .../lsp/lsp-workspace-configuration.cpp | 2 +- .../lsp/lsp-workspace-configuration.h | 6 +- test/test-lsp-workspace-configuration.cpp | 95 ++++++++++--------- 6 files changed, 88 insertions(+), 73 deletions(-) diff --git a/src/quick-lint-js/container/linked-bump-allocator.h b/src/quick-lint-js/container/linked-bump-allocator.h index f40f6f9ac1..4c64d1b38f 100644 --- a/src/quick-lint-js/container/linked-bump-allocator.h +++ b/src/quick-lint-js/container/linked-bump-allocator.h @@ -140,6 +140,11 @@ class Linked_Bump_Allocator : public Memory_Resource { return new (this->allocate_bytes(byte_size)) T(std::forward(args)...); } + template + T* new_object_copy(T&& value) { + return this->new_object(std::forward(value)); + } + template [[nodiscard]] T* allocate_uninitialized_array(std::size_t size) { static_assert(alignof(T) <= alignment, diff --git a/src/quick-lint-js/lsp/lsp-server.cpp b/src/quick-lint-js/lsp/lsp-server.cpp index 3e94d76a91..8346995356 100644 --- a/src/quick-lint-js/lsp/lsp-server.cpp +++ b/src/quick-lint-js/lsp/lsp-server.cpp @@ -125,31 +125,33 @@ Linting_LSP_Server_Handler::Linting_LSP_Server_Handler( this->workspace_configuration_.add_item( u8"quick-lint-js.tracing-directory"_sv, - [this](std::string_view new_value) { - bool changed = this->server_config_.tracing_directory != new_value; - if (changed) { - this->server_config_.tracing_directory = new_value; - if (this->tracer_backend_) { - Trace_Flusher::instance()->disable_backend( - this->tracer_backend_.get()); - this->tracer_backend_.reset(); - } - if (!this->server_config_.tracing_directory.empty()) { - auto new_backend = - Trace_Flusher_Directory_Backend::create_child_directory( - this->server_config_.tracing_directory); - if (new_backend) { - this->tracer_backend_ = - std::make_unique( - std::move(*new_backend)); - Trace_Flusher::instance()->enable_backend( - this->tracer_backend_.get()); - QLJS_DEBUG_LOG("enabled tracing in directory %s\n", - this->tracer_backend_->trace_directory().c_str()); + *this->workspace_configuration_allocator_.new_object_copy( + [this](std::string_view new_value) -> void { + bool changed = this->server_config_.tracing_directory != new_value; + if (changed) { + this->server_config_.tracing_directory = new_value; + if (this->tracer_backend_) { + Trace_Flusher::instance()->disable_backend( + this->tracer_backend_.get()); + this->tracer_backend_.reset(); + } + if (!this->server_config_.tracing_directory.empty()) { + auto new_backend = + Trace_Flusher_Directory_Backend::create_child_directory( + this->server_config_.tracing_directory); + if (new_backend) { + this->tracer_backend_ = + std::make_unique( + std::move(*new_backend)); + Trace_Flusher::instance()->enable_backend( + this->tracer_backend_.get()); + QLJS_DEBUG_LOG( + "enabled tracing in directory %s\n", + this->tracer_backend_->trace_directory().c_str()); + } + } } - } - } - }); + })); } void Linting_LSP_Server_Handler::handle_request( diff --git a/src/quick-lint-js/lsp/lsp-server.h b/src/quick-lint-js/lsp/lsp-server.h index b7bcf66172..d69c8a88e4 100644 --- a/src/quick-lint-js/lsp/lsp-server.h +++ b/src/quick-lint-js/lsp/lsp-server.h @@ -242,6 +242,9 @@ class Linting_LSP_Server_Handler final : public JSON_RPC_Message_Handler { bool did_report_watch_io_error_ = false; bool shutdown_requested_ = false; + Monotonic_Allocator workspace_configuration_allocator_{ + "Linting_LSP_Server_Handler::workspace_configuration_allocator_"}; + friend class LSP_Linter; friend struct LSP_Documents::Config_Document; friend struct LSP_Documents::Lintable_Document; diff --git a/src/quick-lint-js/lsp/lsp-workspace-configuration.cpp b/src/quick-lint-js/lsp/lsp-workspace-configuration.cpp index ea8ca177e6..ec4aebbc81 100644 --- a/src/quick-lint-js/lsp/lsp-workspace-configuration.cpp +++ b/src/quick-lint-js/lsp/lsp-workspace-configuration.cpp @@ -18,7 +18,7 @@ using namespace std::literals::string_view_literals; namespace quick_lint_js { void LSP_Workspace_Configuration::add_item( - String8_View name, Heap_Function&& callback) { + String8_View name, Async_Function_Ref callback) { this->items_.push_back(Item{ .name = name, .callback = std::move(callback), diff --git a/src/quick-lint-js/lsp/lsp-workspace-configuration.h b/src/quick-lint-js/lsp/lsp-workspace-configuration.h index b05f2dda99..1fa469fec6 100644 --- a/src/quick-lint-js/lsp/lsp-workspace-configuration.h +++ b/src/quick-lint-js/lsp/lsp-workspace-configuration.h @@ -7,9 +7,9 @@ // No LSP on the web. #else -#include #include #include +#include #include #include #include @@ -28,7 +28,7 @@ class LSP_Workspace_Configuration { // name must be have global lifetime (e.g. be a compile-time string). // name must be a JSON-encoded string (without surrounding quotation marks). void add_item(String8_View name, - Heap_Function&& callback); + Async_Function_Ref callback); // Create a workspace/configuration JSON-RPC request to send to the LSP // client. @@ -52,7 +52,7 @@ class LSP_Workspace_Configuration { private: struct Item { String8_View name; - Heap_Function callback; + Async_Function_Ref callback; }; Item* find_item(String8_View name); diff --git a/test/test-lsp-workspace-configuration.cpp b/test/test-lsp-workspace-configuration.cpp index 5080ff7e0a..2491181d9d 100644 --- a/test/test-lsp-workspace-configuration.cpp +++ b/test/test-lsp-workspace-configuration.cpp @@ -87,15 +87,18 @@ TEST(Test_LSP_Workspace_Configuration, empty_config_response) { TEST(Test_LSP_Workspace_Configuration, config_response_with_strings) { std::string items[3]; LSP_Workspace_Configuration config; - config.add_item(u8"first"_sv, [&items](std::string_view new_value) { + auto first_callback = [&items](std::string_view new_value) { items[0] = new_value; - }); - config.add_item(u8"second"_sv, [&items](std::string_view new_value) { + }; + config.add_item(u8"first"_sv, first_callback); + auto second_callback = [&items](std::string_view new_value) { items[1] = new_value; - }); - config.add_item(u8"third"_sv, [&items](std::string_view new_value) { + }; + config.add_item(u8"second"_sv, second_callback); + auto third_callback = [&items](std::string_view new_value) { items[2] = new_value; - }); + }; + config.add_item(u8"third"_sv, third_callback); Easy_SIMDJSON_Parser result( R"(["firstval", "secondval", "thirdval"])"_padded); @@ -112,12 +115,12 @@ TEST(Test_LSP_Workspace_Configuration, empty_config_response_with_added_items_fails) { LSP_Workspace_Configuration config; bool myitem_callback_called = false; - config.add_item(u8"myitem"_sv, [&myitem_callback_called]( - std::string_view new_value) { + auto myitem_callback = [&myitem_callback_called](std::string_view new_value) { myitem_callback_called = true; ADD_FAILURE() << "myitem callback should not have been called; new_value=" << new_value; - }); + }; + config.add_item(u8"myitem"_sv, myitem_callback); Easy_SIMDJSON_Parser result("[]"_padded); ASSERT_EQ(result.error, ::simdjson::SUCCESS); @@ -131,11 +134,11 @@ TEST(Test_LSP_Workspace_Configuration, more_values_than_config_fails_but_calls_callback_anyway) { LSP_Workspace_Configuration config; bool myitem_callback_called = false; - config.add_item(u8"myitem"_sv, - [&myitem_callback_called](std::string_view new_value) { - myitem_callback_called = true; - EXPECT_EQ(new_value, "val"); - }); + auto myitem_callback = [&myitem_callback_called](std::string_view new_value) { + myitem_callback_called = true; + EXPECT_EQ(new_value, "val"); + }; + config.add_item(u8"myitem"_sv, myitem_callback); Easy_SIMDJSON_Parser result(R"(["val", "otherval"])"_padded); ASSERT_EQ(result.error, ::simdjson::SUCCESS); @@ -148,11 +151,11 @@ TEST(Test_LSP_Workspace_Configuration, TEST(Test_LSP_Workspace_Configuration, null_is_coerced_to_empty_string) { LSP_Workspace_Configuration config; bool myitem_callback_called = false; - config.add_item(u8"myitem"_sv, - [&myitem_callback_called](std::string_view new_value) { - myitem_callback_called = true; - EXPECT_EQ(new_value, ""); - }); + auto myitem_callback = [&myitem_callback_called](std::string_view new_value) { + myitem_callback_called = true; + EXPECT_EQ(new_value, ""); + }; + config.add_item(u8"myitem"_sv, myitem_callback); Easy_SIMDJSON_Parser result(R"([null])"_padded); ASSERT_EQ(result.error, ::simdjson::SUCCESS); @@ -184,11 +187,11 @@ TEST(Test_LSP_Workspace_Configuration, config_notification_calls_item_callbacks) { LSP_Workspace_Configuration config; bool myitem_callback_called = false; - config.add_item(u8"myitem"_sv, - [&myitem_callback_called](std::string_view new_value) { - myitem_callback_called = true; - EXPECT_EQ(new_value, "hello"); - }); + auto myitem_callback = [&myitem_callback_called](std::string_view new_value) { + myitem_callback_called = true; + EXPECT_EQ(new_value, "hello"); + }; + config.add_item(u8"myitem"_sv, myitem_callback); Easy_SIMDJSON_Parser result(R"({"myitem": "hello"})"_padded); ASSERT_EQ(result.error, ::simdjson::SUCCESS); @@ -202,11 +205,12 @@ TEST(Test_LSP_Workspace_Configuration, config_notification_ignores_extra_entries) { LSP_Workspace_Configuration config; int myitem_callback_called_count = 0; - config.add_item(u8"myitem"_sv, - [&myitem_callback_called_count](std::string_view new_value) { - myitem_callback_called_count += 1; - EXPECT_EQ(new_value, "hello"); - }); + auto myitem_callback = + [&myitem_callback_called_count](std::string_view new_value) { + myitem_callback_called_count += 1; + EXPECT_EQ(new_value, "hello"); + }; + config.add_item(u8"myitem"_sv, myitem_callback); Easy_SIMDJSON_Parser result( R"({"myitem": "hello", "extraitem": "hi"})"_padded); @@ -221,12 +225,12 @@ TEST(Test_LSP_Workspace_Configuration, config_notification_does_not_call_callback_for_unnotified_items) { LSP_Workspace_Configuration config; bool myitem_callback_called = false; - config.add_item(u8"myitem"_sv, [&myitem_callback_called]( - std::string_view new_value) { + auto myitem_callback = [&myitem_callback_called](std::string_view new_value) { myitem_callback_called = true; ADD_FAILURE() << "myitem callback should not have been called; new_value=" << new_value; - }); + }; + config.add_item(u8"myitem"_sv, myitem_callback); Easy_SIMDJSON_Parser result(R"({})"_padded); ASSERT_EQ(result.error, ::simdjson::SUCCESS); @@ -240,11 +244,11 @@ TEST(Test_LSP_Workspace_Configuration, initialization_options_calls_item_callbacks) { LSP_Workspace_Configuration config; bool myitem_callback_called = false; - config.add_item(u8"mysection.myitem"_sv, - [&myitem_callback_called](std::string_view new_value) { - myitem_callback_called = true; - EXPECT_EQ(new_value, "hello"); - }); + auto myitem_callback = [&myitem_callback_called](std::string_view new_value) { + myitem_callback_called = true; + EXPECT_EQ(new_value, "hello"); + }; + config.add_item(u8"mysection.myitem"_sv, myitem_callback); Easy_SIMDJSON_Parser result(R"({"mysection.myitem": "hello"})"_padded); ASSERT_EQ(result.error, ::simdjson::SUCCESS); @@ -258,11 +262,12 @@ TEST(Test_LSP_Workspace_Configuration, initialization_options_ignores_extra_entries) { LSP_Workspace_Configuration config; int myitem_callback_called_count = 0; - config.add_item(u8"mysection.myitem"_sv, - [&myitem_callback_called_count](std::string_view new_value) { - myitem_callback_called_count += 1; - EXPECT_EQ(new_value, "hello"); - }); + auto myitem_callback = + [&myitem_callback_called_count](std::string_view new_value) { + myitem_callback_called_count += 1; + EXPECT_EQ(new_value, "hello"); + }; + config.add_item(u8"mysection.myitem"_sv, myitem_callback); Easy_SIMDJSON_Parser result( R"({"mysection.myitem": "hello", "mysection.extraitem": "hi"})"_padded); @@ -277,13 +282,13 @@ TEST(Test_LSP_Workspace_Configuration, initialization_options_does_not_call_callback_for_unnotified_items) { LSP_Workspace_Configuration config; bool myitem_callback_called = false; - config.add_item(u8"mysection.myitem"_sv, [&myitem_callback_called]( - std::string_view new_value) { + auto myitem_callback = [&myitem_callback_called](std::string_view new_value) { myitem_callback_called = true; ADD_FAILURE() << "mysection.myitem callback should not have been called; new_value=" << new_value; - }); + }; + config.add_item(u8"mysection.myitem"_sv, myitem_callback); Easy_SIMDJSON_Parser result(R"({})"_padded); ASSERT_EQ(result.error, ::simdjson::SUCCESS); From cd7f3350b715c5280d74cd5866a66ffdb1cbf21c Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 15:20:15 -0400 Subject: [PATCH 033/117] refactor(test): use Async_Function_Ref instead of Heap_Function for callbacks Fake_Configuration_Filesystem is one of the the only users of Heap_Function. I don't want to maintain Heap_Function, so make Fake_Configuration_Filesystem use Async_Function_Ref instead. The interface is slightly more clunky, but I think the change is worth it. --- src/quick-lint-js/port/function-ref.h | 3 ++ .../fake-configuration-filesystem.cpp | 20 +++++++++---- .../fake-configuration-filesystem.h | 6 ++-- test/test-lsp-server.cpp | 30 ++++++++++--------- 4 files changed, 37 insertions(+), 22 deletions(-) diff --git a/src/quick-lint-js/port/function-ref.h b/src/quick-lint-js/port/function-ref.h index df27907fe7..f80ee90878 100644 --- a/src/quick-lint-js/port/function-ref.h +++ b/src/quick-lint-js/port/function-ref.h @@ -123,6 +123,9 @@ class Async_Function_Ref { Async_Function_Ref(const Async_Function_Ref& func) = default; Async_Function_Ref(Async_Function_Ref&& func) = default; + Async_Function_Ref& operator=(const Async_Function_Ref&) = default; + Async_Function_Ref& operator=(Async_Function_Ref&&) = default; + Result operator()(Args... args) { return this->callback_(std::forward(args)..., this->closure_); } diff --git a/test/quick-lint-js/fake-configuration-filesystem.cpp b/test/quick-lint-js/fake-configuration-filesystem.cpp index 21ef482a52..409f13c21f 100644 --- a/test/quick-lint-js/fake-configuration-filesystem.cpp +++ b/test/quick-lint-js/fake-configuration-filesystem.cpp @@ -5,6 +5,7 @@ // No filesystem on the web. #else +#include #include #include #include @@ -24,15 +25,22 @@ Fake_Configuration_Filesystem::~Fake_Configuration_Filesystem() = default; void Fake_Configuration_Filesystem::create_file(const Canonical_Path& path, String8_View content) { - this->files_.insert_or_assign( - path, [content_string = String8(content)]() -> Read_File_Result { - return Padded_String(String8_View(content_string)); - }); + Span content_copy = + this->allocator_.allocate_uninitialized_span(content.size()); + std::uninitialized_copy(content.begin(), content.end(), content_copy.data()); + String8_View content_copy_view(content_copy.data(), + narrow_cast(content_copy.size())); + this->files_.insert_or_assign(path, + *this->allocator_.new_object_copy( + [content_copy_view]() -> Read_File_Result { + return Padded_String(content_copy_view); + })); } void Fake_Configuration_Filesystem::create_file( - const Canonical_Path& path, Heap_Function callback) { - this->files_.insert_or_assign(path, std::move(callback)); + const Canonical_Path& path, + Async_Function_Ref callback) { + this->files_.insert_or_assign(path, callback); } Canonical_Path Fake_Configuration_Filesystem::rooted(const char* path) const { diff --git a/test/quick-lint-js/fake-configuration-filesystem.h b/test/quick-lint-js/fake-configuration-filesystem.h index d3a0e0e0d9..4781bf5487 100644 --- a/test/quick-lint-js/fake-configuration-filesystem.h +++ b/test/quick-lint-js/fake-configuration-filesystem.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -29,7 +30,7 @@ class Fake_Configuration_Filesystem : public Configuration_Filesystem { // Create a new file, or modify an existing file. void create_file(const Canonical_Path& path, String8_View content); void create_file(const Canonical_Path& path, - Heap_Function callback); + Async_Function_Ref callback); Canonical_Path rooted(const char* path) const; @@ -44,7 +45,8 @@ class Fake_Configuration_Filesystem : public Configuration_Filesystem { void clear(); private: - Hash_Map> files_; + Monotonic_Allocator allocator_{"Fake_Configuration_Filesystem"}; + Hash_Map> files_; }; } diff --git a/test/test-lsp-server.cpp b/test/test-lsp-server.cpp index e07e63880b..401ee28e4b 100644 --- a/test/test-lsp-server.cpp +++ b/test/test-lsp-server.cpp @@ -1825,14 +1825,15 @@ TEST_F(Test_Linting_LSP_Server, } TEST_F(Test_Linting_LSP_Server, opening_js_file_with_unreadable_config_lints) { - this->fs.create_file( - this->fs.rooted("quick-lint-js.config"), + auto failing_read_file_callback = [this]() -> Fake_Configuration_Filesystem::Read_File_Result { - return failed_result(Read_File_IO_Error{ - .path = this->fs.rooted("quick-lint-js.config").path(), - .io_error = generic_file_io_error, - }); - }); + return failed_result(Read_File_IO_Error{ + .path = this->fs.rooted("quick-lint-js.config").path(), + .io_error = generic_file_io_error, + }); + }; + this->fs.create_file(this->fs.rooted("quick-lint-js.config"), + failing_read_file_callback); this->lint_callback = [&](Configuration& config, Linter_Options, Padded_String_View, String8_View uri_json, String8_View version_json, @@ -1977,14 +1978,15 @@ TEST_F(Test_Linting_LSP_Server, making_config_file_unreadable_relints) { } })"_sv))); - this->fs.create_file( - this->fs.rooted("quick-lint-js.config"), + auto failing_read_file_callback = [this]() -> Fake_Configuration_Filesystem::Read_File_Result { - return failed_result(Read_File_IO_Error{ - .path = this->fs.rooted("quick-lint-js.config").path(), - .io_error = generic_file_io_error, - }); - }); + return failed_result(Read_File_IO_Error{ + .path = this->fs.rooted("quick-lint-js.config").path(), + .io_error = generic_file_io_error, + }); + }; + this->fs.create_file(this->fs.rooted("quick-lint-js.config"), + failing_read_file_callback); this->lint_callback = [&](Configuration& config, Linter_Options, Padded_String_View, String8_View uri_json, String8_View version_json, From b678a2b9bf356123354c23ce4aa2cc6a73460795 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 15:01:10 -0400 Subject: [PATCH 034/117] refactor(test): use Async_Function_Ref instead of Heap_Function for callbacks Mock_LSP_Linter is one of the the only users of Heap_Function. I don't want to maintain Heap_Function, so make Mock_LSP_Linter use Async_Function_Ref instead. The interface is slightly more clunky, but I think the change is worth it. To make the refactoring easier, hoist Test_Linting_LSP_Server::lint_calls into Mock_LSP_Linter, but leave Test_Linting_LSP_Server::lint_calls as a reference to reduce code churn in callers. --- test/test-lsp-server.cpp | 365 ++++++++++++++++++++------------------- 1 file changed, 185 insertions(+), 180 deletions(-) diff --git a/test/test-lsp-server.cpp b/test/test-lsp-server.cpp index 401ee28e4b..639d60f5e2 100644 --- a/test/test-lsp-server.cpp +++ b/test/test-lsp-server.cpp @@ -58,11 +58,12 @@ class Mock_LSP_Linter final : public LSP_Linter { String8_View uri_json, String8_View version_json, Outgoing_JSON_RPC_Message_Queue& outgoing_messages); - explicit Mock_LSP_Linter() = default; - - explicit Mock_LSP_Linter( - Heap_Function callback) - : callback_(std::move(callback)) {} + explicit Mock_LSP_Linter() + : lint_callback([](Configuration&, Linter_Options, Padded_String_View, + String8_View, String8_View, + Outgoing_JSON_RPC_Message_Queue&) -> void { + // Do nothing. + }) {} Mock_LSP_Linter(Mock_LSP_Linter&&) = default; Mock_LSP_Linter& operator=(Mock_LSP_Linter&&) = default; @@ -73,12 +74,13 @@ class Mock_LSP_Linter final : public LSP_Linter { Padded_String_View code, String8_View uri_json, String8_View version_json, Outgoing_JSON_RPC_Message_Queue& outgoing_messages) override { - this->callback_(config, lint_options, code, uri_json, version_json, - outgoing_messages); + this->lint_calls.emplace_back(code.string_view()); + this->lint_callback(config, lint_options, code, uri_json, version_json, + outgoing_messages); } - private: - Heap_Function callback_; + std::vector lint_calls; + Async_Function_Ref lint_callback; }; class Test_Linting_LSP_Server : public ::testing::Test, public Filesystem_Test { @@ -86,20 +88,9 @@ class Test_Linting_LSP_Server : public ::testing::Test, public Filesystem_Test { explicit Test_Linting_LSP_Server() { this->reset(); } void reset() { - this->lint_callback = {}; this->lint_calls.clear(); this->fs.clear(); - this->linter = Mock_LSP_Linter( - [this](Configuration& config, Linter_Options lint_options, - Padded_String_View code, String8_View uri_json, - String8_View version_json, - Outgoing_JSON_RPC_Message_Queue& outgoing_messages) { - this->lint_calls.emplace_back(code.string_view()); - if (this->lint_callback) { - this->lint_callback(config, lint_options, code, uri_json, - version_json, outgoing_messages); - } - }); + this->linter = Mock_LSP_Linter(); this->handler = std::make_unique(&this->fs, &this->linter); this->client = std::make_unique(); @@ -107,12 +98,6 @@ class Test_Linting_LSP_Server : public ::testing::Test, public Filesystem_Test { std::make_unique(this->handler.get()); } - Heap_Function - lint_callback; - std::vector lint_calls; - Fake_Configuration_Filesystem fs; Mock_LSP_Linter linter; @@ -120,6 +105,8 @@ class Test_Linting_LSP_Server : public ::testing::Test, public Filesystem_Test { std::unique_ptr client; std::unique_ptr server; + std::vector& lint_calls = linter.lint_calls; + std::string config_file_load_error_message(const char* js_path, const char* error_path) { return concat("Failed to load configuration file for "sv, @@ -543,17 +530,17 @@ TEST_F(Test_Linting_LSP_Server, dollar_notifications_are_ignored) { } TEST_F(Test_Linting_LSP_Server, opening_document_lints) { - this->lint_callback = - [&](Configuration&, Linter_Options, Padded_String_View code, - String8_View uri_json, String8_View version, - Outgoing_JSON_RPC_Message_Queue& outgoing_messages) { - EXPECT_EQ(code, u8"let x = x;"_sv); - EXPECT_EQ(uri_json, u8"\"file:///test.js\""_sv); - EXPECT_EQ(version, u8"10"_sv); - - Byte_Buffer& notification_json = outgoing_messages.new_message(); - notification_json.append_copy( - u8R"--( + auto lint_callback = [&](Configuration&, Linter_Options, + Padded_String_View code, String8_View uri_json, + String8_View version, + Outgoing_JSON_RPC_Message_Queue& outgoing_messages) { + EXPECT_EQ(code, u8"let x = x;"_sv); + EXPECT_EQ(uri_json, u8"\"file:///test.js\""_sv); + EXPECT_EQ(version, u8"10"_sv); + + Byte_Buffer& notification_json = outgoing_messages.new_message(); + notification_json.append_copy( + u8R"--( { "method":"textDocument/publishDiagnostics", "params":{ @@ -573,7 +560,8 @@ TEST_F(Test_Linting_LSP_Server, opening_document_lints) { "jsonrpc":"2.0" } )--"_sv); - }; + }; + this->linter.lint_callback = lint_callback; this->server->append( make_message(u8R"({ @@ -618,12 +606,13 @@ TEST_F(Test_Linting_LSP_Server, javascript_language_ids_enable_jsx) { SCOPED_TRACE(out_string8(language_id)); this->reset(); - this->lint_callback = [&](Configuration&, Linter_Options lint_options, - Padded_String_View, String8_View, String8_View, - Outgoing_JSON_RPC_Message_Queue&) { + auto lint_callback = [&](Configuration&, Linter_Options lint_options, + Padded_String_View, String8_View, String8_View, + Outgoing_JSON_RPC_Message_Queue&) { EXPECT_TRUE(lint_options.jsx); EXPECT_FALSE(lint_options.typescript); }; + this->linter.lint_callback = lint_callback; this->server->append( make_message(concat(u8R"({ @@ -649,12 +638,13 @@ TEST_F(Test_Linting_LSP_Server, typescript_language_ids_enable_typescript) { SCOPED_TRACE(out_string8(language_id)); this->reset(); - this->lint_callback = [&](Configuration&, Linter_Options lint_options, - Padded_String_View, String8_View, String8_View, - Outgoing_JSON_RPC_Message_Queue&) { + auto lint_callback = [&](Configuration&, Linter_Options lint_options, + Padded_String_View, String8_View, String8_View, + Outgoing_JSON_RPC_Message_Queue&) { EXPECT_TRUE(lint_options.typescript); EXPECT_FALSE(lint_options.jsx); }; + this->linter.lint_callback = lint_callback; this->server->append( make_message(concat(u8R"({ @@ -680,12 +670,13 @@ TEST_F(Test_Linting_LSP_Server, tsx_language_ids_enable_typescript_jsx) { SCOPED_TRACE(out_string8(language_id)); this->reset(); - this->lint_callback = [&](Configuration&, Linter_Options lint_options, - Padded_String_View, String8_View, String8_View, - Outgoing_JSON_RPC_Message_Queue&) { + auto lint_callback = [&](Configuration&, Linter_Options lint_options, + Padded_String_View, String8_View, String8_View, + Outgoing_JSON_RPC_Message_Queue&) { EXPECT_TRUE(lint_options.typescript); EXPECT_TRUE(lint_options.jsx); }; + this->linter.lint_callback = lint_callback; this->server->append( make_message(concat(u8R"({ @@ -855,11 +846,12 @@ TEST_F(Test_Linting_LSP_Server, linting_uses_config_from_file) { this->fs.create_file(this->fs.rooted("quick-lint-js.config"), u8R"({"globals": {"testGlobalVariable": true}})"_sv); - this->lint_callback = [&](Configuration& config, Linter_Options, - Padded_String_View, String8_View, String8_View, - Outgoing_JSON_RPC_Message_Queue&) { + auto lint_callback = [&](Configuration& config, Linter_Options, + Padded_String_View, String8_View, String8_View, + Outgoing_JSON_RPC_Message_Queue&) { EXPECT_TRUE(config.globals().find(u8"testGlobalVariable"_sv)); }; + this->linter.lint_callback = lint_callback; this->server->append( make_message(concat(u8R"({ @@ -942,12 +934,13 @@ TEST_F( })"_sv))); this->lint_calls.clear(); - this->lint_callback = [&](Configuration& config, Linter_Options, - Padded_String_View, String8_View, String8_View, - Outgoing_JSON_RPC_Message_Queue&) { + auto lint_callback = [&](Configuration& config, Linter_Options, + Padded_String_View, String8_View, String8_View, + Outgoing_JSON_RPC_Message_Queue&) { EXPECT_FALSE(config.globals().find(u8"testGlobalVariableBefore"_sv)); EXPECT_TRUE(config.globals().find(u8"testGlobalVariableAfter"_sv)); }; + this->linter.lint_callback = lint_callback; this->server->append( make_message(concat(u8R"({ "jsonrpc": "2.0", @@ -975,11 +968,12 @@ TEST_F(Test_Linting_LSP_Server, this->fs.create_file(this->fs.rooted("a%b~/quick-lint-js.config"), u8R"({"globals": {"testGlobalVariable": true}})"_sv); - this->lint_callback = [&](Configuration& config, Linter_Options, - Padded_String_View, String8_View, String8_View, - Outgoing_JSON_RPC_Message_Queue&) { + auto lint_callback = [&](Configuration& config, Linter_Options, + Padded_String_View, String8_View, String8_View, + Outgoing_JSON_RPC_Message_Queue&) { EXPECT_TRUE(config.globals().find(u8"testGlobalVariable"_sv)); }; + this->linter.lint_callback = lint_callback; this->server->append( make_message(concat(u8R"({ @@ -1001,11 +995,12 @@ TEST_F(Test_Linting_LSP_Server, } TEST_F(Test_Linting_LSP_Server, linting_uses_already_opened_config_file) { - this->lint_callback = [&](Configuration& config, Linter_Options, - Padded_String_View, String8_View, String8_View, - Outgoing_JSON_RPC_Message_Queue&) { + auto lint_callback = [&](Configuration& config, Linter_Options, + Padded_String_View, String8_View, String8_View, + Outgoing_JSON_RPC_Message_Queue&) { EXPECT_TRUE(config.globals().find(u8"modified"_sv)); }; + this->linter.lint_callback = lint_callback; this->fs.create_file(this->fs.rooted("quick-lint-js.config"), u8R"({"globals": {"modified": false}})"_sv); @@ -1045,12 +1040,13 @@ TEST_F(Test_Linting_LSP_Server, linting_uses_already_opened_config_file) { TEST_F(Test_Linting_LSP_Server, linting_uses_already_opened_shadowing_config_file) { - this->lint_callback = [&](Configuration& config, Linter_Options, - Padded_String_View, String8_View, String8_View, - Outgoing_JSON_RPC_Message_Queue&) { + auto lint_callback = [&](Configuration& config, Linter_Options, + Padded_String_View, String8_View, String8_View, + Outgoing_JSON_RPC_Message_Queue&) { EXPECT_TRUE(config.globals().find(u8"haveInnerConfig"_sv)); EXPECT_FALSE(config.globals().find(u8"haveOuterConfig"_sv)); }; + this->linter.lint_callback = lint_callback; this->fs.create_file(this->fs.rooted("quick-lint-js.config"), u8R"({"globals": {"haveOuterConfig": false}})"_sv); @@ -1091,10 +1087,10 @@ TEST_F(Test_Linting_LSP_Server, TEST_F(Test_Linting_LSP_Server, editing_config_relints_open_js_file) { bool after_config_was_loaded = false; - this->lint_callback = [&](Configuration& config, Linter_Options, - Padded_String_View, String8_View uri_json, - String8_View version_json, - Outgoing_JSON_RPC_Message_Queue&) { + auto lint_callback = [&](Configuration& config, Linter_Options, + Padded_String_View, String8_View uri_json, + String8_View version_json, + Outgoing_JSON_RPC_Message_Queue&) { if (config.globals().find(u8"after"_sv)) { EXPECT_FALSE(config.globals().find(u8"before"_sv)); EXPECT_EQ(version_json, u8"10"_sv); @@ -1103,6 +1099,7 @@ TEST_F(Test_Linting_LSP_Server, editing_config_relints_open_js_file) { after_config_was_loaded = true; } }; + this->linter.lint_callback = lint_callback; this->fs.create_file(this->fs.rooted("quick-lint-js.config"), u8R"({"globals": {"before": true}})"_sv); @@ -1220,11 +1217,12 @@ TEST_F(Test_Linting_LSP_Server, } })"_sv))); - this->lint_callback = [&](Configuration&, Linter_Options, Padded_String_View, - String8_View, String8_View version_json, - Outgoing_JSON_RPC_Message_Queue&) { + auto lint_callback = [&](Configuration&, Linter_Options, Padded_String_View, + String8_View, String8_View version_json, + Outgoing_JSON_RPC_Message_Queue&) { EXPECT_EQ(version_json, u8"11"_sv); }; + this->linter.lint_callback = lint_callback; this->lint_calls.clear(); // Change 'before' to 'after'. @@ -1255,28 +1253,28 @@ TEST_F(Test_Linting_LSP_Server, } TEST_F(Test_Linting_LSP_Server, editing_config_relints_many_open_js_files) { - this->lint_callback = - [&](Configuration&, Linter_Options, Padded_String_View, - String8_View uri_json, String8_View version_json, - Outgoing_JSON_RPC_Message_Queue& outgoing_messages) { - Byte_Buffer& notification_json = outgoing_messages.new_message(); - notification_json.append_copy( - concat(u8R"( + auto lint_callback = [&](Configuration&, Linter_Options, Padded_String_View, + String8_View uri_json, String8_View version_json, + Outgoing_JSON_RPC_Message_Queue& outgoing_messages) { + Byte_Buffer& notification_json = outgoing_messages.new_message(); + notification_json.append_copy( + concat(u8R"( { "method": "textDocument/publishDiagnostics", "params":{ "uri": )"_sv, - uri_json, - u8R"(, + uri_json, + u8R"(, "version": )"_sv, - version_json, - u8R"(, + version_json, + u8R"(, "diagnostics": [] }, "jsonrpc":"2.0" } )"_sv)); - }; + }; + this->linter.lint_callback = lint_callback; this->fs.create_file(this->fs.rooted("quick-lint-js.config"), u8R"({"globals": {"before": true}})"_sv); @@ -1369,28 +1367,28 @@ TEST_F(Test_Linting_LSP_Server, editing_config_relints_many_open_js_files) { } TEST_F(Test_Linting_LSP_Server, editing_config_relints_only_affected_js_files) { - this->lint_callback = - [&](Configuration&, Linter_Options, Padded_String_View, - String8_View uri_json, String8_View version_json, - Outgoing_JSON_RPC_Message_Queue& outgoing_messages) { - Byte_Buffer& notification_json = outgoing_messages.new_message(); - notification_json.append_copy( - concat(u8R"( + auto lint_callback = [&](Configuration&, Linter_Options, Padded_String_View, + String8_View uri_json, String8_View version_json, + Outgoing_JSON_RPC_Message_Queue& outgoing_messages) { + Byte_Buffer& notification_json = outgoing_messages.new_message(); + notification_json.append_copy( + concat(u8R"( { "method": "textDocument/publishDiagnostics", "params":{ "uri": )"_sv, - uri_json, - u8R"(, + uri_json, + u8R"(, "version": )"_sv, - version_json, - u8R"(, + version_json, + u8R"(, "diagnostics": [] }, "jsonrpc":"2.0" } )"_sv)); - }; + }; + this->linter.lint_callback = lint_callback; this->server->append( make_message(concat(u8R"({ @@ -1548,14 +1546,15 @@ TEST_F(Test_Linting_LSP_Server, })"_sv))); this->lint_calls.clear(); - this->lint_callback = [&](Configuration& config, Linter_Options, - Padded_String_View, String8_View, - String8_View version_json, - Outgoing_JSON_RPC_Message_Queue&) { + auto lint_callback = [&](Configuration& config, Linter_Options, + Padded_String_View, String8_View, + String8_View version_json, + Outgoing_JSON_RPC_Message_Queue&) { EXPECT_EQ(version_json, u8"11"_sv); EXPECT_FALSE(config.globals().find(u8"before"_sv)); EXPECT_TRUE(config.globals().find(u8"after"_sv)); }; + this->linter.lint_callback = lint_callback; this->server->append( make_message(concat(u8R"({ @@ -1582,10 +1581,10 @@ TEST_F(Test_Linting_LSP_Server, TEST_F(Test_Linting_LSP_Server, opening_config_relints_open_js_files) { bool after_config_was_loaded = false; - this->lint_callback = [&](Configuration& config, Linter_Options, - Padded_String_View, String8_View uri_json, - String8_View version_json, - Outgoing_JSON_RPC_Message_Queue&) { + auto lint_callback = [&](Configuration& config, Linter_Options, + Padded_String_View, String8_View uri_json, + String8_View version_json, + Outgoing_JSON_RPC_Message_Queue&) { if (config.globals().find(u8"after"_sv)) { EXPECT_FALSE(config.globals().find(u8"before"_sv)); EXPECT_EQ(version_json, u8"10"_sv); @@ -1594,6 +1593,7 @@ TEST_F(Test_Linting_LSP_Server, opening_config_relints_open_js_files) { after_config_was_loaded = true; } }; + this->linter.lint_callback = lint_callback; this->fs.create_file(this->fs.rooted("quick-lint-js.config"), u8R"({"globals": {"before": true}})"_sv); @@ -1652,31 +1652,32 @@ TEST_F(Test_Linting_LSP_Server, })"_sv))); bool after_config_was_loaded = false; - this->lint_callback = - [&](Configuration& config, Linter_Options, Padded_String_View, - String8_View uri_json, String8_View version_json, - Outgoing_JSON_RPC_Message_Queue& outgoing_messages) { - EXPECT_TRUE(config.globals().find(u8"after"_sv)); - EXPECT_FALSE(config.globals().find(u8"before"_sv)); - EXPECT_EQ(version_json, u8"10"_sv); - EXPECT_EQ(uri_json, concat(u8"\""_sv, this->fs.file_uri_prefix_8(), - u8"test.js\""_sv)); - after_config_was_loaded = true; - - Byte_Buffer& notification_json = outgoing_messages.new_message(); - notification_json.append_copy( - concat(u8R"({ + auto lint_callback = [&](Configuration& config, Linter_Options, + Padded_String_View, String8_View uri_json, + String8_View version_json, + Outgoing_JSON_RPC_Message_Queue& outgoing_messages) { + EXPECT_TRUE(config.globals().find(u8"after"_sv)); + EXPECT_FALSE(config.globals().find(u8"before"_sv)); + EXPECT_EQ(version_json, u8"10"_sv); + EXPECT_EQ(uri_json, concat(u8"\""_sv, this->fs.file_uri_prefix_8(), + u8"test.js\""_sv)); + after_config_was_loaded = true; + + Byte_Buffer& notification_json = outgoing_messages.new_message(); + notification_json.append_copy( + concat(u8R"({ "method": "textDocument/publishDiagnostics", "params": { "uri": ")"_sv, - this->fs.file_uri_prefix_8(), - u8R"(test.js", + this->fs.file_uri_prefix_8(), + u8R"(test.js", "version": 10, "diagnostics": [] }, "jsonrpc": "2.0" })"_sv)); - }; + }; + this->linter.lint_callback = lint_callback; this->client->messages.clear(); this->fs.create_file(this->fs.rooted("quick-lint-js.config"), @@ -1697,12 +1698,13 @@ TEST_F(Test_Linting_LSP_Server, TEST_F( Test_Linting_LSP_Server, linting_uses_config_from_filesystem_if_config_is_opened_then_closed_before_opening_js_file) { - this->lint_callback = [&](Configuration& config, Linter_Options, - Padded_String_View, String8_View, String8_View, - Outgoing_JSON_RPC_Message_Queue&) { + auto lint_callback = [&](Configuration& config, Linter_Options, + Padded_String_View, String8_View, String8_View, + Outgoing_JSON_RPC_Message_Queue&) { EXPECT_TRUE(config.globals().find(u8"v1"_sv)); EXPECT_FALSE(config.globals().find(u8"v2"_sv)); }; + this->linter.lint_callback = lint_callback; this->fs.create_file(this->fs.rooted("quick-lint-js.config"), u8R"({"globals": {"v1": true}})"_sv); @@ -1788,26 +1790,26 @@ TEST_F(Test_Linting_LSP_Server, })"_sv))); this->lint_calls.clear(); - this->lint_callback = - [&](Configuration& config, Linter_Options, Padded_String_View, - String8_View, String8_View, - Outgoing_JSON_RPC_Message_Queue& outgoing_messages) { - EXPECT_TRUE(config.globals().find(u8"configFromFilesystem"_sv)); - EXPECT_FALSE(config.globals().find(u8"configFromLSP"_sv)); - Byte_Buffer& notification_json = outgoing_messages.new_message(); - notification_json.append_copy( - concat(u8R"({ + auto lint_callback = [&](Configuration& config, Linter_Options, + Padded_String_View, String8_View, String8_View, + Outgoing_JSON_RPC_Message_Queue& outgoing_messages) { + EXPECT_TRUE(config.globals().find(u8"configFromFilesystem"_sv)); + EXPECT_FALSE(config.globals().find(u8"configFromLSP"_sv)); + Byte_Buffer& notification_json = outgoing_messages.new_message(); + notification_json.append_copy( + concat(u8R"({ "method": "textDocument/publishDiagnostics", "params": { "uri": ")"_sv, - this->fs.file_uri_prefix_8(), - u8R"(test.js", + this->fs.file_uri_prefix_8(), + u8R"(test.js", "version": 10, "diagnostics": [] }, "jsonrpc": "2.0" })"_sv)); - }; + }; + this->linter.lint_callback = lint_callback; this->server->append( make_message(concat(u8R"({ "jsonrpc": "2.0", @@ -1834,30 +1836,31 @@ TEST_F(Test_Linting_LSP_Server, opening_js_file_with_unreadable_config_lints) { }; this->fs.create_file(this->fs.rooted("quick-lint-js.config"), failing_read_file_callback); - this->lint_callback = - [&](Configuration& config, Linter_Options, Padded_String_View, - String8_View uri_json, String8_View version_json, - Outgoing_JSON_RPC_Message_Queue& outgoing_messages) { - EXPECT_TRUE(config.globals().find(u8"Array"_sv)) - << "config should be default"; - EXPECT_FALSE(config.globals().find(u8"undeclaredVariable"_sv)) - << "config should be default"; - Byte_Buffer& notification_json = outgoing_messages.new_message(); - notification_json.append_copy( - concat(u8R"({ + auto lint_callback = [&](Configuration& config, Linter_Options, + Padded_String_View, String8_View uri_json, + String8_View version_json, + Outgoing_JSON_RPC_Message_Queue& outgoing_messages) { + EXPECT_TRUE(config.globals().find(u8"Array"_sv)) + << "config should be default"; + EXPECT_FALSE(config.globals().find(u8"undeclaredVariable"_sv)) + << "config should be default"; + Byte_Buffer& notification_json = outgoing_messages.new_message(); + notification_json.append_copy( + concat(u8R"({ "method": "textDocument/publishDiagnostics", "params": { "uri": )"_sv, - uri_json, - u8R"(, + uri_json, + u8R"(, "version": )"_sv, - version_json, - u8R"(, + version_json, + u8R"(, "diagnostics": [] }, "jsonrpc": "2.0" })"_sv)); - }; + }; + this->linter.lint_callback = lint_callback; this->server->append( make_message(concat(u8R"({ @@ -1897,30 +1900,31 @@ TEST_F(Test_Linting_LSP_Server, opening_js_file_with_invalid_config_json_lints) { this->fs.create_file(this->fs.rooted("quick-lint-js.config"), u8"INVALID JSON"_sv); - this->lint_callback = - [&](Configuration& config, Linter_Options, Padded_String_View, - String8_View uri_json, String8_View version_json, - Outgoing_JSON_RPC_Message_Queue& outgoing_messages) { - EXPECT_TRUE(config.globals().find(u8"Array"_sv)) - << "config should be default"; - EXPECT_FALSE(config.globals().find(u8"undeclaredVariable"_sv)) - << "config should be default"; - Byte_Buffer& notification_json = outgoing_messages.new_message(); - notification_json.append_copy( - concat(u8R"({ + auto lint_callback = [&](Configuration& config, Linter_Options, + Padded_String_View, String8_View uri_json, + String8_View version_json, + Outgoing_JSON_RPC_Message_Queue& outgoing_messages) { + EXPECT_TRUE(config.globals().find(u8"Array"_sv)) + << "config should be default"; + EXPECT_FALSE(config.globals().find(u8"undeclaredVariable"_sv)) + << "config should be default"; + Byte_Buffer& notification_json = outgoing_messages.new_message(); + notification_json.append_copy( + concat(u8R"({ "method": "textDocument/publishDiagnostics", "params": { "uri": )"_sv, - uri_json, - u8R"(, + uri_json, + u8R"(, "version": )"_sv, - version_json, - u8R"(, + version_json, + u8R"(, "diagnostics": [] }, "jsonrpc": "2.0" })"_sv)); - }; + }; + this->linter.lint_callback = lint_callback; this->server->append( make_message(concat(u8R"({ @@ -1987,28 +1991,29 @@ TEST_F(Test_Linting_LSP_Server, making_config_file_unreadable_relints) { }; this->fs.create_file(this->fs.rooted("quick-lint-js.config"), failing_read_file_callback); - this->lint_callback = - [&](Configuration& config, Linter_Options, Padded_String_View, - String8_View uri_json, String8_View version_json, - Outgoing_JSON_RPC_Message_Queue& outgoing_messages) { - EXPECT_FALSE(config.globals().find(u8"configFromFilesystem"_sv)) - << "config should be default"; - Byte_Buffer& notification_json = outgoing_messages.new_message(); - notification_json.append_copy( - concat(u8R"({ + auto lint_callback = [&](Configuration& config, Linter_Options, + Padded_String_View, String8_View uri_json, + String8_View version_json, + Outgoing_JSON_RPC_Message_Queue& outgoing_messages) { + EXPECT_FALSE(config.globals().find(u8"configFromFilesystem"_sv)) + << "config should be default"; + Byte_Buffer& notification_json = outgoing_messages.new_message(); + notification_json.append_copy( + concat(u8R"({ "method": "textDocument/publishDiagnostics", "params": { "uri": )"_sv, - uri_json, - u8R"(, + uri_json, + u8R"(, "version": )"_sv, - version_json, - u8R"(, + version_json, + u8R"(, "diagnostics": [] }, "jsonrpc": "2.0" })"_sv)); - }; + }; + this->linter.lint_callback = lint_callback; this->client->messages.clear(); this->handler->filesystem_changed(); this->server->flush_error_responses(*this->client); From 886b2f34e1945ecc0d97c44706f5b7da4680a288 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 15:01:10 -0400 Subject: [PATCH 035/117] refactor(test): remove lint_calls alias; make tests more explicit --- test/test-lsp-server.cpp | 80 ++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/test/test-lsp-server.cpp b/test/test-lsp-server.cpp index 639d60f5e2..36c373f580 100644 --- a/test/test-lsp-server.cpp +++ b/test/test-lsp-server.cpp @@ -88,7 +88,7 @@ class Test_Linting_LSP_Server : public ::testing::Test, public Filesystem_Test { explicit Test_Linting_LSP_Server() { this->reset(); } void reset() { - this->lint_calls.clear(); + this->linter.lint_calls.clear(); this->fs.clear(); this->linter = Mock_LSP_Linter(); this->handler = @@ -105,8 +105,6 @@ class Test_Linting_LSP_Server : public ::testing::Test, public Filesystem_Test { std::unique_ptr client; std::unique_ptr server; - std::vector& lint_calls = linter.lint_calls; - std::string config_file_load_error_message(const char* js_path, const char* error_path) { return concat("Failed to load configuration file for "sv, @@ -597,7 +595,7 @@ TEST_F(Test_Linting_LSP_Server, opening_document_lints) { EXPECT_EQ(diagnostics[0][u8"message"_sv], u8"variable used before declaration: x"_sv); - EXPECT_THAT(this->lint_calls, ElementsAreArray({u8"let x = x;"})); + EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8"let x = x;"})); } TEST_F(Test_Linting_LSP_Server, javascript_language_ids_enable_jsx) { @@ -629,7 +627,7 @@ TEST_F(Test_Linting_LSP_Server, javascript_language_ids_enable_jsx) { } } })"_sv))); - EXPECT_THAT(this->lint_calls, ElementsAreArray({u8"code goes here"})); + EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8"code goes here"})); } } @@ -661,7 +659,7 @@ TEST_F(Test_Linting_LSP_Server, typescript_language_ids_enable_typescript) { } } })"_sv))); - EXPECT_THAT(this->lint_calls, ElementsAreArray({u8"code goes here"})); + EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8"code goes here"})); } } @@ -693,7 +691,7 @@ TEST_F(Test_Linting_LSP_Server, tsx_language_ids_enable_typescript_jsx) { } } })"_sv))); - EXPECT_THAT(this->lint_calls, ElementsAreArray({u8"code goes here"})); + EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8"code goes here"})); } } @@ -711,7 +709,7 @@ TEST_F(Test_Linting_LSP_Server, changing_document_with_full_text_lints) { } } })"_sv)); - this->lint_calls.clear(); + this->linter.lint_calls.clear(); this->server->append( make_message(u8R"({ "jsonrpc": "2.0", @@ -729,7 +727,7 @@ TEST_F(Test_Linting_LSP_Server, changing_document_with_full_text_lints) { } })"_sv)); - EXPECT_THAT(this->lint_calls, ElementsAreArray({u8"SECOND"})); + EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8"SECOND"})); } TEST_F(Test_Linting_LSP_Server, @@ -747,7 +745,7 @@ TEST_F(Test_Linting_LSP_Server, } } })"_sv)); - this->lint_calls.clear(); + this->linter.lint_calls.clear(); this->server->append( make_message(u8R"({ @@ -790,7 +788,7 @@ TEST_F(Test_Linting_LSP_Server, } })"_sv)); - EXPECT_THAT(this->lint_calls, ElementsAreArray({u8"the slow brown fox", + EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8"the slow brown fox", u8"the slow purple fox"})); } @@ -809,7 +807,7 @@ TEST_F(Test_Linting_LSP_Server, } } })"_sv)); - this->lint_calls.clear(); + this->linter.lint_calls.clear(); this->server->append( make_message(u8R"({ @@ -839,7 +837,7 @@ TEST_F(Test_Linting_LSP_Server, } })"_sv)); - EXPECT_THAT(this->lint_calls, ElementsAreArray({u8"the slow purple fox"})); + EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8"the slow purple fox"})); } TEST_F(Test_Linting_LSP_Server, linting_uses_config_from_file) { @@ -869,7 +867,7 @@ TEST_F(Test_Linting_LSP_Server, linting_uses_config_from_file) { } })"_sv))); - EXPECT_THAT(this->lint_calls, ElementsAreArray({u8""})); + EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8""})); } TEST_F( @@ -933,7 +931,7 @@ TEST_F( } })"_sv))); - this->lint_calls.clear(); + this->linter.lint_calls.clear(); auto lint_callback = [&](Configuration& config, Linter_Options, Padded_String_View, String8_View, String8_View, Outgoing_JSON_RPC_Message_Queue&) { @@ -960,7 +958,7 @@ TEST_F( } })"_sv))); - EXPECT_THAT(this->lint_calls, ElementsAreArray({u8""})); + EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8""})); } TEST_F(Test_Linting_LSP_Server, @@ -991,7 +989,7 @@ TEST_F(Test_Linting_LSP_Server, } })"_sv))); - EXPECT_THAT(this->lint_calls, ElementsAreArray({u8"snowman"})); + EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8"snowman"})); } TEST_F(Test_Linting_LSP_Server, linting_uses_already_opened_config_file) { @@ -1035,7 +1033,7 @@ TEST_F(Test_Linting_LSP_Server, linting_uses_already_opened_config_file) { } })"_sv))); - EXPECT_THAT(this->lint_calls, ElementsAreArray({u8""})); + EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8""})); } TEST_F(Test_Linting_LSP_Server, @@ -1081,7 +1079,7 @@ TEST_F(Test_Linting_LSP_Server, } })"_sv))); - EXPECT_THAT(this->lint_calls, ElementsAreArray({u8""})); + EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8""})); } TEST_F(Test_Linting_LSP_Server, editing_config_relints_open_js_file) { @@ -1223,7 +1221,7 @@ TEST_F(Test_Linting_LSP_Server, EXPECT_EQ(version_json, u8"11"_sv); }; this->linter.lint_callback = lint_callback; - this->lint_calls.clear(); + this->linter.lint_calls.clear(); // Change 'before' to 'after'. this->server->append( @@ -1249,7 +1247,7 @@ TEST_F(Test_Linting_LSP_Server, } })"_sv))); - EXPECT_THAT(this->lint_calls, ElementsAreArray({u8"updated"_sv})); + EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8"updated"_sv})); } TEST_F(Test_Linting_LSP_Server, editing_config_relints_many_open_js_files) { @@ -1315,7 +1313,7 @@ TEST_F(Test_Linting_LSP_Server, editing_config_relints_many_open_js_files) { } this->handler->flush_pending_notifications(*this->client); - this->lint_calls.clear(); + this->linter.lint_calls.clear(); this->client->messages.clear(); // Change 'before' to 'after'. this->server->append( @@ -1343,7 +1341,7 @@ TEST_F(Test_Linting_LSP_Server, editing_config_relints_many_open_js_files) { this->server->flush_error_responses(*this->client); this->handler->flush_pending_notifications(*this->client); - EXPECT_THAT(this->lint_calls, + EXPECT_THAT(this->linter.lint_calls, ::testing::UnorderedElementsAreArray( {u8"/* a.js */", u8"/* b.js */", u8"/* c.js */"})); @@ -1442,7 +1440,7 @@ TEST_F(Test_Linting_LSP_Server, editing_config_relints_only_affected_js_files) { } this->handler->flush_pending_notifications(*this->client); - this->lint_calls.clear(); + this->linter.lint_calls.clear(); this->client->messages.clear(); // Change 'a' to 'A' in dir-a/quick-lint-js.config (but leave // dir-b/quick-lint-js.config as-is). @@ -1471,7 +1469,7 @@ TEST_F(Test_Linting_LSP_Server, editing_config_relints_only_affected_js_files) { this->server->flush_error_responses(*this->client); this->handler->flush_pending_notifications(*this->client); - EXPECT_THAT(this->lint_calls, ElementsAreArray({u8"/* dir-a/test.js */"})); + EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8"/* dir-a/test.js */"})); std::vector linted_uris; for (const TJSON_Value& notification : this->client->notifications()) { @@ -1545,7 +1543,7 @@ TEST_F(Test_Linting_LSP_Server, } })"_sv))); - this->lint_calls.clear(); + this->linter.lint_calls.clear(); auto lint_callback = [&](Configuration& config, Linter_Options, Padded_String_View, String8_View, String8_View version_json, @@ -1575,7 +1573,7 @@ TEST_F(Test_Linting_LSP_Server, } })"_sv))); - EXPECT_THAT(this->lint_calls, ElementsAreArray({u8"modified"})); + EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8"modified"})); } TEST_F(Test_Linting_LSP_Server, opening_config_relints_open_js_files) { @@ -1751,7 +1749,7 @@ TEST_F( } })"_sv))); - EXPECT_THAT(this->lint_calls, ElementsAreArray({u8""})); + EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8""})); } TEST_F(Test_Linting_LSP_Server, @@ -1789,7 +1787,7 @@ TEST_F(Test_Linting_LSP_Server, } })"_sv))); - this->lint_calls.clear(); + this->linter.lint_calls.clear(); auto lint_callback = [&](Configuration& config, Linter_Options, Padded_String_View, String8_View, String8_View, Outgoing_JSON_RPC_Message_Queue& outgoing_messages) { @@ -1823,7 +1821,7 @@ TEST_F(Test_Linting_LSP_Server, } })"_sv))); - EXPECT_THAT(this->lint_calls, ElementsAreArray({u8""})); + EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8""})); } TEST_F(Test_Linting_LSP_Server, opening_js_file_with_unreadable_config_lints) { @@ -1880,7 +1878,7 @@ TEST_F(Test_Linting_LSP_Server, opening_js_file_with_unreadable_config_lints) { this->server->flush_error_responses(*this->client); this->handler->flush_pending_notifications(*this->client); - EXPECT_THAT(this->lint_calls, ElementsAreArray({u8"testjs"})) + EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8"testjs"})) << "should have linted despite config file being unloadable"; std::vector notifications = this->client->notifications(); @@ -1944,7 +1942,7 @@ TEST_F(Test_Linting_LSP_Server, this->server->flush_error_responses(*this->client); this->handler->flush_pending_notifications(*this->client); - EXPECT_THAT(this->lint_calls, ElementsAreArray({u8"testjs"})) + EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8"testjs"})) << "should have linted despite config file being unloadable"; std::vector notifications = this->client->notifications(); @@ -2019,7 +2017,7 @@ TEST_F(Test_Linting_LSP_Server, making_config_file_unreadable_relints) { this->server->flush_error_responses(*this->client); this->handler->flush_pending_notifications(*this->client); - EXPECT_THAT(this->lint_calls, ElementsAreArray({u8"testjs", u8"testjs"})) + EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8"testjs", u8"testjs"})) << "should have linted twice: once on open, and once after config file " "changed"; @@ -2153,7 +2151,7 @@ TEST_F(Test_Linting_LSP_Server, } } })"_sv)); - this->lint_calls.clear(); + this->linter.lint_calls.clear(); this->server->append( make_message(u8R"({ "jsonrpc": "2.0", @@ -2171,7 +2169,7 @@ TEST_F(Test_Linting_LSP_Server, } })"_sv)); - EXPECT_THAT(this->lint_calls, IsEmpty()); + EXPECT_THAT(this->linter.lint_calls, IsEmpty()); } TEST_F(Test_Linting_LSP_Server, json_file_which_is_not_config_file_is_ignored) { @@ -2193,7 +2191,7 @@ TEST_F(Test_Linting_LSP_Server, json_file_which_is_not_config_file_is_ignored) { this->server->flush_error_responses(*this->client); EXPECT_THAT(this->client->messages, IsEmpty()); - EXPECT_THAT(this->lint_calls, IsEmpty()); + EXPECT_THAT(this->linter.lint_calls, IsEmpty()); } TEST_F(Test_Linting_LSP_Server, @@ -2212,7 +2210,7 @@ TEST_F(Test_Linting_LSP_Server, } })"_sv)); - EXPECT_THAT(this->lint_calls, IsEmpty()); + EXPECT_THAT(this->linter.lint_calls, IsEmpty()); } TEST_F(Test_Linting_LSP_Server, @@ -2240,7 +2238,7 @@ TEST_F(Test_Linting_LSP_Server, } } })"_sv)); - this->lint_calls.clear(); + this->linter.lint_calls.clear(); this->server->append( make_message(u8R"({ "jsonrpc": "2.0", @@ -2271,7 +2269,7 @@ TEST_F(Test_Linting_LSP_Server, } })"_sv)); - EXPECT_THAT(this->lint_calls, + EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8"let x = x;", u8"let y = y;"})); } @@ -2300,7 +2298,7 @@ TEST_F(Test_Linting_LSP_Server, } } })"_sv)); - this->lint_calls.clear(); + this->linter.lint_calls.clear(); this->server->append( make_message(u8R"({ "jsonrpc": "2.0", @@ -2331,7 +2329,7 @@ TEST_F(Test_Linting_LSP_Server, } })"_sv)); - EXPECT_THAT(this->lint_calls, IsEmpty()); + EXPECT_THAT(this->linter.lint_calls, IsEmpty()); } TEST_F(Test_Linting_LSP_Server, showing_io_errors_shows_only_first) { From a23a19d7e3059eb0348d7815b47438546f16d071 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 15:01:10 -0400 Subject: [PATCH 036/117] refactor(container): delete unused Heap_Function --- src/CMakeLists.txt | 1 - src/quick-lint-js/container/heap-function.h | 90 ---------- .../lsp/lsp-workspace-configuration.cpp | 1 - test/CMakeLists.txt | 1 - .../fake-configuration-filesystem.cpp | 1 - .../fake-configuration-filesystem.h | 1 - test/test-heap-function.cpp | 167 ------------------ test/test-lsp-server.cpp | 1 - 8 files changed, 263 deletions(-) delete mode 100644 src/quick-lint-js/container/heap-function.h delete mode 100644 test/test-heap-function.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fc5df2a340..911b9e243b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -295,7 +295,6 @@ quick_lint_js_add_library( quick-lint-js/container/hash-map.h quick-lint-js/container/hash-set.h quick-lint-js/container/hash.h - quick-lint-js/container/heap-function.h quick-lint-js/container/linked-bump-allocator.h quick-lint-js/container/linked-vector.h quick-lint-js/container/optional.h diff --git a/src/quick-lint-js/container/heap-function.h b/src/quick-lint-js/container/heap-function.h deleted file mode 100644 index 9607451b50..0000000000 --- a/src/quick-lint-js/container/heap-function.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (C) 2020 Matthew "strager" Glazar -// See end of file for extended copyright information. - -#pragma once - -#include -#include - -namespace quick_lint_js { -template -class Heap_Function; - -// Heap_Function is like std::function but with a few differences: -// -// * Heap_Function compiles significantly faster than libc++'s std::function. -// * Heap_Function supports move-only targets. -// * Heap_Function does not have inline storage. It always heap-allocates. -// * Heap_Function does not support allocators. -// * Heap_Function does not support member function pointers and other -// craziness. -template -class Heap_Function { - public: - /*implicit*/ Heap_Function() = default; - - template >::type> - /*implicit*/ Heap_Function(Func&& func) - : callable_(new Dynamic_Callable(std::move(func))) {} - - Heap_Function(Heap_Function&& other) - : callable_(std::exchange(other.callable_, nullptr)) {} - - Heap_Function& operator=(Heap_Function&& other) { - if (this != &other) { - delete this->callable_; - this->callable_ = std::exchange(other.callable_, nullptr); - } - return *this; - } - - ~Heap_Function() { delete this->callable_; } - - explicit operator bool() const { return this->callable_ != nullptr; } - - Result operator()(Args... args) { - return this->callable_->call(std::forward(args)...); - } - - private: - struct Dynamic_Callable_Base { - virtual ~Dynamic_Callable_Base() = default; - - virtual Result call(Args... args) = 0; - }; - - template - struct Dynamic_Callable : Dynamic_Callable_Base { - explicit Dynamic_Callable(Func&& func) : func(std::move(func)) {} - - virtual ~Dynamic_Callable() override = default; - - Result call(Args... args) override { - return this->func(std::forward(args)...); - } - - Func func; - }; - - Dynamic_Callable_Base* callable_ = nullptr; -}; -} - -// quick-lint-js finds bugs in JavaScript programs. -// Copyright (C) 2020 Matthew "strager" Glazar -// -// This file is part of quick-lint-js. -// -// quick-lint-js is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// quick-lint-js is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with quick-lint-js. If not, see . diff --git a/src/quick-lint-js/lsp/lsp-workspace-configuration.cpp b/src/quick-lint-js/lsp/lsp-workspace-configuration.cpp index ec4aebbc81..9b606f71ae 100644 --- a/src/quick-lint-js/lsp/lsp-workspace-configuration.cpp +++ b/src/quick-lint-js/lsp/lsp-workspace-configuration.cpp @@ -6,7 +6,6 @@ #else #include -#include #include #include #include diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4f61ea838d..a07387674c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -107,7 +107,6 @@ quick_lint_js_add_executable( test-file.cpp test-fixed-vector.cpp test-function-ref.cpp - test-heap-function.cpp test-instance-tracker.cpp test-integer-decimal.cpp test-integer-hexadecimal.cpp diff --git a/test/quick-lint-js/fake-configuration-filesystem.cpp b/test/quick-lint-js/fake-configuration-filesystem.cpp index 409f13c21f..3ff574b7af 100644 --- a/test/quick-lint-js/fake-configuration-filesystem.cpp +++ b/test/quick-lint-js/fake-configuration-filesystem.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/test/quick-lint-js/fake-configuration-filesystem.h b/test/quick-lint-js/fake-configuration-filesystem.h index 4781bf5487..77b124a6e7 100644 --- a/test/quick-lint-js/fake-configuration-filesystem.h +++ b/test/quick-lint-js/fake-configuration-filesystem.h @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/test/test-heap-function.cpp b/test/test-heap-function.cpp deleted file mode 100644 index 8da1831e35..0000000000 --- a/test/test-heap-function.cpp +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright (C) 2020 Matthew "strager" Glazar -// See end of file for extended copyright information. - -#include -#include -#include -#include - -QLJS_WARNING_IGNORE_CLANG("-Wunused-member-function") - -namespace quick_lint_js { -namespace { -// Copy_Spy keeps track of the number of instances. -struct Copy_Spy { - inline static int instance_count; - - Copy_Spy() { instance_count += 1; } - - Copy_Spy(const Copy_Spy&) { instance_count += 1; } - Copy_Spy& operator=(const Copy_Spy&) { return *this; } - - Copy_Spy(Copy_Spy&&) { instance_count += 1; } - Copy_Spy& operator=(Copy_Spy&&) { return *this; } - - ~Copy_Spy() { instance_count -= 1; } - - void operator()() {} -}; - -TEST(Test_Heap_Function, default_constructed_has_no_target) { - Heap_Function f; - EXPECT_FALSE(f); -} - -TEST(Test_Heap_Function, constructed_with_lambda_has_target) { - Heap_Function f = []() -> void {}; - EXPECT_TRUE(f); -} - -TEST(Test_Heap_Function, destructing_heap_function_calls_target_destructor) { - Copy_Spy::instance_count = 0; - { - Heap_Function f = Copy_Spy(); - EXPECT_EQ(Copy_Spy::instance_count, 1); - } - EXPECT_EQ(Copy_Spy::instance_count, 0); -} - -TEST(Test_Heap_Function, call_closureless_lambda) { - static bool called; - Heap_Function f = []() -> void { called = true; }; - called = false; - f(); - EXPECT_TRUE(called); -} - -TEST(Test_Heap_Function, call_lambda_with_closure) { - bool called = false; - Heap_Function f = [&called]() -> void { called = true; }; - ASSERT_FALSE(called); - f(); - EXPECT_TRUE(called); -} - -TEST(Test_Heap_Function, call_manual_functor_with_closure) { - struct Functor { - bool& called; - - void operator()() { called = true; } - }; - bool called = false; - Heap_Function f = Functor{called}; - ASSERT_FALSE(called); - f(); - EXPECT_TRUE(called); -} - -TEST(Test_Heap_Function, lambda_return_value) { - Heap_Function f = []() -> int { return 42; }; - int result = f(); - EXPECT_EQ(result, 42); -} - -TEST(Test_Heap_Function, single_parameter) { - static int got_x; - Heap_Function f = [](int x) -> void { got_x = x; }; - got_x = 0; - f(42); - EXPECT_EQ(got_x, 42); -} - -TEST(Test_Heap_Function, move_only_parameter) { - static int* got_o; - Heap_Function)> f = - [](std::unique_ptr o) -> void { got_o = o.get(); }; - got_o = nullptr; - - std::unique_ptr o = std::make_unique(42); - int* o_raw = o.get(); - f(std::move(o)); - - EXPECT_EQ(got_o, o_raw); -} - -TEST(Test_Heap_Function, assign_lambda_over_empty) { - static bool called; - called = false; - - Heap_Function f; - f = []() -> void { called = true; }; - - EXPECT_TRUE(f); - f(); - EXPECT_TRUE(called); -} - -TEST(Test_Heap_Function, assign_heap_function_over_empty) { - static bool called; - called = false; - - Heap_Function f; - f = Heap_Function([]() -> void { called = true; }); - - EXPECT_TRUE(f); - f(); - EXPECT_TRUE(called); -} - -TEST(Test_Heap_Function, assign_empty_over_empty) { - Heap_Function f; - f = Heap_Function(); - EXPECT_FALSE(f); -} - -TEST(Test_Heap_Function, assign_over_existing_destructs_existing) { - Copy_Spy::instance_count = 0; - Heap_Function f = Copy_Spy(); - EXPECT_EQ(Copy_Spy::instance_count, 1); - f = []() -> void {}; - EXPECT_EQ(Copy_Spy::instance_count, 0); -} - -TEST(Test_Heap_Function, assign_empty_over_lambda) { - Heap_Function f = []() -> void {}; - f = Heap_Function(); - EXPECT_FALSE(f); -} -} -} - -// quick-lint-js finds bugs in JavaScript programs. -// Copyright (C) 2020 Matthew "strager" Glazar -// -// This file is part of quick-lint-js. -// -// quick-lint-js is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// quick-lint-js is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with quick-lint-js. If not, see . diff --git a/test/test-lsp-server.cpp b/test/test-lsp-server.cpp index 36c373f580..07faee6e3c 100644 --- a/test/test-lsp-server.cpp +++ b/test/test-lsp-server.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include From d3573baea125fd530f13a1b682282d616f5d6008 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 15:01:10 -0400 Subject: [PATCH 037/117] refactor(lsp): prefer Bump_Vector over std::vector Reduce our use of std::vector to reduce binary bloat: https://github.com/quick-lint/quick-lint-js/issues/689 --- src/quick-lint-js/lsp/lsp-server.h | 9 +- .../lsp/lsp-workspace-configuration.cpp | 4 + .../lsp/lsp-workspace-configuration.h | 7 +- test/test-lsp-server.cpp | 23 ++++-- test/test-lsp-workspace-configuration.cpp | 82 ++++++++++--------- 5 files changed, 73 insertions(+), 52 deletions(-) diff --git a/src/quick-lint-js/lsp/lsp-server.h b/src/quick-lint-js/lsp/lsp-server.h index d69c8a88e4..6648ee781f 100644 --- a/src/quick-lint-js/lsp/lsp-server.h +++ b/src/quick-lint-js/lsp/lsp-server.h @@ -235,16 +235,17 @@ class Linting_LSP_Server_Handler final : public JSON_RPC_Message_Handler { // lock. LSP_Overlay_Configuration_Filesystem reads without taking the lock. Synchronized documents_; + Monotonic_Allocator workspace_configuration_allocator_{ + "Linting_LSP_Server_Handler::workspace_configuration_allocator_"}; + Outgoing_JSON_RPC_Message_Queue outgoing_messages_; Linting_LSP_Server_Config server_config_; - LSP_Workspace_Configuration workspace_configuration_; + LSP_Workspace_Configuration workspace_configuration_{ + &this->workspace_configuration_allocator_}; std::unique_ptr tracer_backend_; bool did_report_watch_io_error_ = false; bool shutdown_requested_ = false; - Monotonic_Allocator workspace_configuration_allocator_{ - "Linting_LSP_Server_Handler::workspace_configuration_allocator_"}; - friend class LSP_Linter; friend struct LSP_Documents::Config_Document; friend struct LSP_Documents::Lintable_Document; diff --git a/src/quick-lint-js/lsp/lsp-workspace-configuration.cpp b/src/quick-lint-js/lsp/lsp-workspace-configuration.cpp index 9b606f71ae..e6e2849aa6 100644 --- a/src/quick-lint-js/lsp/lsp-workspace-configuration.cpp +++ b/src/quick-lint-js/lsp/lsp-workspace-configuration.cpp @@ -16,6 +16,10 @@ using namespace std::literals::string_view_literals; namespace quick_lint_js { +LSP_Workspace_Configuration::LSP_Workspace_Configuration( + Monotonic_Allocator* allocator) + : items_("LSP_Workspace_Configuration::items_", allocator) {} + void LSP_Workspace_Configuration::add_item( String8_View name, Async_Function_Ref callback) { this->items_.push_back(Item{ diff --git a/src/quick-lint-js/lsp/lsp-workspace-configuration.h b/src/quick-lint-js/lsp/lsp-workspace-configuration.h index 1fa469fec6..023d9a9c96 100644 --- a/src/quick-lint-js/lsp/lsp-workspace-configuration.h +++ b/src/quick-lint-js/lsp/lsp-workspace-configuration.h @@ -7,12 +7,13 @@ // No LSP on the web. #else +#include +#include #include #include #include #include #include -#include namespace quick_lint_js { class Byte_Buffer; @@ -21,6 +22,8 @@ class Byte_Buffer; // (e.g. workspace/configuration). class LSP_Workspace_Configuration { public: + explicit LSP_Workspace_Configuration(Monotonic_Allocator* allocator); + // Register a configuration setting. // // callback is later called by process_response or process_notification. @@ -58,7 +61,7 @@ class LSP_Workspace_Configuration { Item* find_item(String8_View name); bool set_item(Item&, ::simdjson::ondemand::value); - std::vector items_; + Bump_Vector items_; }; } diff --git a/test/test-lsp-server.cpp b/test/test-lsp-server.cpp index 07faee6e3c..08c93c809a 100644 --- a/test/test-lsp-server.cpp +++ b/test/test-lsp-server.cpp @@ -626,7 +626,8 @@ TEST_F(Test_Linting_LSP_Server, javascript_language_ids_enable_jsx) { } } })"_sv))); - EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8"code goes here"})); + EXPECT_THAT(this->linter.lint_calls, + ElementsAreArray({u8"code goes here"})); } } @@ -658,7 +659,8 @@ TEST_F(Test_Linting_LSP_Server, typescript_language_ids_enable_typescript) { } } })"_sv))); - EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8"code goes here"})); + EXPECT_THAT(this->linter.lint_calls, + ElementsAreArray({u8"code goes here"})); } } @@ -690,7 +692,8 @@ TEST_F(Test_Linting_LSP_Server, tsx_language_ids_enable_typescript_jsx) { } } })"_sv))); - EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8"code goes here"})); + EXPECT_THAT(this->linter.lint_calls, + ElementsAreArray({u8"code goes here"})); } } @@ -787,8 +790,9 @@ TEST_F(Test_Linting_LSP_Server, } })"_sv)); - EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8"the slow brown fox", - u8"the slow purple fox"})); + EXPECT_THAT( + this->linter.lint_calls, + ElementsAreArray({u8"the slow brown fox", u8"the slow purple fox"})); } TEST_F(Test_Linting_LSP_Server, @@ -836,7 +840,8 @@ TEST_F(Test_Linting_LSP_Server, } })"_sv)); - EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8"the slow purple fox"})); + EXPECT_THAT(this->linter.lint_calls, + ElementsAreArray({u8"the slow purple fox"})); } TEST_F(Test_Linting_LSP_Server, linting_uses_config_from_file) { @@ -1468,7 +1473,8 @@ TEST_F(Test_Linting_LSP_Server, editing_config_relints_only_affected_js_files) { this->server->flush_error_responses(*this->client); this->handler->flush_pending_notifications(*this->client); - EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8"/* dir-a/test.js */"})); + EXPECT_THAT(this->linter.lint_calls, + ElementsAreArray({u8"/* dir-a/test.js */"})); std::vector linted_uris; for (const TJSON_Value& notification : this->client->notifications()) { @@ -2016,7 +2022,8 @@ TEST_F(Test_Linting_LSP_Server, making_config_file_unreadable_relints) { this->server->flush_error_responses(*this->client); this->handler->flush_pending_notifications(*this->client); - EXPECT_THAT(this->linter.lint_calls, ElementsAreArray({u8"testjs", u8"testjs"})) + EXPECT_THAT(this->linter.lint_calls, + ElementsAreArray({u8"testjs", u8"testjs"})) << "should have linted twice: once on open, and once after config file " "changed"; diff --git a/test/test-lsp-workspace-configuration.cpp b/test/test-lsp-workspace-configuration.cpp index 2491181d9d..bb5818f001 100644 --- a/test/test-lsp-workspace-configuration.cpp +++ b/test/test-lsp-workspace-configuration.cpp @@ -44,8 +44,13 @@ struct Easy_SIMDJSON_Parser { ::simdjson::ondemand::value value; }; -TEST(Test_LSP_Workspace_Configuration, empty_config_request) { - LSP_Workspace_Configuration config; +class Test_LSP_Workspace_Configuration : public ::testing::Test { + public: + Monotonic_Allocator allocator{"Test_LSP_Workspace_Configuration"}; +}; + +TEST_F(Test_LSP_Workspace_Configuration, empty_config_request) { + LSP_Workspace_Configuration config(&this->allocator); Byte_Buffer request_json; config.build_request(77, request_json); @@ -58,8 +63,8 @@ TEST(Test_LSP_Workspace_Configuration, empty_config_request) { EXPECT_THAT(items.try_get_array().value(), IsEmpty()); } -TEST(Test_LSP_Workspace_Configuration, config_request_with_three_items) { - LSP_Workspace_Configuration config; +TEST_F(Test_LSP_Workspace_Configuration, config_request_with_three_items) { + LSP_Workspace_Configuration config(&this->allocator); config.add_item(u8"first"_sv, [](std::string_view) {}); config.add_item(u8"second"_sv, [](std::string_view) {}); config.add_item(u8"third"_sv, [](std::string_view) {}); @@ -75,8 +80,8 @@ TEST(Test_LSP_Workspace_Configuration, config_request_with_three_items) { EXPECT_EQ(request_items[2][u8"section"_sv], u8"third"_sv); } -TEST(Test_LSP_Workspace_Configuration, empty_config_response) { - LSP_Workspace_Configuration config; +TEST_F(Test_LSP_Workspace_Configuration, empty_config_response) { + LSP_Workspace_Configuration config(&this->allocator); Easy_SIMDJSON_Parser result("[]"_padded); ASSERT_EQ(result.error, ::simdjson::SUCCESS); @@ -84,9 +89,9 @@ TEST(Test_LSP_Workspace_Configuration, empty_config_response) { ASSERT_TRUE(ok); } -TEST(Test_LSP_Workspace_Configuration, config_response_with_strings) { +TEST_F(Test_LSP_Workspace_Configuration, config_response_with_strings) { std::string items[3]; - LSP_Workspace_Configuration config; + LSP_Workspace_Configuration config(&this->allocator); auto first_callback = [&items](std::string_view new_value) { items[0] = new_value; }; @@ -111,9 +116,9 @@ TEST(Test_LSP_Workspace_Configuration, config_response_with_strings) { EXPECT_EQ(items[2], "thirdval"); } -TEST(Test_LSP_Workspace_Configuration, - empty_config_response_with_added_items_fails) { - LSP_Workspace_Configuration config; +TEST_F(Test_LSP_Workspace_Configuration, + empty_config_response_with_added_items_fails) { + LSP_Workspace_Configuration config(&this->allocator); bool myitem_callback_called = false; auto myitem_callback = [&myitem_callback_called](std::string_view new_value) { myitem_callback_called = true; @@ -130,9 +135,9 @@ TEST(Test_LSP_Workspace_Configuration, EXPECT_FALSE(myitem_callback_called); } -TEST(Test_LSP_Workspace_Configuration, - more_values_than_config_fails_but_calls_callback_anyway) { - LSP_Workspace_Configuration config; +TEST_F(Test_LSP_Workspace_Configuration, + more_values_than_config_fails_but_calls_callback_anyway) { + LSP_Workspace_Configuration config(&this->allocator); bool myitem_callback_called = false; auto myitem_callback = [&myitem_callback_called](std::string_view new_value) { myitem_callback_called = true; @@ -148,8 +153,8 @@ TEST(Test_LSP_Workspace_Configuration, EXPECT_TRUE(myitem_callback_called); } -TEST(Test_LSP_Workspace_Configuration, null_is_coerced_to_empty_string) { - LSP_Workspace_Configuration config; +TEST_F(Test_LSP_Workspace_Configuration, null_is_coerced_to_empty_string) { + LSP_Workspace_Configuration config(&this->allocator); bool myitem_callback_called = false; auto myitem_callback = [&myitem_callback_called](std::string_view new_value) { myitem_callback_called = true; @@ -165,8 +170,8 @@ TEST(Test_LSP_Workspace_Configuration, null_is_coerced_to_empty_string) { EXPECT_TRUE(myitem_callback_called); } -TEST(Test_LSP_Workspace_Configuration, non_array_config_response_fails) { - LSP_Workspace_Configuration config; +TEST_F(Test_LSP_Workspace_Configuration, non_array_config_response_fails) { + LSP_Workspace_Configuration config(&this->allocator); Easy_SIMDJSON_Parser result("{}"_padded); ASSERT_EQ(result.error, ::simdjson::SUCCESS); @@ -174,8 +179,9 @@ TEST(Test_LSP_Workspace_Configuration, non_array_config_response_fails) { ASSERT_FALSE(ok); } -TEST(Test_LSP_Workspace_Configuration, empty_config_notification_does_nothing) { - LSP_Workspace_Configuration config; +TEST_F(Test_LSP_Workspace_Configuration, + empty_config_notification_does_nothing) { + LSP_Workspace_Configuration config(&this->allocator); Easy_SIMDJSON_Parser result("{}"_padded); ASSERT_EQ(result.error, ::simdjson::SUCCESS); @@ -183,9 +189,9 @@ TEST(Test_LSP_Workspace_Configuration, empty_config_notification_does_nothing) { ASSERT_TRUE(ok); } -TEST(Test_LSP_Workspace_Configuration, - config_notification_calls_item_callbacks) { - LSP_Workspace_Configuration config; +TEST_F(Test_LSP_Workspace_Configuration, + config_notification_calls_item_callbacks) { + LSP_Workspace_Configuration config(&this->allocator); bool myitem_callback_called = false; auto myitem_callback = [&myitem_callback_called](std::string_view new_value) { myitem_callback_called = true; @@ -201,9 +207,9 @@ TEST(Test_LSP_Workspace_Configuration, EXPECT_TRUE(myitem_callback_called); } -TEST(Test_LSP_Workspace_Configuration, - config_notification_ignores_extra_entries) { - LSP_Workspace_Configuration config; +TEST_F(Test_LSP_Workspace_Configuration, + config_notification_ignores_extra_entries) { + LSP_Workspace_Configuration config(&this->allocator); int myitem_callback_called_count = 0; auto myitem_callback = [&myitem_callback_called_count](std::string_view new_value) { @@ -221,9 +227,9 @@ TEST(Test_LSP_Workspace_Configuration, EXPECT_EQ(myitem_callback_called_count, 1); } -TEST(Test_LSP_Workspace_Configuration, - config_notification_does_not_call_callback_for_unnotified_items) { - LSP_Workspace_Configuration config; +TEST_F(Test_LSP_Workspace_Configuration, + config_notification_does_not_call_callback_for_unnotified_items) { + LSP_Workspace_Configuration config(&this->allocator); bool myitem_callback_called = false; auto myitem_callback = [&myitem_callback_called](std::string_view new_value) { myitem_callback_called = true; @@ -240,9 +246,9 @@ TEST(Test_LSP_Workspace_Configuration, EXPECT_FALSE(myitem_callback_called); } -TEST(Test_LSP_Workspace_Configuration, - initialization_options_calls_item_callbacks) { - LSP_Workspace_Configuration config; +TEST_F(Test_LSP_Workspace_Configuration, + initialization_options_calls_item_callbacks) { + LSP_Workspace_Configuration config(&this->allocator); bool myitem_callback_called = false; auto myitem_callback = [&myitem_callback_called](std::string_view new_value) { myitem_callback_called = true; @@ -258,9 +264,9 @@ TEST(Test_LSP_Workspace_Configuration, EXPECT_TRUE(myitem_callback_called); } -TEST(Test_LSP_Workspace_Configuration, - initialization_options_ignores_extra_entries) { - LSP_Workspace_Configuration config; +TEST_F(Test_LSP_Workspace_Configuration, + initialization_options_ignores_extra_entries) { + LSP_Workspace_Configuration config(&this->allocator); int myitem_callback_called_count = 0; auto myitem_callback = [&myitem_callback_called_count](std::string_view new_value) { @@ -278,9 +284,9 @@ TEST(Test_LSP_Workspace_Configuration, EXPECT_EQ(myitem_callback_called_count, 1); } -TEST(Test_LSP_Workspace_Configuration, - initialization_options_does_not_call_callback_for_unnotified_items) { - LSP_Workspace_Configuration config; +TEST_F(Test_LSP_Workspace_Configuration, + initialization_options_does_not_call_callback_for_unnotified_items) { + LSP_Workspace_Configuration config(&this->allocator); bool myitem_callback_called = false; auto myitem_callback = [&myitem_callback_called](std::string_view new_value) { myitem_callback_called = true; From 69f652bb0e35c5c174d9c6ccbb4e27da016733fa Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 15:01:10 -0400 Subject: [PATCH 038/117] refactor(lsp): std::vector -> Span add_watch_io_errors and handle_config_file_changes don't *need* a vector, they just need a list. Have them accept a Span instead to make this more obvious. --- src/quick-lint-js/cli/main.cpp | 3 ++- src/quick-lint-js/lsp/lsp-server.cpp | 14 +++++++++----- src/quick-lint-js/lsp/lsp-server.h | 5 ++--- test/test-lsp-server.cpp | 13 +++++++------ 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/quick-lint-js/cli/main.cpp b/src/quick-lint-js/cli/main.cpp index 1d2a94cc16..78d6c286bd 100644 --- a/src/quick-lint-js/cli/main.cpp +++ b/src/quick-lint-js/cli/main.cpp @@ -587,7 +587,8 @@ void run_lsp_server() { } void report_pending_watch_io_errors() { - this->handler_.add_watch_io_errors(this->fs_.take_watch_errors()); + this->handler_.add_watch_io_errors( + Span(this->fs_.take_watch_errors())); this->handler_.flush_pending_notifications(this->writer_); #if QLJS_EVENT_LOOP2_PIPE_WRITE this->enable_or_disable_writer_events_as_needed(); diff --git a/src/quick-lint-js/lsp/lsp-server.cpp b/src/quick-lint-js/lsp/lsp-server.cpp index 8346995356..62e08d948f 100644 --- a/src/quick-lint-js/lsp/lsp-server.cpp +++ b/src/quick-lint-js/lsp/lsp-server.cpp @@ -34,6 +34,7 @@ #include #include #include +#include using namespace std::literals::string_view_literals; @@ -222,12 +223,13 @@ void Linting_LSP_Server_Handler::filesystem_changed() { this->config_loader_.refresh(); { Lock_Ptr documents = this->documents_.lock(); - this->handle_config_file_changes(documents, config_changes); + this->handle_config_file_changes( + documents, Span(config_changes)); } } void Linting_LSP_Server_Handler::add_watch_io_errors( - const std::vector& errors) { + Span errors) { if (!errors.empty() && !this->did_report_watch_io_error_) { Byte_Buffer& out_json = this->outgoing_messages_.new_message(); // clang-format off @@ -366,7 +368,8 @@ void Linting_LSP_Server_Handler::handle_text_document_did_change_notification( case LSP_Documents::Document_Type::config: { std::vector config_changes = this->config_loader_.refresh(); - this->handle_config_file_changes(documents, config_changes); + this->handle_config_file_changes( + documents, Span(config_changes)); break; } @@ -517,7 +520,8 @@ void Linting_LSP_Server_Handler::handle_text_document_did_open_notification( this->config_loader_.refresh(); { Lock_Ptr documents = this->documents_.lock(); - this->handle_config_file_changes(documents, config_changes); + this->handle_config_file_changes( + documents, Span(config_changes)); } doc_ptr = std::move(doc); @@ -552,7 +556,7 @@ void Linting_LSP_Server_Handler:: void Linting_LSP_Server_Handler::handle_config_file_changes( Lock_Ptr& documents, - const std::vector& config_changes) { + Span config_changes) { for (auto& entry : documents->documents) { const String8& document_uri = entry.first; LSP_Documents::Document_Base& doc = *entry.second; diff --git a/src/quick-lint-js/lsp/lsp-server.h b/src/quick-lint-js/lsp/lsp-server.h index 6648ee781f..bfeb36b14f 100644 --- a/src/quick-lint-js/lsp/lsp-server.h +++ b/src/quick-lint-js/lsp/lsp-server.h @@ -29,7 +29,6 @@ #include #include #include -#include namespace quick_lint_js { class Byte_Buffer; @@ -150,7 +149,7 @@ class Linting_LSP_Server_Handler final : public JSON_RPC_Message_Handler { this->outgoing_messages_.send(remote); } - void add_watch_io_errors(const std::vector&); + void add_watch_io_errors(Span); private: void handle_initialize_request(::simdjson::ondemand::object& request, @@ -197,7 +196,7 @@ class Linting_LSP_Server_Handler final : public JSON_RPC_Message_Handler { void handle_config_file_changes( Lock_Ptr& documents, - const std::vector& config_changes); + Span config_changes); void get_config_file_diagnostics_notification(Loaded_Config_File*, String8_View uri_json, diff --git a/test/test-lsp-server.cpp b/test/test-lsp-server.cpp index 08c93c809a..8d53d3076d 100644 --- a/test/test-lsp-server.cpp +++ b/test/test-lsp-server.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -2339,7 +2340,7 @@ TEST_F(Test_Linting_LSP_Server, } TEST_F(Test_Linting_LSP_Server, showing_io_errors_shows_only_first) { - this->handler->add_watch_io_errors(std::vector{ + this->handler->add_watch_io_errors(Span({ Watch_IO_Error{ .path = "/banana", .io_error = generic_file_io_error, @@ -2348,7 +2349,7 @@ TEST_F(Test_Linting_LSP_Server, showing_io_errors_shows_only_first) { .path = "/orange", .io_error = generic_file_io_error, }, - }); + })); this->handler->flush_pending_notifications(*this->client); std::vector notifications = this->client->notifications(); @@ -2366,20 +2367,20 @@ TEST_F(Test_Linting_LSP_Server, showing_io_errors_shows_only_first) { } TEST_F(Test_Linting_LSP_Server, showing_io_errors_shows_only_first_ever) { - this->handler->add_watch_io_errors(std::vector{ + this->handler->add_watch_io_errors(Span({ Watch_IO_Error{ .path = "/banana", .io_error = generic_file_io_error, }, - }); + })); this->handler->flush_pending_notifications(*this->client); // Separate call to add_watch_io_errors: - this->handler->add_watch_io_errors(std::vector{ + this->handler->add_watch_io_errors(Span({ Watch_IO_Error{ .path = "/orange", .io_error = generic_file_io_error, }, - }); + })); this->handler->flush_pending_notifications(*this->client); std::vector notifications = this->client->notifications(); From 9f7bac89383ef1daf3350bcc0b762fcf48c85913 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 15:01:10 -0400 Subject: [PATCH 039/117] refactor(debug): prefer Bump_Vector over std::vector Reduce our use of std::vector to reduce binary bloat: https://github.com/quick-lint/quick-lint-js/issues/689 --- src/quick-lint-js/cli/main.cpp | 4 +- src/quick-lint-js/debug/find-debug-server.cpp | 117 ++++++++++-------- src/quick-lint-js/debug/find-debug-server.h | 6 +- test/test-debug-server.cpp | 3 +- 4 files changed, 74 insertions(+), 56 deletions(-) diff --git a/src/quick-lint-js/cli/main.cpp b/src/quick-lint-js/cli/main.cpp index 78d6c286bd..1055c84c54 100644 --- a/src/quick-lint-js/cli/main.cpp +++ b/src/quick-lint-js/cli/main.cpp @@ -348,12 +348,14 @@ Linter_Options get_linter_options_from_language( } void list_debug_apps() { + Monotonic_Allocator temporary_allocator("list_debug_apps"); + struct Table_Row { std::string process_id; std::string server_url; }; std::vector table; - for (const Found_Debug_Server &s : find_debug_servers()) { + for (const Found_Debug_Server &s : find_debug_servers(&temporary_allocator)) { table.push_back(Table_Row{ .process_id = std::to_string(s.process_id), .server_url = diff --git a/src/quick-lint-js/debug/find-debug-server.cpp b/src/quick-lint-js/debug/find-debug-server.cpp index 347e34d9e1..6397632143 100644 --- a/src/quick-lint-js/debug/find-debug-server.cpp +++ b/src/quick-lint-js/debug/find-debug-server.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -22,7 +23,6 @@ #include #include #include -#include #if defined(__linux__) #include @@ -257,8 +257,9 @@ void enumerate_all_process_thread_names(Callback&& callback) { #endif #if defined(__linux__) -std::vector find_debug_servers() { - std::vector debug_servers; +Span find_debug_servers(Monotonic_Allocator* allocator) { + Bump_Vector debug_servers( + "debug_servers", allocator); enumerate_all_process_thread_names([&](std::string_view process_id_string, std::string_view thread_name) { @@ -277,13 +278,14 @@ std::vector find_debug_servers() { } }); - return debug_servers; + return debug_servers.release_to_span(); } #endif #if defined(__APPLE__) template -void enumerate_all_process_threads(Callback&& callback) { +void enumerate_all_process_threads(Monotonic_Allocator& allocator, + Callback&& callback) { // Kernel code uses sizeof(int), not sizeof(::pid_t): // https://github.com/apple/darwin-xnu/blob/8f02f2a044b9bb1ad951987ef5bab20ec9486310/bsd/kern/proc_info.c#L339 // @@ -300,13 +302,16 @@ void enumerate_all_process_threads(Callback&& callback) { QLJS_ASSERT( narrow_cast(process_id_buffer_size) % sizeof(::pid_t) == 0); + Bump_Vector<::pid_t, Monotonic_Allocator> process_ids("process_ids", + &allocator); // NOTE(strager): It's okay if our buffer is to small. We miss out on some // processes, but they were just created anyway. Harmless race condition. - std::vector<::pid_t> process_ids( - narrow_cast(process_id_buffer_size) / sizeof(::pid_t)); - process_id_buffer_size = - ::proc_listpids(PROC_ALL_PIDS, 0, process_ids.data(), - narrow_cast(process_ids.size() * sizeof(::pid_t))); + process_ids.resize(narrow_cast(process_id_buffer_size) / + sizeof(::pid_t)); + process_id_buffer_size = ::proc_listpids( + PROC_ALL_PIDS, 0, process_ids.data(), + narrow_cast(process_ids.size() * + narrow_cast(sizeof(::pid_t)))); if (process_id_buffer_size == -1) { QLJS_DEBUG_LOG("%s: ignoring failure to get process IDs: %s\n", __func__, std::strerror(errno)); @@ -315,7 +320,8 @@ void enumerate_all_process_threads(Callback&& callback) { process_ids.resize(narrow_cast(process_id_buffer_size) / sizeof(int)); - std::vector thread_ids; + Bump_Vector thread_ids("thread_ids", + &allocator); constexpr std::size_t initial_thread_ids_buffer_count = 128; // Arbitrary. for (::pid_t process_id : process_ids) { thread_ids.resize(initial_thread_ids_buffer_count); @@ -323,7 +329,8 @@ void enumerate_all_process_threads(Callback&& callback) { int thread_ids_buffer_size = ::proc_pidinfo( process_id, PROC_PIDLISTTHREADIDS, /*arg=*/0, thread_ids.data(), - narrow_cast(thread_ids.size() * sizeof(std::uint64_t))); + narrow_cast(thread_ids.size() * + narrow_cast(sizeof(std::uint64_t)))); if (thread_ids_buffer_size == -1) { QLJS_DEBUG_LOG( "%s: ignoring failure to get thread IDs for process %d: %s\n", @@ -333,10 +340,10 @@ void enumerate_all_process_threads(Callback&& callback) { QLJS_ASSERT(narrow_cast(thread_ids_buffer_size) % sizeof(std::uint64_t) == 0); - std::size_t thread_count = - narrow_cast(thread_ids_buffer_size) / - sizeof(std::uint64_t); - if (thread_count == thread_ids.size()) { + Bump_Vector_Size thread_count = + narrow_cast(thread_ids_buffer_size) / + narrow_cast(sizeof(std::uint64_t)); + if (narrow_cast(thread_count) == thread_ids.size()) { // We can't tell if we read exactly all the threads or if there are more // threads. Assume there are more threads. thread_ids.resize(thread_ids.size() * 2); @@ -352,42 +359,45 @@ void enumerate_all_process_threads(Callback&& callback) { #endif #if defined(__APPLE__) -std::vector find_debug_servers() { +Span find_debug_servers(Monotonic_Allocator* allocator) { static constexpr char func[] = "find_debug_servers"; - std::vector debug_servers; - enumerate_all_process_threads([&](::pid_t process_id, - std::uint64_t thread_id) -> void { - ::proc_threadinfo thread_info; - int rc = - ::proc_pidinfo(process_id, PROC_PIDTHREADID64INFO, - /*arg=*/thread_id, &thread_info, sizeof(thread_info)); - if (rc == -1) { - QLJS_DEBUG_LOG( - "%s: ignoring failure to get name of thread %llu in process %d: %s\n", - func, narrow_cast(thread_id), process_id, - std::strerror(errno)); - return; - } - QLJS_ASSERT(rc == sizeof(thread_info)); - - std::string_view thread_name( - thread_info.pth_name, - ::strnlen(thread_info.pth_name, MAXTHREADNAMESIZE)); - if (std::optional port_number = - parse_port_number_from_thread_name(to_string8_view(thread_name))) { - debug_servers.push_back(Found_Debug_Server{ - .process_id = narrow_cast(process_id), - .port_number = *port_number, + Bump_Vector debug_servers( + "debug_servers", allocator); + enumerate_all_process_threads( + *allocator, [&](::pid_t process_id, std::uint64_t thread_id) -> void { + ::proc_threadinfo thread_info; + int rc = ::proc_pidinfo(process_id, PROC_PIDTHREADID64INFO, + /*arg=*/thread_id, &thread_info, + sizeof(thread_info)); + if (rc == -1) { + QLJS_DEBUG_LOG( + "%s: ignoring failure to get name of thread %llu in process %d: " + "%s\n", + func, narrow_cast(thread_id), process_id, + std::strerror(errno)); + return; + } + QLJS_ASSERT(rc == sizeof(thread_info)); + + std::string_view thread_name( + thread_info.pth_name, + ::strnlen(thread_info.pth_name, MAXTHREADNAMESIZE)); + if (std::optional port_number = + parse_port_number_from_thread_name( + to_string8_view(thread_name))) { + debug_servers.push_back(Found_Debug_Server{ + .process_id = narrow_cast(process_id), + .port_number = *port_number, + }); + } }); - } - }); - return debug_servers; + return debug_servers.release_to_span(); } #endif #if defined(__FreeBSD__) -std::vector find_debug_servers() { +Span find_debug_servers(Monotonic_Allocator* allocator) { static constexpr char func[] = "find_debug_servers"; // NOTE(Nico): On FreeBSD we can just fetch the list of all active LWPs by @@ -409,7 +419,8 @@ std::vector find_debug_servers() { size_t own_jid_size; ::kinfo_proc* p; ::kvm_t* kd; - std::vector debug_servers; + Bump_Vector debug_servers( + "debug_servers", allocator); // Query our own jail id own_jid_size = sizeof own_jid; @@ -458,7 +469,7 @@ std::vector find_debug_servers() { error_get_procs: ::kvm_close(kd); error_open_kvm: - return debug_servers; + return debug_servers.release_to_span(); } #endif // __FreeBSD__ @@ -505,10 +516,11 @@ void enumerate_all_process_threads(Callback&& callback) { #endif #if defined(_WIN32) -std::vector find_debug_servers() { +Span find_debug_servers(Monotonic_Allocator* allocator) { static constexpr char func[] = "find_debug_servers"; - std::vector debug_servers; + Bump_Vector debug_servers( + "debug_servers", allocator); enumerate_all_process_threads([&](::DWORD process_id, ::DWORD thread_id) -> void { Windows_Handle_File thread_handle( @@ -564,14 +576,15 @@ std::vector find_debug_servers() { ::LocalFree(thread_name); }); - return debug_servers; + return debug_servers.release_to_span(); } #endif #if !QLJS_CAN_FIND_DEBUG_SERVERS -std::vector find_debug_servers() { +Span find_debug_servers([ + [maybe_unused]] Monotonic_Allocator* allocator) { #warning "--debug-apps is not supported on this platform" - return std::vector(); + return Span(); } #endif } diff --git a/src/quick-lint-js/debug/find-debug-server.h b/src/quick-lint-js/debug/find-debug-server.h index e116d7b05b..55da591328 100644 --- a/src/quick-lint-js/debug/find-debug-server.h +++ b/src/quick-lint-js/debug/find-debug-server.h @@ -4,8 +4,8 @@ #pragma once #include +#include #include -#include namespace quick_lint_js { #if QLJS_FEATURE_DEBUG_SERVER @@ -32,8 +32,10 @@ struct Found_Debug_Server { // This function is inherently racy. By the time this function returns, any // number of returned debug servers might be dead. // +// allocator is used to allocate memory for the returned Span. +// // NOTE[find-debug-server] for implementation details. -std::vector find_debug_servers(); +Span find_debug_servers(Monotonic_Allocator* allocator); } // quick-lint-js finds bugs in JavaScript programs. diff --git a/test/test-debug-server.cpp b/test/test-debug-server.cpp index 34257e363b..c069352f49 100644 --- a/test/test-debug-server.cpp +++ b/test/test-debug-server.cpp @@ -538,7 +538,8 @@ TEST_F(Test_Debug_Server, find_debug_servers_finds_running_instance_SLOW) { ASSERT_TRUE(wait_result.ok()) << wait_result.error_to_string(); std::uint16_t server_port = server->tcp_port_number(); - std::vector servers = find_debug_servers(); + Monotonic_Allocator allocator("Test_Debug_Server"); + Span servers = find_debug_servers(&allocator); auto found_server_it = find_first_if(servers, [&](const Found_Debug_Server &s) -> bool { return s.port_number == server_port; From 7cd5f3d6514469758656d50e5e46ba02a2b59908 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 15:01:10 -0400 Subject: [PATCH 040/117] refactor(lsp): std::vector -> Span use_messages_from_locales doesn't *need* a vector, it just needs a list. Have it accept a Span instead to make this more obvious. --- src/quick-lint-js/i18n/translation.cpp | 6 ++++-- src/quick-lint-js/i18n/translation.h | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/quick-lint-js/i18n/translation.cpp b/src/quick-lint-js/i18n/translation.cpp index 533960e3d1..91741303a4 100644 --- a/src/quick-lint-js/i18n/translation.cpp +++ b/src/quick-lint-js/i18n/translation.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -72,7 +73,8 @@ void initialize_locale() { void initialize_translations_from_environment() { initialize_locale(); - if (!qljs_messages.use_messages_from_locales(get_user_locale_preferences())) { + if (!qljs_messages.use_messages_from_locales( + Span(get_user_locale_preferences()))) { qljs_messages.use_messages_from_source_code(); } } @@ -100,7 +102,7 @@ bool Translator::use_messages_from_locale(const char* locale_name) { } bool Translator::use_messages_from_locales( - const std::vector& locale_names) { + Span locale_names) { for (const std::string& locale : locale_names) { if (locale == "C" || locale == "POSIX") { // Stop seaching. C/POSIX locale takes priority. See GNU gettext. diff --git a/src/quick-lint-js/i18n/translation.h b/src/quick-lint-js/i18n/translation.h index b4967f2eb7..4bf0189f21 100644 --- a/src/quick-lint-js/i18n/translation.h +++ b/src/quick-lint-js/i18n/translation.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -27,7 +28,7 @@ class Translator { void use_messages_from_source_code(); bool use_messages_from_locale(const char* locale_name); - bool use_messages_from_locales(const std::vector& locale_names); + bool use_messages_from_locales(Span locale_names); const Char8* translate(const Translatable_Message& message); From 92157ff1f671ce5f7c918cb1929882b47c12b716 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 15:01:10 -0400 Subject: [PATCH 041/117] refactor(i18n): don't assume null-terminated when parsing locale Currently, locale names are null-terminated. This forces us to copy strings in get_user_locale_preferences which splits the user-provided LANGUAGE variable. Refactor parse_locale to accept a string_view instead of a null-terminated string. --- src/quick-lint-js/i18n/locale.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/quick-lint-js/i18n/locale.cpp b/src/quick-lint-js/i18n/locale.cpp index df7c953ea2..5ddcd26060 100644 --- a/src/quick-lint-js/i18n/locale.cpp +++ b/src/quick-lint-js/i18n/locale.cpp @@ -27,19 +27,19 @@ struct Locale_Parts { std::string_view& language() { return this->parts[this->language_index]; } }; -Locale_Parts parse_locale(const char* locale_name) { +Locale_Parts parse_locale(std::string_view locale_name) { struct Found_Separator { std::size_t length; std::size_t which_separator; }; - auto find_next_separator = [](const char* c, + auto find_next_separator = [](std::string_view s, const char* separators) -> Found_Separator { - std::size_t length = std::strcspn(c, separators); - if (c[length] == '\0') { - return Found_Separator{.length = length, + std::size_t length = s.find_first_of(separators); + if (length == s.npos) { + return Found_Separator{.length = s.size(), .which_separator = static_cast(-1)}; } - const char* separator = std::strchr(separators, c[length]); + const char* separator = std::strchr(separators, s[length]); QLJS_ASSERT(separator); return Found_Separator{ .length = length, @@ -50,19 +50,20 @@ Locale_Parts parse_locale(const char* locale_name) { const char* current_separators = &locale_part_separators[0]; std::string_view* current_part = &parts.language(); - const char* c = locale_name; + std::string_view remaining_locale_name = locale_name; for (;;) { - Found_Separator part = find_next_separator(c, current_separators); - *current_part = std::string_view(c, part.length); - c += part.length; - if (*c == '\0') { + Found_Separator part = + find_next_separator(remaining_locale_name, current_separators); + *current_part = remaining_locale_name.substr(0, part.length); + remaining_locale_name = remaining_locale_name.substr(part.length); + if (remaining_locale_name.empty()) { break; } QLJS_ASSERT(part.which_separator != static_cast(-1)); current_separators += part.which_separator + 1; current_part += part.which_separator + 1; - c += 1; + remaining_locale_name = remaining_locale_name.substr(1); } return parts; } From fa46bd0bebbabf2db6da8cf99197d57e01f76dd3 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 15:01:10 -0400 Subject: [PATCH 042/117] refactor(i18): use string_view for separator list in parse_locale In parse_locale, don't mix pointer style and string_view style; use string_view style consistently. --- src/quick-lint-js/i18n/locale.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/quick-lint-js/i18n/locale.cpp b/src/quick-lint-js/i18n/locale.cpp index 5ddcd26060..2ecd1a2692 100644 --- a/src/quick-lint-js/i18n/locale.cpp +++ b/src/quick-lint-js/i18n/locale.cpp @@ -11,9 +11,11 @@ #include #include +using namespace std::literals::string_view_literals; + namespace quick_lint_js { namespace { -constexpr const char locale_part_separators[] = "_.@"; +constexpr std::string_view locale_part_separators = "_.@"sv; struct Locale_Parts { // language, territory, codeset, modifier @@ -32,23 +34,22 @@ Locale_Parts parse_locale(std::string_view locale_name) { std::size_t length; std::size_t which_separator; }; - auto find_next_separator = [](std::string_view s, - const char* separators) -> Found_Separator { + auto find_next_separator = + [](std::string_view s, std::string_view separators) -> Found_Separator { std::size_t length = s.find_first_of(separators); if (length == s.npos) { return Found_Separator{.length = s.size(), .which_separator = static_cast(-1)}; } - const char* separator = std::strchr(separators, s[length]); - QLJS_ASSERT(separator); - return Found_Separator{ - .length = length, - .which_separator = narrow_cast(separator - separators)}; + std::size_t which_separator = separators.find(s[length]); + QLJS_ASSERT(which_separator != separators.npos); + return Found_Separator{.length = length, + .which_separator = which_separator}; }; Locale_Parts parts; - const char* current_separators = &locale_part_separators[0]; + std::string_view current_separators = locale_part_separators; std::string_view* current_part = &parts.language(); std::string_view remaining_locale_name = locale_name; for (;;) { @@ -61,7 +62,7 @@ Locale_Parts parse_locale(std::string_view locale_name) { } QLJS_ASSERT(part.which_separator != static_cast(-1)); - current_separators += part.which_separator + 1; + current_separators = current_separators.substr(part.which_separator + 1); current_part += part.which_separator + 1; remaining_locale_name = remaining_locale_name.substr(1); } From a3b4b789aaad62e89c04774251efb218360dde8c Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 15:01:10 -0400 Subject: [PATCH 043/117] refactor(i18n): remove std::vector from public API Reduce our use of std::vector in non-test code to reduce binary bloat: https://github.com/quick-lint/quick-lint-js/issues/689 --- src/quick-lint-js/i18n/locale.cpp | 14 ++++++-------- src/quick-lint-js/i18n/locale.h | 9 ++++++--- test/test-locale.cpp | 10 ++++++++++ 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/quick-lint-js/i18n/locale.cpp b/src/quick-lint-js/i18n/locale.cpp index 2ecd1a2692..baa30252e9 100644 --- a/src/quick-lint-js/i18n/locale.cpp +++ b/src/quick-lint-js/i18n/locale.cpp @@ -93,14 +93,12 @@ std::optional find_locale(const char* locales, const char* locale_name) { return found_entry; } -std::vector locale_name_combinations(const char* locale_name) { - std::vector locale_names; - locale_name_combinations(locale_name, - [&](std::string_view current_locale) -> bool { - locale_names.emplace_back(current_locale); - return true; - }); - return locale_names; +void enumerate_locale_name_combinations( + const char* locale_name, + Temporary_Function_Ref callback) { + return locale_name_combinations< + Temporary_Function_Ref>( + locale_name, std::move(callback)); } namespace { diff --git a/src/quick-lint-js/i18n/locale.h b/src/quick-lint-js/i18n/locale.h index 28d5445245..6ce1a3ceac 100644 --- a/src/quick-lint-js/i18n/locale.h +++ b/src/quick-lint-js/i18n/locale.h @@ -5,8 +5,8 @@ #include #include -#include -#include +#include +#include namespace quick_lint_js { // Returns the index of the matching locale. @@ -15,7 +15,10 @@ namespace quick_lint_js { // result will be 1. std::optional find_locale(const char* locales, const char* locale_name); -std::vector locale_name_combinations(const char* locale_name); +// For testing only. +void enumerate_locale_name_combinations( + const char* locale_name, + Temporary_Function_Ref); } // quick-lint-js finds bugs in JavaScript programs. diff --git a/test/test-locale.cpp b/test/test-locale.cpp index 028b7676ba..9f94283ef6 100644 --- a/test/test-locale.cpp +++ b/test/test-locale.cpp @@ -11,6 +11,16 @@ using namespace std::literals::string_view_literals; namespace quick_lint_js { namespace { +std::vector locale_name_combinations(const char* locale_name) { + std::vector locale_names; + enumerate_locale_name_combinations( + locale_name, [&](std::string_view current_locale) -> bool { + locale_names.emplace_back(current_locale); + return true; + }); + return locale_names; +} + TEST(Test_Locale, combinations_for_language) { EXPECT_THAT(locale_name_combinations("en"), ElementsAreArray({"en"})); } From 28d55cd095d0e9f9359ce9836e5f7975575eb020 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 17:05:59 -0400 Subject: [PATCH 044/117] refactor(port): prefer Bump_Vector over std::vector Reduce our use of std::vector to reduce binary bloat: https://github.com/quick-lint/quick-lint-js/issues/689 --- src/quick-lint-js/port/child-process.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/quick-lint-js/port/child-process.cpp b/src/quick-lint-js/port/child-process.cpp index f50ffd0192..bb5bdd5d1c 100644 --- a/src/quick-lint-js/port/child-process.cpp +++ b/src/quick-lint-js/port/child-process.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include #include @@ -17,7 +19,6 @@ #include #include #include -#include #if QLJS_HAVE_CRT_EXTERNS_H #include @@ -84,7 +85,9 @@ Run_Program_Result run_program(Span command) { Run_Program_Result run_program(Span command, Run_Program_Options options) { - std::vector command_raw; + Monotonic_Allocator allocator("run_program"); + Bump_Vector command_raw("command_raw", + &allocator); for (const std::string& arg : command) { command_raw.push_back(arg.c_str()); } @@ -119,7 +122,8 @@ Run_Program_Result run_program(Span command, set_current_working_directory_or_exit(options.current_directory); } - std::vector argv; + Monotonic_Allocator allocator("run_program"); + Bump_Vector argv("argv", &allocator); for (const char* arg : command) { argv.push_back(const_cast(arg)); } From f74d834fc9876b3faaa342dc05122c89672913c6 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 17:37:21 -0400 Subject: [PATCH 045/117] refactor(io): prefer Bump_Vector over std::vector Reduce our use of std::vector to reduce binary bloat: https://github.com/quick-lint/quick-lint-js/issues/689 --- src/quick-lint-js/io/event-loop-poll.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/quick-lint-js/io/event-loop-poll.cpp b/src/quick-lint-js/io/event-loop-poll.cpp index 747abf15e6..8910816313 100644 --- a/src/quick-lint-js/io/event-loop-poll.cpp +++ b/src/quick-lint-js/io/event-loop-poll.cpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include #include #include @@ -70,9 +72,11 @@ Event_Loop_Poll::Event_Loop_Poll() : impl_(new Impl()) { Event_Loop_Poll::~Event_Loop_Poll() { delete this->impl_; } void Event_Loop_Poll::run() { + Monotonic_Allocator allocator("Event_Loop_Poll"); // events[i] corresponds to event_registered_events[i]. - std::vector<::pollfd> events; - std::vector event_registered_events; + Bump_Vector<::pollfd, Monotonic_Allocator> events("events", &allocator); + Bump_Vector + event_registered_events("event_registered_events", &allocator); while (!this->is_stop_requested()) { events.clear(); @@ -112,7 +116,7 @@ void Event_Loop_Poll::run() { } QLJS_ASSERT(rc > 0); - for (std::size_t i = 0; i < events.size(); ++i) { + for (Bump_Vector_Size i = 0; i < events.size(); ++i) { const ::pollfd& event = events[i]; if (event.revents == 0) { continue; From 2891afc13c51a2d2b896b1b273e3e665d425cbe5 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 18:29:41 -0400 Subject: [PATCH 046/117] refactor(i18n): char* -> std::string_view Prefer std::string_view over char* so make it clear that null terminators are not required. --- src/quick-lint-js/i18n/locale.cpp | 11 ++++++----- src/quick-lint-js/i18n/locale.h | 5 +++-- src/quick-lint-js/i18n/translation.cpp | 23 ++++++++++++----------- src/quick-lint-js/i18n/translation.h | 6 +++--- 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/quick-lint-js/i18n/locale.cpp b/src/quick-lint-js/i18n/locale.cpp index baa30252e9..a34d2f1419 100644 --- a/src/quick-lint-js/i18n/locale.cpp +++ b/src/quick-lint-js/i18n/locale.cpp @@ -70,10 +70,11 @@ Locale_Parts parse_locale(std::string_view locale_name) { } template -void locale_name_combinations(const char* locale_name, Func&& callback); +void locale_name_combinations(std::string_view locale_name, Func&& callback); } -std::optional find_locale(const char* locales, const char* locale_name) { +std::optional find_locale(const char* locales, + std::string_view locale_name) { // NOTE[locale-list-null-terminator]: The code generator guarantees that there // is an empty string at the end of the list (i.e. two null bytes at the end). C_String_List_View locales_list(locales); @@ -94,7 +95,7 @@ std::optional find_locale(const char* locales, const char* locale_name) { } void enumerate_locale_name_combinations( - const char* locale_name, + std::string_view locale_name, Temporary_Function_Ref callback) { return locale_name_combinations< Temporary_Function_Ref>( @@ -106,11 +107,11 @@ QLJS_WARNING_PUSH QLJS_WARNING_IGNORE_GCC("-Wzero-as-null-pointer-constant") template -void locale_name_combinations(const char* locale_name, Func&& callback) { +void locale_name_combinations(std::string_view locale_name, Func&& callback) { Locale_Parts parts = parse_locale(locale_name); std::vector locale; - std::size_t max_locale_size = std::strlen(locale_name); + std::size_t max_locale_size = locale_name.size(); locale.reserve(max_locale_size); locale.insert(locale.end(), parts.language().begin(), parts.language().end()); diff --git a/src/quick-lint-js/i18n/locale.h b/src/quick-lint-js/i18n/locale.h index 6ce1a3ceac..13e990b608 100644 --- a/src/quick-lint-js/i18n/locale.h +++ b/src/quick-lint-js/i18n/locale.h @@ -13,11 +13,12 @@ namespace quick_lint_js { // // If locales is "en_US\0fr_FR\0de_DE\0", and locale_name is "fr_FR", then the // result will be 1. -std::optional find_locale(const char* locales, const char* locale_name); +std::optional find_locale(const char* locales, + std::string_view locale_name); // For testing only. void enumerate_locale_name_combinations( - const char* locale_name, + std::string_view locale_name, Temporary_Function_Ref); } diff --git a/src/quick-lint-js/i18n/translation.cpp b/src/quick-lint-js/i18n/translation.cpp index 91741303a4..57caf17dc7 100644 --- a/src/quick-lint-js/i18n/translation.cpp +++ b/src/quick-lint-js/i18n/translation.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -22,12 +23,12 @@ namespace quick_lint_js { Translator qljs_messages; namespace { -std::vector split_on(const char* s, char separator) { - std::vector locales; +std::vector split_on(const char* s, char separator) { + std::vector locales; for (;;) { const char* sep = std::strchr(s, separator); if (sep) { - locales.emplace_back(s, sep); + locales.emplace_back(make_string_view(s, sep)); s = sep + 1; } else { locales.emplace_back(s); @@ -37,7 +38,7 @@ std::vector split_on(const char* s, char separator) { return locales; } -std::vector get_user_locale_preferences() { +std::vector get_user_locale_preferences() { // This lookup order roughly mimics GNU gettext. int category = @@ -74,12 +75,12 @@ void initialize_locale() { void initialize_translations_from_environment() { initialize_locale(); if (!qljs_messages.use_messages_from_locales( - Span(get_user_locale_preferences()))) { + Span(get_user_locale_preferences()))) { qljs_messages.use_messages_from_source_code(); } } -void initialize_translations_from_locale(const char* locale_name) { +void initialize_translations_from_locale(std::string_view locale_name) { initialize_locale(); if (!qljs_messages.use_messages_from_locale(locale_name)) { qljs_messages.use_messages_from_source_code(); @@ -91,7 +92,7 @@ void Translator::use_messages_from_source_code() { this->locale_index_ = translation_table_locale_count; } -bool Translator::use_messages_from_locale(const char* locale_name) { +bool Translator::use_messages_from_locale(std::string_view locale_name) { std::optional locale_index = find_locale(translation_data.locale_table, locale_name); if (locale_index.has_value()) { @@ -102,13 +103,13 @@ bool Translator::use_messages_from_locale(const char* locale_name) { } bool Translator::use_messages_from_locales( - Span locale_names) { - for (const std::string& locale : locale_names) { - if (locale == "C" || locale == "POSIX") { + Span locale_names) { + for (const std::string_view& locale : locale_names) { + if (locale == "C"sv || locale == "POSIX"sv) { // Stop seaching. C/POSIX locale takes priority. See GNU gettext. break; } - bool found_messages = this->use_messages_from_locale(locale.c_str()); + bool found_messages = this->use_messages_from_locale(locale); if (found_messages) { return true; } diff --git a/src/quick-lint-js/i18n/translation.h b/src/quick-lint-js/i18n/translation.h index 4bf0189f21..6b605138fc 100644 --- a/src/quick-lint-js/i18n/translation.h +++ b/src/quick-lint-js/i18n/translation.h @@ -19,7 +19,7 @@ namespace quick_lint_js { class Translatable_Message; void initialize_translations_from_environment(); -void initialize_translations_from_locale(const char* locale_name); +void initialize_translations_from_locale(std::string_view locale_name); class Translator { public: @@ -27,8 +27,8 @@ class Translator { explicit Translator() = default; void use_messages_from_source_code(); - bool use_messages_from_locale(const char* locale_name); - bool use_messages_from_locales(Span locale_names); + bool use_messages_from_locale(std::string_view locale_name); + bool use_messages_from_locales(Span locale_names); const Char8* translate(const Translatable_Message& message); From 104cc7688c04c06e0336a3b420d7f11e64a8ae8a Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 18:27:18 -0400 Subject: [PATCH 047/117] refactor(i18n): prefer Bump_Vector over std::vector Reduce our use of std::vector to reduce binary bloat: https://github.com/quick-lint/quick-lint-js/issues/689 --- src/quick-lint-js/i18n/translation.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/quick-lint-js/i18n/translation.cpp b/src/quick-lint-js/i18n/translation.cpp index 57caf17dc7..8f984a64a9 100644 --- a/src/quick-lint-js/i18n/translation.cpp +++ b/src/quick-lint-js/i18n/translation.cpp @@ -6,14 +6,15 @@ #include #include #include +#include #include +#include #include #include #include #include #include #include -#include using namespace std::literals::string_view_literals; @@ -23,8 +24,10 @@ namespace quick_lint_js { Translator qljs_messages; namespace { -std::vector split_on(const char* s, char separator) { - std::vector locales; +Span split_on(const char* s, char separator, + Monotonic_Allocator* allocator) { + Bump_Vector locales("locales", + allocator); for (;;) { const char* sep = std::strchr(s, separator); if (sep) { @@ -35,10 +38,11 @@ std::vector split_on(const char* s, char separator) { break; } } - return locales; + return locales.release_to_span(); } -std::vector get_user_locale_preferences() { +Span get_user_locale_preferences( + Monotonic_Allocator* allocator) { // This lookup order roughly mimics GNU gettext. int category = @@ -55,13 +59,16 @@ std::vector get_user_locale_preferences() { const char* language_env = ::getenv("LANGUAGE"); if (language_env && language_env[0] != '\0') { - return split_on(language_env, ':'); + return split_on(language_env, ':', allocator); } // TODO(strager): Determine the language using macOS' and Windows' native // APIs. See GNU gettext's _nl_language_preferences_default. - return {locale}; + Bump_Vector locales("locales", + allocator); + locales.push_back(locale); + return locales.release_to_span(); } void initialize_locale() { @@ -74,8 +81,9 @@ void initialize_locale() { void initialize_translations_from_environment() { initialize_locale(); + Monotonic_Allocator allocator("initialize_translations_from_environment"); if (!qljs_messages.use_messages_from_locales( - Span(get_user_locale_preferences()))) { + get_user_locale_preferences(&allocator))) { qljs_messages.use_messages_from_source_code(); } } From 2bc65b9982bcdd5befc25fcdb3ccefa5508d9604 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 21:18:02 -0400 Subject: [PATCH 048/117] refactor(container): delete unused Byte_Buffer::to_iovec This function is only used in tests. Delete it, preferring Byte_Buffer_IOVec::append instead. --- src/quick-lint-js/container/byte-buffer.cpp | 6 ------ src/quick-lint-js/container/byte-buffer.h | 4 ---- test/test-byte-buffer.cpp | 24 ++++++++++++++------- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/quick-lint-js/container/byte-buffer.cpp b/src/quick-lint-js/container/byte-buffer.cpp index bfb66ba0f4..006874ca98 100644 --- a/src/quick-lint-js/container/byte-buffer.cpp +++ b/src/quick-lint-js/container/byte-buffer.cpp @@ -161,12 +161,6 @@ String8 Byte_Buffer::to_string8() const { return s; } -Byte_Buffer_IOVec Byte_Buffer::to_iovec() && { - this->update_current_chunk_size(); - this->remove_current_chunk_if_empty(); - return Byte_Buffer_IOVec(std::move(this->chunks_)); -} - void Byte_Buffer::reserve(Size_Type extra_byte_count) { if (this->bytes_remaining_in_current_chunk() < extra_byte_count) { this->grow(extra_byte_count); diff --git a/src/quick-lint-js/container/byte-buffer.h b/src/quick-lint-js/container/byte-buffer.h index c1789de051..72c798c9cf 100644 --- a/src/quick-lint-js/container/byte-buffer.h +++ b/src/quick-lint-js/container/byte-buffer.h @@ -87,10 +87,6 @@ class Byte_Buffer { // For testing. String8 to_string8() const; - // After calling this->to_iovec(), do not call any other member function on - // this byte_buffer (aside from the destructor). - Byte_Buffer_IOVec to_iovec() &&; - template void enumerate_chunks(Func&& on_chunk) const { for (std::size_t chunk_index = 0; chunk_index < this->chunks_.size(); diff --git a/test/test-byte-buffer.cpp b/test/test-byte-buffer.cpp index d0682fb911..ae2a9e512c 100644 --- a/test/test-byte-buffer.cpp +++ b/test/test-byte-buffer.cpp @@ -256,7 +256,8 @@ TEST(Test_Byte_Buffer, append_byte_buffer_to_byte_buffer_iovec) { bb_2.append_copy(u8"WORLD"_sv); bb_2_expected.append(u8"WORLD"); - Byte_Buffer_IOVec iov = std::move(bb_1).to_iovec(); + Byte_Buffer_IOVec iov; + iov.append(std::move(bb_1)); String8 iov_expected = bb_1_expected; iov.append(std::move(bb_2)); iov_expected.append(bb_2_expected); @@ -267,7 +268,8 @@ TEST(Test_Byte_Buffer, append_byte_buffer_to_byte_buffer_iovec) { TEST(Test_Byte_Buffer, append_empty_byte_buffer_to_byte_buffer_iovec) { Byte_Buffer bb_1; bb_1.append_copy(u8"hello"_sv); - Byte_Buffer_IOVec iov = std::move(bb_1).to_iovec(); + Byte_Buffer_IOVec iov; + iov.append(std::move(bb_1)); Byte_Buffer bb_2; iov.append(std::move(bb_2)); @@ -278,7 +280,8 @@ TEST(Test_Byte_Buffer, append_empty_byte_buffer_to_byte_buffer_iovec) { TEST(Test_Byte_Buffer, append_byte_buffer_to_indirectly_empty_byte_buffer_iovec) { Byte_Buffer bb_1; - Byte_Buffer_IOVec iov = std::move(bb_1).to_iovec(); + Byte_Buffer_IOVec iov; + iov.append(std::move(bb_1)); Byte_Buffer bb_2; bb_2.append_copy(u8"hello"_sv); @@ -330,13 +333,15 @@ TEST(Test_Byte_Buffer, iovec) { bb.append_copy(String8_View(small_data)); expected_data.append(small_data); - Byte_Buffer_IOVec iovec = std::move(bb).to_iovec(); + Byte_Buffer_IOVec iovec; + iovec.append(std::move(bb)); EXPECT_EQ(get_data(iovec), expected_data); } TEST(Test_Byte_Buffer, empty_byte_buffer_to_iovec_has_no_chunks) { Byte_Buffer bb; - Byte_Buffer_IOVec iovec = std::move(bb).to_iovec(); + Byte_Buffer_IOVec iovec; + iovec.append(std::move(bb)); EXPECT_EQ(iovec.iovec_count(), 0); } @@ -348,7 +353,8 @@ TEST(Test_Byte_Buffer, // to Byte_Buffer_IOVec. Byte_Buffer bb; bb.append_copy(String8(Byte_Buffer::default_chunk_size * 3, 'x')); - Byte_Buffer_IOVec iovec = std::move(bb).to_iovec(); + Byte_Buffer_IOVec iovec; + iovec.append(std::move(bb)); assert_no_empty_iovec(iovec); } @@ -359,7 +365,8 @@ TEST(Test_Byte_Buffer, // Byte_Buffer_IOVec. Byte_Buffer bb; bb.append(1, []([[maybe_unused]] void* data) -> std::size_t { return 0; }); - Byte_Buffer_IOVec iovec = std::move(bb).to_iovec(); + Byte_Buffer_IOVec iovec; + iovec.append(std::move(bb)); assert_no_empty_iovec(iovec); } @@ -372,7 +379,8 @@ TEST(Test_Byte_Buffer, Byte_Buffer bb; bb.append(Byte_Buffer::default_chunk_size * 3, []([[maybe_unused]] void* data) -> std::size_t { return 0; }); - Byte_Buffer_IOVec iovec = std::move(bb).to_iovec(); + Byte_Buffer_IOVec iovec; + iovec.append(std::move(bb)); assert_no_empty_iovec(iovec); } From ce989c0380c6570f8d4cf4b2ef1918c37f32ddf9 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 21:39:07 -0400 Subject: [PATCH 049/117] refactor(container): delete test-only Byte_Buffer_IOVec constructor The non-default Byte_Buffer_IOVec constructor is only used in tests, not in production code. Remove it and make tests use the same code paths that production code uses. --- src/quick-lint-js/container/byte-buffer.cpp | 16 +-- src/quick-lint-js/container/byte-buffer.h | 1 - test/test-byte-buffer.cpp | 130 ++++++++++---------- 3 files changed, 68 insertions(+), 79 deletions(-) diff --git a/src/quick-lint-js/container/byte-buffer.cpp b/src/quick-lint-js/container/byte-buffer.cpp index 006874ca98..fb1a82f95a 100644 --- a/src/quick-lint-js/container/byte-buffer.cpp +++ b/src/quick-lint-js/container/byte-buffer.cpp @@ -212,20 +212,8 @@ void Byte_Buffer::delete_chunk(Byte_Buffer_Chunk&& c) { delete[] chunk_begin(c); } -Byte_Buffer_IOVec::Byte_Buffer_IOVec() - : Byte_Buffer_IOVec(std::vector()) {} - -Byte_Buffer_IOVec::Byte_Buffer_IOVec(std::vector&& chunks) - : chunks_(std::move(chunks)), first_chunk_index_(0) { - if (this->chunks_.empty()) { - this->first_chunk_allocation_ = make_chunk(nullptr, 0); - } else { - this->first_chunk_allocation_ = this->chunks_.front(); - } - - for (const Byte_Buffer_Chunk& c : this->chunks_) { - QLJS_ASSERT(chunk_size(c) > 0); - } +Byte_Buffer_IOVec::Byte_Buffer_IOVec() : first_chunk_index_(0) { + this->first_chunk_allocation_ = make_chunk(nullptr, 0); } Byte_Buffer_IOVec::Byte_Buffer_IOVec(Byte_Buffer_IOVec&&) = default; diff --git a/src/quick-lint-js/container/byte-buffer.h b/src/quick-lint-js/container/byte-buffer.h index 72c798c9cf..891a84df40 100644 --- a/src/quick-lint-js/container/byte-buffer.h +++ b/src/quick-lint-js/container/byte-buffer.h @@ -148,7 +148,6 @@ class Byte_Buffer_IOVec { using Size_Type = Byte_Buffer::Size_Type; explicit Byte_Buffer_IOVec(); - explicit Byte_Buffer_IOVec(std::vector&&); Byte_Buffer_IOVec(Byte_Buffer_IOVec&&); Byte_Buffer_IOVec& operator=(Byte_Buffer_IOVec&&) = delete; diff --git a/test/test-byte-buffer.cpp b/test/test-byte-buffer.cpp index ae2a9e512c..aeeb5e7b64 100644 --- a/test/test-byte-buffer.cpp +++ b/test/test-byte-buffer.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -20,8 +21,9 @@ using namespace std::literals::string_view_literals; namespace quick_lint_js { namespace { String8 get_data(const Byte_Buffer_IOVec&); -Byte_Buffer_Chunk make_chunk(String8_View); void assert_no_empty_iovec(const Byte_Buffer_IOVec&); +Byte_Buffer_IOVec make_byte_buffer_iovec_with_chunks( + Span chunks); TEST(Test_Byte_Buffer, empty_byte_buffer_is_empty) { Byte_Buffer bb; @@ -291,7 +293,7 @@ TEST(Test_Byte_Buffer, } TEST(Test_Byte_Buffer, append_byte_buffer_to_empty_byte_buffer_iovec) { - Byte_Buffer_IOVec iov(std::vector{}); + Byte_Buffer_IOVec iov; Byte_Buffer bb; bb.append_copy(u8"hello"_sv); @@ -301,11 +303,11 @@ TEST(Test_Byte_Buffer, append_byte_buffer_to_empty_byte_buffer_iovec) { } TEST(Test_Byte_Buffer, append_byte_buffer_to_exhausted_byte_buffer_iovec) { - std::vector chunks = { - make_chunk(u8"hello"_sv), - make_chunk(u8"world"_sv), - }; - Byte_Buffer_IOVec iov(std::move(chunks)); + Byte_Buffer_IOVec iov = + make_byte_buffer_iovec_with_chunks(Span({ + u8"hello"_sv, + u8"world"_sv, + })); iov.remove_front(u8"helloworld"_sv.size()); Byte_Buffer bb; @@ -385,56 +387,56 @@ TEST(Test_Byte_Buffer, } TEST(Test_Byte_Buffer_Iovec, remove_front_entire_single_chunk) { - std::vector chunks = { - make_chunk(u8"hello"_sv), - make_chunk(u8" "_sv), - make_chunk(u8"world"_sv), - }; - Byte_Buffer_IOVec bb(std::move(chunks)); + Byte_Buffer_IOVec bb = + make_byte_buffer_iovec_with_chunks(Span({ + u8"hello"_sv, + u8" "_sv, + u8"world"_sv, + })); bb.remove_front(u8"hello"_sv.size()); EXPECT_EQ(get_data(bb), u8" world"); } TEST(Test_Byte_Buffer_Iovec, remove_front_entire_multiple_chunks) { - std::vector chunks = { - make_chunk(u8"hello"_sv), - make_chunk(u8"beautiful"_sv), - make_chunk(u8"world"_sv), - }; - Byte_Buffer_IOVec bb(std::move(chunks)); + Byte_Buffer_IOVec bb = + make_byte_buffer_iovec_with_chunks(Span({ + u8"hello"_sv, + u8"beautiful"_sv, + u8"world"_sv, + })); bb.remove_front(u8"hello"_sv.size() + u8"beautiful"_sv.size()); EXPECT_EQ(get_data(bb), u8"world"); } TEST(Test_Byte_Buffer_Iovec, remove_front_all_chunks) { - std::vector chunks = { - make_chunk(u8"hello"_sv), - make_chunk(u8" "_sv), - make_chunk(u8"world"_sv), - }; - Byte_Buffer_IOVec bb(std::move(chunks)); + Byte_Buffer_IOVec bb = + make_byte_buffer_iovec_with_chunks(Span({ + u8"hello"_sv, + u8" "_sv, + u8"world"_sv, + })); bb.remove_front(u8"hello"_sv.size() + u8" "_sv.size() + u8"world"_sv.size()); EXPECT_EQ(get_data(bb), u8""); } TEST(Test_Byte_Buffer_Iovec, remove_part_of_first_chunk) { - std::vector chunks = { - make_chunk(u8"hello"_sv), - make_chunk(u8" "_sv), - make_chunk(u8"world"_sv), - }; - Byte_Buffer_IOVec bb(std::move(chunks)); + Byte_Buffer_IOVec bb = + make_byte_buffer_iovec_with_chunks(Span({ + u8"hello"_sv, + u8" "_sv, + u8"world"_sv, + })); bb.remove_front(u8"hel"_sv.size()); EXPECT_EQ(get_data(bb), u8"lo world"); } TEST(Test_Byte_Buffer_Iovec, remove_parts_of_first_chunk) { - std::vector chunks = { - make_chunk(u8"hello"_sv), - make_chunk(u8" "_sv), - make_chunk(u8"world"_sv), - }; - Byte_Buffer_IOVec bb(std::move(chunks)); + Byte_Buffer_IOVec bb = + make_byte_buffer_iovec_with_chunks(Span({ + u8"hello"_sv, + u8" "_sv, + u8"world"_sv, + })); bb.remove_front(1); bb.remove_front(1); bb.remove_front(1); @@ -442,23 +444,23 @@ TEST(Test_Byte_Buffer_Iovec, remove_parts_of_first_chunk) { } TEST(Test_Byte_Buffer_Iovec, remove_first_chunk_and_part_of_second_chunk) { - std::vector chunks = { - make_chunk(u8"hello"_sv), - make_chunk(u8"beautiful"_sv), - make_chunk(u8"world"_sv), - }; - Byte_Buffer_IOVec bb(std::move(chunks)); + Byte_Buffer_IOVec bb = + make_byte_buffer_iovec_with_chunks(Span({ + u8"hello"_sv, + u8"beautiful"_sv, + u8"world"_sv, + })); bb.remove_front(u8"hello"_sv.size() + u8"beauti"_sv.size()); EXPECT_EQ(get_data(bb), u8"fulworld"); } TEST(Test_Byte_Buffer_Iovec, remove_front_all_chunks_byte_by_byte) { - std::vector chunks = { - make_chunk(u8"hello"_sv), - make_chunk(u8"beautiful"_sv), - make_chunk(u8"world"_sv), - }; - Byte_Buffer_IOVec bb(std::move(chunks)); + Byte_Buffer_IOVec bb = + make_byte_buffer_iovec_with_chunks(Span({ + u8"hello"_sv, + u8"beautiful"_sv, + u8"world"_sv, + })); for (std::size_t i = 0; i < u8"hello"_sv.size() + u8"beautiful"_sv.size() + u8"world"_sv.size(); ++i) { @@ -468,12 +470,12 @@ TEST(Test_Byte_Buffer_Iovec, remove_front_all_chunks_byte_by_byte) { } TEST(Test_Byte_Buffer_Iovec, moving_makes_original_empty) { - std::vector chunks = { - make_chunk(u8"hello"_sv), - make_chunk(u8"beautiful"_sv), - make_chunk(u8"world"_sv), - }; - Byte_Buffer_IOVec bb_1(std::move(chunks)); + Byte_Buffer_IOVec bb_1 = + make_byte_buffer_iovec_with_chunks(Span({ + u8"hello"_sv, + u8"beautiful"_sv, + u8"world"_sv, + })); Byte_Buffer_IOVec bb_2(std::move(bb_1)); EXPECT_EQ(bb_1.iovec_count(), 0); @@ -492,15 +494,15 @@ String8 get_data(const Byte_Buffer_IOVec& bb) { return data; } -Byte_Buffer_Chunk make_chunk(String8_View data) { - Char8* chunk_data = new Char8[data.size()]; - std::copy_n(data.data(), data.size(), chunk_data); -#if QLJS_HAVE_WRITEV - return Byte_Buffer_Chunk{.iov_base = chunk_data, .iov_len = data.size()}; -#else - return Byte_Buffer_Chunk{.data = reinterpret_cast(chunk_data), - .size = data.size()}; -#endif +Byte_Buffer_IOVec make_byte_buffer_iovec_with_chunks( + Span chunks) { + Byte_Buffer_IOVec iovec; + for (String8_View chunk : chunks) { + Byte_Buffer chunk_byte_buffer; + chunk_byte_buffer.append_copy(chunk); + iovec.append(std::move(chunk_byte_buffer)); + } + return iovec; } void assert_no_empty_iovec(const Byte_Buffer_IOVec& iovec) { From cffac99282748c34fde0b27a9803e93a7b555739 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 21:40:27 -0400 Subject: [PATCH 050/117] refactor(test): fix capitalization: Iovec -> IOVec --- test/test-byte-buffer.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/test-byte-buffer.cpp b/test/test-byte-buffer.cpp index aeeb5e7b64..5ac76d7bd7 100644 --- a/test/test-byte-buffer.cpp +++ b/test/test-byte-buffer.cpp @@ -386,7 +386,7 @@ TEST(Test_Byte_Buffer, assert_no_empty_iovec(iovec); } -TEST(Test_Byte_Buffer_Iovec, remove_front_entire_single_chunk) { +TEST(Test_Byte_Buffer_IOVec, remove_front_entire_single_chunk) { Byte_Buffer_IOVec bb = make_byte_buffer_iovec_with_chunks(Span({ u8"hello"_sv, @@ -397,7 +397,7 @@ TEST(Test_Byte_Buffer_Iovec, remove_front_entire_single_chunk) { EXPECT_EQ(get_data(bb), u8" world"); } -TEST(Test_Byte_Buffer_Iovec, remove_front_entire_multiple_chunks) { +TEST(Test_Byte_Buffer_IOVec, remove_front_entire_multiple_chunks) { Byte_Buffer_IOVec bb = make_byte_buffer_iovec_with_chunks(Span({ u8"hello"_sv, @@ -408,7 +408,7 @@ TEST(Test_Byte_Buffer_Iovec, remove_front_entire_multiple_chunks) { EXPECT_EQ(get_data(bb), u8"world"); } -TEST(Test_Byte_Buffer_Iovec, remove_front_all_chunks) { +TEST(Test_Byte_Buffer_IOVec, remove_front_all_chunks) { Byte_Buffer_IOVec bb = make_byte_buffer_iovec_with_chunks(Span({ u8"hello"_sv, @@ -419,7 +419,7 @@ TEST(Test_Byte_Buffer_Iovec, remove_front_all_chunks) { EXPECT_EQ(get_data(bb), u8""); } -TEST(Test_Byte_Buffer_Iovec, remove_part_of_first_chunk) { +TEST(Test_Byte_Buffer_IOVec, remove_part_of_first_chunk) { Byte_Buffer_IOVec bb = make_byte_buffer_iovec_with_chunks(Span({ u8"hello"_sv, @@ -430,7 +430,7 @@ TEST(Test_Byte_Buffer_Iovec, remove_part_of_first_chunk) { EXPECT_EQ(get_data(bb), u8"lo world"); } -TEST(Test_Byte_Buffer_Iovec, remove_parts_of_first_chunk) { +TEST(Test_Byte_Buffer_IOVec, remove_parts_of_first_chunk) { Byte_Buffer_IOVec bb = make_byte_buffer_iovec_with_chunks(Span({ u8"hello"_sv, @@ -443,7 +443,7 @@ TEST(Test_Byte_Buffer_Iovec, remove_parts_of_first_chunk) { EXPECT_EQ(get_data(bb), u8"lo world"); } -TEST(Test_Byte_Buffer_Iovec, remove_first_chunk_and_part_of_second_chunk) { +TEST(Test_Byte_Buffer_IOVec, remove_first_chunk_and_part_of_second_chunk) { Byte_Buffer_IOVec bb = make_byte_buffer_iovec_with_chunks(Span({ u8"hello"_sv, @@ -454,7 +454,7 @@ TEST(Test_Byte_Buffer_Iovec, remove_first_chunk_and_part_of_second_chunk) { EXPECT_EQ(get_data(bb), u8"fulworld"); } -TEST(Test_Byte_Buffer_Iovec, remove_front_all_chunks_byte_by_byte) { +TEST(Test_Byte_Buffer_IOVec, remove_front_all_chunks_byte_by_byte) { Byte_Buffer_IOVec bb = make_byte_buffer_iovec_with_chunks(Span({ u8"hello"_sv, @@ -469,7 +469,7 @@ TEST(Test_Byte_Buffer_Iovec, remove_front_all_chunks_byte_by_byte) { EXPECT_EQ(get_data(bb), u8""); } -TEST(Test_Byte_Buffer_Iovec, moving_makes_original_empty) { +TEST(Test_Byte_Buffer_IOVec, moving_makes_original_empty) { Byte_Buffer_IOVec bb_1 = make_byte_buffer_iovec_with_chunks(Span({ u8"hello"_sv, From f41a6651cc98765695d692298f53cd30b6a7309e Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 28 Oct 2023 22:10:15 -0400 Subject: [PATCH 051/117] refactor(test): clean up tests for Compiled_Diag_Code_List Declare excludes/includes in-line to reduce line count. Also, document ownership a bit. --- src/quick-lint-js/diag/diag-code-list.h | 2 + test/test-diag-code-list.cpp | 119 +++++++++++------------- test/test-options.cpp | 9 +- 3 files changed, 61 insertions(+), 69 deletions(-) diff --git a/src/quick-lint-js/diag/diag-code-list.h b/src/quick-lint-js/diag/diag-code-list.h index 25b362eca2..f4f637e6d4 100644 --- a/src/quick-lint-js/diag/diag-code-list.h +++ b/src/quick-lint-js/diag/diag-code-list.h @@ -22,10 +22,12 @@ struct Parsed_Diag_Code_List { bool override_defaults = false; }; +// Return std::string_view-s within raw_diag_code_list. Parsed_Diag_Code_List parse_diag_code_list(const char* raw_diag_code_list); class Compiled_Diag_Code_List { public: + // Retains references to the std::string_view-s. void add(const Parsed_Diag_Code_List&); std::vector parse_errors(std::string_view cli_option_name) const; diff --git a/test/test-diag-code-list.cpp b/test/test-diag-code-list.cpp index 4e0f4b8908..caf0621a2c 100644 --- a/test/test-diag-code-list.cpp +++ b/test/test-diag-code-list.cpp @@ -27,11 +27,10 @@ TEST(Test_Diag_Code_List, compiled_default_matches_all_errors) { } TEST(Test_Diag_Code_List, compiled_excluded_error_by_code) { - Parsed_Diag_Code_List parsed_errors; - parsed_errors.excluded_codes.emplace_back("E0003"); - Compiled_Diag_Code_List errors; - errors.add(parsed_errors); + errors.add(Parsed_Diag_Code_List{ + .excluded_codes = {"E0003"}, + }); EXPECT_FALSE(errors.is_present(Diag_Type::Diag_Assignment_To_Const_Variable)) << "E0003 should be disabled"; @@ -44,37 +43,36 @@ TEST(Test_Diag_Code_List, compiled_excluded_error_by_code) { } TEST(Test_Diag_Code_List, compiled_excluded_then_included_error_by_code) { - std::array parsed_diag_code_lists; - parsed_diag_code_lists[0].excluded_codes.emplace_back("E0003"); - parsed_diag_code_lists[1].included_codes.emplace_back("E0003"); - Compiled_Diag_Code_List errors; - errors.add(parsed_diag_code_lists[0]); - errors.add(parsed_diag_code_lists[1]); + errors.add(Parsed_Diag_Code_List{ + .excluded_codes = {"E0003"}, + }); + errors.add(Parsed_Diag_Code_List{ + .included_codes = {"E0003"}, + }); EXPECT_TRUE(errors.is_present(Diag_Type::Diag_Assignment_To_Const_Variable)) << "E0003 should be enabled"; } TEST(Test_Diag_Code_List, compiled_included_then_excluded_error_by_code) { - std::array parsed_diag_code_lists; - parsed_diag_code_lists[0].included_codes.emplace_back("E0003"); - parsed_diag_code_lists[1].excluded_codes.emplace_back("E0003"); - Compiled_Diag_Code_List errors; - errors.add(parsed_diag_code_lists[0]); - errors.add(parsed_diag_code_lists[1]); + errors.add(Parsed_Diag_Code_List{ + .included_codes = {"E0003"}, + }); + errors.add(Parsed_Diag_Code_List{ + .excluded_codes = {"E0003"}, + }); EXPECT_FALSE(errors.is_present(Diag_Type::Diag_Assignment_To_Const_Variable)) << "E0003 should be disabled"; } TEST(Test_Diag_Code_List, compiled_exclude_all_matches_no_errors) { - Parsed_Diag_Code_List parsed_errors; - parsed_errors.excluded_categories.emplace_back("all"); - Compiled_Diag_Code_List errors; - errors.add(parsed_errors); + errors.add(Parsed_Diag_Code_List{ + .excluded_categories = {"all"}, + }); #define QLJS_DIAG_TYPE_NAME(error_name) \ EXPECT_FALSE(errors.is_present(Diag_Type::error_name)) << #error_name; @@ -87,12 +85,11 @@ TEST(Test_Diag_Code_List, compiled_exclude_all_matches_no_errors) { TEST(Test_Diag_Code_List, compiled_override_and_include_code_matches_only_explicit) { - Parsed_Diag_Code_List parsed_errors; - parsed_errors.included_codes.emplace_back("E0003"); - parsed_errors.override_defaults = true; - Compiled_Diag_Code_List errors; - errors.add(parsed_errors); + errors.add(Parsed_Diag_Code_List{ + .included_codes = {"E0003"}, + .override_defaults = true, + }); EXPECT_TRUE(errors.is_present(Diag_Type::Diag_Assignment_To_Const_Variable)) << "E0003 should be enabled"; @@ -103,15 +100,14 @@ TEST(Test_Diag_Code_List, TEST(Test_Diag_Code_List, compiled_include_code_then_override_matches_only_later_included_codes) { - std::array parsed_diag_code_lists; - parsed_diag_code_lists[0].included_codes.emplace_back("E0003"); - - parsed_diag_code_lists[1].override_defaults = true; - parsed_diag_code_lists[1].included_codes.emplace_back("E0005"); - Compiled_Diag_Code_List errors; - errors.add(parsed_diag_code_lists[0]); - errors.add(parsed_diag_code_lists[1]); + errors.add(Parsed_Diag_Code_List{ + .included_codes = {"E0003"}, + }); + errors.add(Parsed_Diag_Code_List{ + .included_codes = {"E0005"}, + .override_defaults = true, + }); EXPECT_FALSE(errors.is_present(Diag_Type::Diag_Assignment_To_Const_Variable)) << "E0003 should be disabled"; @@ -122,12 +118,11 @@ TEST(Test_Diag_Code_List, TEST(Test_Diag_Code_List, compiled_exclude_all_and_include_code_matches_only_explicit) { - Parsed_Diag_Code_List parsed_errors; - parsed_errors.excluded_categories.emplace_back("all"); - parsed_errors.included_codes.emplace_back("E0003"); - Compiled_Diag_Code_List errors; - errors.add(parsed_errors); + errors.add(Parsed_Diag_Code_List{ + .included_codes = {"E0003"}, + .excluded_categories = {"all"}, + }); EXPECT_TRUE(errors.is_present(Diag_Type::Diag_Assignment_To_Const_Variable)) << "E0003 should be enabled"; @@ -138,16 +133,14 @@ TEST(Test_Diag_Code_List, TEST(Test_Diag_Code_List, compiled_exclude_default_code_and_include_all_matches_excluded_code) { - std::array parsed_diag_code_lists; - // These codes are enabled by default. - parsed_diag_code_lists[0].excluded_codes.emplace_back("E0003"); - parsed_diag_code_lists[0].excluded_codes.emplace_back("E0005"); - - parsed_diag_code_lists[1].included_categories.emplace_back("all"); - Compiled_Diag_Code_List errors; - errors.add(parsed_diag_code_lists[0]); - errors.add(parsed_diag_code_lists[1]); + errors.add(Parsed_Diag_Code_List{ + // These codes are enabled by default. + .excluded_codes = {"E0003", "E0005"}, + }); + errors.add(Parsed_Diag_Code_List{ + .included_categories = {"all"}, + }); EXPECT_TRUE(errors.is_present(Diag_Type::Diag_Assignment_To_Const_Variable)) << "E0003 (all) should be enabled"; @@ -157,12 +150,11 @@ TEST(Test_Diag_Code_List, } TEST(Test_Diag_Code_List, compiling_invalid_category_is_an_error) { - Parsed_Diag_Code_List parsed_errors; - parsed_errors.included_categories.emplace_back("banana"); - parsed_errors.excluded_categories.emplace_back("strawberry"); - Compiled_Diag_Code_List errors; - errors.add(parsed_errors); + errors.add(Parsed_Diag_Code_List{ + .included_categories = {"banana"}, + .excluded_categories = {"strawberry"}, + }); EXPECT_THAT(errors.parse_warnings(), UnorderedElementsAreArray({ "unknown error category: banana", @@ -171,12 +163,11 @@ TEST(Test_Diag_Code_List, compiling_invalid_category_is_an_error) { } TEST(Test_Diag_Code_List, compiling_invalid_code_is_an_error) { - Parsed_Diag_Code_List parsed_errors; - parsed_errors.included_codes.emplace_back("E9999"); - parsed_errors.excluded_codes.emplace_back("E0000"); - Compiled_Diag_Code_List errors; - errors.add(parsed_errors); + errors.add(Parsed_Diag_Code_List{ + .included_codes = {"E9999"}, + .excluded_codes = {"E0000"}, + }); EXPECT_THAT(errors.parse_warnings(), UnorderedElementsAreArray({ "unknown error code: E9999", @@ -185,14 +176,14 @@ TEST(Test_Diag_Code_List, compiling_invalid_code_is_an_error) { } TEST(Test_Diag_Code_List, compiling_empty_parsed_diag_code_list_is_an_error) { - std::array parsed_diag_code_lists; - parsed_diag_code_lists[0].included_codes.emplace_back("E0003"); - parsed_diag_code_lists[2].excluded_codes.emplace_back("E0003"); - Compiled_Diag_Code_List errors; - errors.add(parsed_diag_code_lists[0]); - errors.add(parsed_diag_code_lists[1]); - errors.add(parsed_diag_code_lists[2]); + errors.add(Parsed_Diag_Code_List{ + .included_codes = {"E0003"}, + }); + errors.add(Parsed_Diag_Code_List{}); + errors.add(Parsed_Diag_Code_List{ + .excluded_codes = {"E0003"}, + }); EXPECT_THAT(errors.parse_warnings(), IsEmpty()); EXPECT_THAT( diff --git a/test/test-options.cpp b/test/test-options.cpp index 7935537c74..189e8f9e57 100644 --- a/test/test-options.cpp +++ b/test/test-options.cpp @@ -896,11 +896,10 @@ TEST(Test_Options, dump_errors) { { Options o; - - Parsed_Diag_Code_List parsed_errors; - parsed_errors.included_categories.emplace_back("banana"); - parsed_errors.excluded_codes.emplace_back("E9999"); - o.exit_fail_on.add(parsed_errors); + o.exit_fail_on.add(Parsed_Diag_Code_List{ + .excluded_codes = {"E9999"}, + .included_categories = {"banana"}, + }); Dumped_Errors errors = dump_errors(o); EXPECT_FALSE(errors.have_errors); From 04c8e20c63a3b33e78d940f24d113d25670e9a69 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sun, 29 Oct 2023 01:19:02 -0400 Subject: [PATCH 052/117] refactor(cli): prefer Bump_Vector over std::vector Reduce our use of std::vector to reduce binary bloat: https://github.com/quick-lint/quick-lint-js/issues/689 --- src/quick-lint-js/cli/options.cpp | 5 +- src/quick-lint-js/diag/diag-code-list.cpp | 45 ++++-- src/quick-lint-js/diag/diag-code-list.h | 19 ++- test/test-diag-code-list.cpp | 161 +++++++++++++--------- test/test-options.cpp | 7 +- 5 files changed, 147 insertions(+), 90 deletions(-) diff --git a/src/quick-lint-js/cli/options.cpp b/src/quick-lint-js/cli/options.cpp index 684a619377..7173d034a7 100644 --- a/src/quick-lint-js/cli/options.cpp +++ b/src/quick-lint-js/cli/options.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,8 @@ namespace quick_lint_js { Options parse_options(int argc, char** argv) { Options o; + Monotonic_Allocator temporary_allocator("parse_options"); + struct { std::optional number; const char* arg_var; @@ -158,7 +161,7 @@ Options parse_options(int argc, char** argv) { } QLJS_OPTION(const char* arg_value, "--exit-fail-on"sv) { - o.exit_fail_on.add(parse_diag_code_list(arg_value)); + o.exit_fail_on.add(parse_diag_code_list(arg_value, &temporary_allocator)); } QLJS_FLAG('h', "--help"sv, "--h"sv) { o.help = true; } diff --git a/src/quick-lint-js/diag/diag-code-list.cpp b/src/quick-lint-js/diag/diag-code-list.cpp index 231d9ee1dd..e4a1889026 100644 --- a/src/quick-lint-js/diag/diag-code-list.cpp +++ b/src/quick-lint-js/diag/diag-code-list.cpp @@ -18,8 +18,8 @@ bool Parsed_Diag_Code_List::error_missing_predicate() const { this->included_categories.empty() && this->excluded_categories.empty(); } -Parsed_Diag_Code_List parse_diag_code_list( - const char* const raw_diag_code_list) { +Parsed_Diag_Code_List parse_diag_code_list(const char* const raw_diag_code_list, + Monotonic_Allocator* allocator) { static auto is_initial_category_character = [](char c) -> bool { return 'a' <= c && c <= 'z'; }; @@ -30,7 +30,18 @@ Parsed_Diag_Code_List parse_diag_code_list( return '0' <= c && c <= '9'; }; - Parsed_Diag_Code_List diag_codes; + Bump_Vector included_codes( + "included_codes", allocator); + Bump_Vector excluded_codes( + "excluded_codes", allocator); + Bump_Vector included_categories( + "included_categories", allocator); + Bump_Vector excluded_categories( + "excluded_categories", allocator); + Bump_Vector unexpected("unexpected", + allocator); + bool override_defaults = false; + std::size_t i = 0; bool need_comma = false; @@ -46,16 +57,15 @@ Parsed_Diag_Code_List parse_diag_code_list( }; if (raw_diag_code_list[i] == 'E') { - (is_include ? diag_codes.included_codes : diag_codes.excluded_codes) + (is_include ? included_codes : excluded_codes) .emplace_back(parse_word(is_continue_code_character)); return true; } else if (is_initial_category_character(raw_diag_code_list[i])) { - (is_include ? diag_codes.included_categories - : diag_codes.excluded_categories) + (is_include ? included_categories : excluded_categories) .emplace_back(parse_word(is_continue_category_character)); return true; } else { - diag_codes.unexpected.emplace_back(&raw_diag_code_list[i], 1); + unexpected.emplace_back(&raw_diag_code_list[i], std::size_t{1}); return false; } }; @@ -66,7 +76,7 @@ Parsed_Diag_Code_List parse_diag_code_list( break; } if (need_comma && raw_diag_code_list[i] != ',') { - diag_codes.unexpected.emplace_back(&raw_diag_code_list[i], 1); + unexpected.emplace_back(&raw_diag_code_list[i], std::size_t{1}); break; } i = i + std::strspn(&raw_diag_code_list[i], " \t,"); @@ -84,11 +94,18 @@ Parsed_Diag_Code_List parse_diag_code_list( if (!try_parse_category_or_code(/*is_include=*/true)) { break; } - diag_codes.override_defaults = true; + override_defaults = true; } } - return diag_codes; + return Parsed_Diag_Code_List{ + .included_codes = included_codes.release_to_span(), + .excluded_codes = excluded_codes.release_to_span(), + .included_categories = included_categories.release_to_span(), + .excluded_categories = excluded_categories.release_to_span(), + .unexpected = unexpected.release_to_span(), + .override_defaults = override_defaults, + }; } void Compiled_Diag_Code_List::add(const Parsed_Diag_Code_List& diag_code_list) { @@ -108,8 +125,12 @@ void Compiled_Diag_Code_List::add(const Parsed_Diag_Code_List& diag_code_list) { for (std::string_view code : diag_code_list.excluded_codes) { add_code(code, c.excluded_codes); } - c.included_categories = diag_code_list.included_categories; - c.excluded_categories = diag_code_list.excluded_categories; + c.included_categories.insert(c.included_categories.end(), + diag_code_list.included_categories.begin(), + diag_code_list.included_categories.end()); + c.excluded_categories.insert(c.excluded_categories.end(), + diag_code_list.excluded_categories.begin(), + diag_code_list.excluded_categories.end()); c.override_defaults = diag_code_list.override_defaults; if (diag_code_list.error_missing_predicate()) { diff --git a/src/quick-lint-js/diag/diag-code-list.h b/src/quick-lint-js/diag/diag-code-list.h index f4f637e6d4..398eaaf0ac 100644 --- a/src/quick-lint-js/diag/diag-code-list.h +++ b/src/quick-lint-js/diag/diag-code-list.h @@ -5,7 +5,9 @@ #include #include +#include #include +#include #include #include #include @@ -14,16 +16,21 @@ namespace quick_lint_js { struct Parsed_Diag_Code_List { bool error_missing_predicate() const; - std::vector included_codes; - std::vector excluded_codes; - std::vector included_categories; - std::vector excluded_categories; - std::vector unexpected; + Span included_codes = Span(); + Span excluded_codes = Span(); + Span included_categories = + Span(); + Span excluded_categories = + Span(); + Span unexpected = Span(); bool override_defaults = false; }; +// Returns Span-s allocated by allocator. +// // Return std::string_view-s within raw_diag_code_list. -Parsed_Diag_Code_List parse_diag_code_list(const char* raw_diag_code_list); +Parsed_Diag_Code_List parse_diag_code_list(const char* raw_diag_code_list, + Monotonic_Allocator* allocator); class Compiled_Diag_Code_List { public: diff --git a/test/test-diag-code-list.cpp b/test/test-diag-code-list.cpp index caf0621a2c..c9c56d7198 100644 --- a/test/test-diag-code-list.cpp +++ b/test/test-diag-code-list.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -15,7 +16,12 @@ using ::testing::UnorderedElementsAreArray; namespace quick_lint_js { namespace { -TEST(Test_Diag_Code_List, compiled_default_matches_all_errors) { +class Test_Diag_Code_List : public ::testing::Test { + public: + Monotonic_Allocator allocator{"Test_Diag_Code_List"}; +}; + +TEST_F(Test_Diag_Code_List, compiled_default_matches_all_errors) { Compiled_Diag_Code_List errors; #define QLJS_DIAG_TYPE_NAME(error_name) \ EXPECT_TRUE(errors.is_present(Diag_Type::error_name)) << #error_name; @@ -26,10 +32,10 @@ TEST(Test_Diag_Code_List, compiled_default_matches_all_errors) { EXPECT_THAT(errors.parse_warnings(), IsEmpty()); } -TEST(Test_Diag_Code_List, compiled_excluded_error_by_code) { +TEST_F(Test_Diag_Code_List, compiled_excluded_error_by_code) { Compiled_Diag_Code_List errors; errors.add(Parsed_Diag_Code_List{ - .excluded_codes = {"E0003"}, + .excluded_codes = Span({"E0003"}), }); EXPECT_FALSE(errors.is_present(Diag_Type::Diag_Assignment_To_Const_Variable)) @@ -42,36 +48,36 @@ TEST(Test_Diag_Code_List, compiled_excluded_error_by_code) { EXPECT_THAT(errors.parse_warnings(), IsEmpty()); } -TEST(Test_Diag_Code_List, compiled_excluded_then_included_error_by_code) { +TEST_F(Test_Diag_Code_List, compiled_excluded_then_included_error_by_code) { Compiled_Diag_Code_List errors; errors.add(Parsed_Diag_Code_List{ - .excluded_codes = {"E0003"}, + .excluded_codes = Span({"E0003"}), }); errors.add(Parsed_Diag_Code_List{ - .included_codes = {"E0003"}, + .included_codes = Span({"E0003"}), }); EXPECT_TRUE(errors.is_present(Diag_Type::Diag_Assignment_To_Const_Variable)) << "E0003 should be enabled"; } -TEST(Test_Diag_Code_List, compiled_included_then_excluded_error_by_code) { +TEST_F(Test_Diag_Code_List, compiled_included_then_excluded_error_by_code) { Compiled_Diag_Code_List errors; errors.add(Parsed_Diag_Code_List{ - .included_codes = {"E0003"}, + .included_codes = Span({"E0003"}), }); errors.add(Parsed_Diag_Code_List{ - .excluded_codes = {"E0003"}, + .excluded_codes = Span({"E0003"}), }); EXPECT_FALSE(errors.is_present(Diag_Type::Diag_Assignment_To_Const_Variable)) << "E0003 should be disabled"; } -TEST(Test_Diag_Code_List, compiled_exclude_all_matches_no_errors) { +TEST_F(Test_Diag_Code_List, compiled_exclude_all_matches_no_errors) { Compiled_Diag_Code_List errors; errors.add(Parsed_Diag_Code_List{ - .excluded_categories = {"all"}, + .excluded_categories = Span({"all"}), }); #define QLJS_DIAG_TYPE_NAME(error_name) \ @@ -83,11 +89,11 @@ TEST(Test_Diag_Code_List, compiled_exclude_all_matches_no_errors) { EXPECT_THAT(errors.parse_warnings(), IsEmpty()); } -TEST(Test_Diag_Code_List, - compiled_override_and_include_code_matches_only_explicit) { +TEST_F(Test_Diag_Code_List, + compiled_override_and_include_code_matches_only_explicit) { Compiled_Diag_Code_List errors; errors.add(Parsed_Diag_Code_List{ - .included_codes = {"E0003"}, + .included_codes = Span({"E0003"}), .override_defaults = true, }); @@ -98,14 +104,14 @@ TEST(Test_Diag_Code_List, << "E0005 (default) should be disabled"; } -TEST(Test_Diag_Code_List, - compiled_include_code_then_override_matches_only_later_included_codes) { +TEST_F(Test_Diag_Code_List, + compiled_include_code_then_override_matches_only_later_included_codes) { Compiled_Diag_Code_List errors; errors.add(Parsed_Diag_Code_List{ - .included_codes = {"E0003"}, + .included_codes = Span({"E0003"}), }); errors.add(Parsed_Diag_Code_List{ - .included_codes = {"E0005"}, + .included_codes = Span({"E0005"}), .override_defaults = true, }); @@ -116,12 +122,12 @@ TEST(Test_Diag_Code_List, << "E0005 should be enabled"; } -TEST(Test_Diag_Code_List, - compiled_exclude_all_and_include_code_matches_only_explicit) { +TEST_F(Test_Diag_Code_List, + compiled_exclude_all_and_include_code_matches_only_explicit) { Compiled_Diag_Code_List errors; errors.add(Parsed_Diag_Code_List{ - .included_codes = {"E0003"}, - .excluded_categories = {"all"}, + .included_codes = Span({"E0003"}), + .excluded_categories = Span({"all"}), }); EXPECT_TRUE(errors.is_present(Diag_Type::Diag_Assignment_To_Const_Variable)) @@ -131,15 +137,15 @@ TEST(Test_Diag_Code_List, << "E0005 (all) should be disabled"; } -TEST(Test_Diag_Code_List, - compiled_exclude_default_code_and_include_all_matches_excluded_code) { +TEST_F(Test_Diag_Code_List, + compiled_exclude_default_code_and_include_all_matches_excluded_code) { Compiled_Diag_Code_List errors; errors.add(Parsed_Diag_Code_List{ // These codes are enabled by default. - .excluded_codes = {"E0003", "E0005"}, + .excluded_codes = Span({"E0003", "E0005"}), }); errors.add(Parsed_Diag_Code_List{ - .included_categories = {"all"}, + .included_categories = Span({"all"}), }); EXPECT_TRUE(errors.is_present(Diag_Type::Diag_Assignment_To_Const_Variable)) @@ -149,11 +155,11 @@ TEST(Test_Diag_Code_List, << "E0005 (all) should be enabled"; } -TEST(Test_Diag_Code_List, compiling_invalid_category_is_an_error) { +TEST_F(Test_Diag_Code_List, compiling_invalid_category_is_an_error) { Compiled_Diag_Code_List errors; errors.add(Parsed_Diag_Code_List{ - .included_categories = {"banana"}, - .excluded_categories = {"strawberry"}, + .included_categories = Span({"banana"}), + .excluded_categories = Span({"strawberry"}), }); EXPECT_THAT(errors.parse_warnings(), UnorderedElementsAreArray({ @@ -162,11 +168,11 @@ TEST(Test_Diag_Code_List, compiling_invalid_category_is_an_error) { })); } -TEST(Test_Diag_Code_List, compiling_invalid_code_is_an_error) { +TEST_F(Test_Diag_Code_List, compiling_invalid_code_is_an_error) { Compiled_Diag_Code_List errors; errors.add(Parsed_Diag_Code_List{ - .included_codes = {"E9999"}, - .excluded_codes = {"E0000"}, + .included_codes = Span({"E9999"}), + .excluded_codes = Span({"E0000"}), }); EXPECT_THAT(errors.parse_warnings(), UnorderedElementsAreArray({ @@ -175,14 +181,14 @@ TEST(Test_Diag_Code_List, compiling_invalid_code_is_an_error) { })); } -TEST(Test_Diag_Code_List, compiling_empty_parsed_diag_code_list_is_an_error) { +TEST_F(Test_Diag_Code_List, compiling_empty_parsed_diag_code_list_is_an_error) { Compiled_Diag_Code_List errors; errors.add(Parsed_Diag_Code_List{ - .included_codes = {"E0003"}, + .included_codes = Span({"E0003"}), }); errors.add(Parsed_Diag_Code_List{}); errors.add(Parsed_Diag_Code_List{ - .excluded_codes = {"E0003"}, + .excluded_codes = Span({"E0003"}), }); EXPECT_THAT(errors.parse_warnings(), IsEmpty()); @@ -192,23 +198,25 @@ TEST(Test_Diag_Code_List, compiling_empty_parsed_diag_code_list_is_an_error) { {"--testoption must be given at least one category or code"})); } -TEST(Test_Diag_Code_List, empty_list_is_disallowed) { +TEST_F(Test_Diag_Code_List, empty_list_is_disallowed) { { - Parsed_Diag_Code_List errors = parse_diag_code_list(""); + Parsed_Diag_Code_List errors = parse_diag_code_list("", &this->allocator); EXPECT_TRUE(errors.error_missing_predicate()); EXPECT_THAT(errors.unexpected, IsEmpty()); } { - Parsed_Diag_Code_List errors = parse_diag_code_list(" \t "); + Parsed_Diag_Code_List errors = + parse_diag_code_list(" \t ", &this->allocator); EXPECT_TRUE(errors.error_missing_predicate()); EXPECT_THAT(errors.unexpected, IsEmpty()); } } -TEST(Test_Diag_Code_List, add_error_code_to_default) { +TEST_F(Test_Diag_Code_List, add_error_code_to_default) { { - Parsed_Diag_Code_List errors = parse_diag_code_list("+E0420"); + Parsed_Diag_Code_List errors = + parse_diag_code_list("+E0420", &this->allocator); EXPECT_THAT(errors.included_codes, ElementsAreArray({"E0420"})); EXPECT_FALSE(errors.override_defaults); EXPECT_FALSE(errors.error_missing_predicate()); @@ -216,7 +224,8 @@ TEST(Test_Diag_Code_List, add_error_code_to_default) { } { - Parsed_Diag_Code_List errors = parse_diag_code_list("+E0420,+E0069"); + Parsed_Diag_Code_List errors = + parse_diag_code_list("+E0420,+E0069", &this->allocator); EXPECT_THAT(errors.included_codes, UnorderedElementsAreArray({"E0420", "E0069"})); EXPECT_FALSE(errors.override_defaults); @@ -225,9 +234,10 @@ TEST(Test_Diag_Code_List, add_error_code_to_default) { } } -TEST(Test_Diag_Code_List, remove_error_code_from_default) { +TEST_F(Test_Diag_Code_List, remove_error_code_from_default) { { - Parsed_Diag_Code_List errors = parse_diag_code_list("-E0420"); + Parsed_Diag_Code_List errors = + parse_diag_code_list("-E0420", &this->allocator); EXPECT_THAT(errors.excluded_codes, ElementsAreArray({"E0420"})); EXPECT_FALSE(errors.override_defaults); EXPECT_FALSE(errors.error_missing_predicate()); @@ -235,7 +245,8 @@ TEST(Test_Diag_Code_List, remove_error_code_from_default) { } { - Parsed_Diag_Code_List errors = parse_diag_code_list("-E0420,-E0069"); + Parsed_Diag_Code_List errors = + parse_diag_code_list("-E0420,-E0069", &this->allocator); EXPECT_THAT(errors.excluded_codes, UnorderedElementsAreArray({"E0420", "E0069"})); EXPECT_FALSE(errors.override_defaults); @@ -244,9 +255,10 @@ TEST(Test_Diag_Code_List, remove_error_code_from_default) { } } -TEST(Test_Diag_Code_List, add_error_category_to_default) { +TEST_F(Test_Diag_Code_List, add_error_category_to_default) { { - Parsed_Diag_Code_List errors = parse_diag_code_list("+warning"); + Parsed_Diag_Code_List errors = + parse_diag_code_list("+warning", &this->allocator); EXPECT_THAT(errors.included_categories, ElementsAreArray({"warning"})); EXPECT_FALSE(errors.override_defaults); EXPECT_FALSE(errors.error_missing_predicate()); @@ -254,9 +266,10 @@ TEST(Test_Diag_Code_List, add_error_category_to_default) { } } -TEST(Test_Diag_Code_List, remove_error_category_from_default) { +TEST_F(Test_Diag_Code_List, remove_error_category_from_default) { { - Parsed_Diag_Code_List errors = parse_diag_code_list("-warning"); + Parsed_Diag_Code_List errors = + parse_diag_code_list("-warning", &this->allocator); EXPECT_THAT(errors.excluded_categories, ElementsAreArray({"warning"})); EXPECT_FALSE(errors.override_defaults); EXPECT_FALSE(errors.error_missing_predicate()); @@ -264,9 +277,10 @@ TEST(Test_Diag_Code_List, remove_error_category_from_default) { } } -TEST(Test_Diag_Code_List, set_default_to_category) { +TEST_F(Test_Diag_Code_List, set_default_to_category) { { - Parsed_Diag_Code_List errors = parse_diag_code_list("warning"); + Parsed_Diag_Code_List errors = + parse_diag_code_list("warning", &this->allocator); EXPECT_THAT(errors.included_categories, ElementsAreArray({"warning"})); EXPECT_TRUE(errors.override_defaults); EXPECT_FALSE(errors.error_missing_predicate()); @@ -274,9 +288,10 @@ TEST(Test_Diag_Code_List, set_default_to_category) { } } -TEST(Test_Diag_Code_List, set_default_to_error_code) { +TEST_F(Test_Diag_Code_List, set_default_to_error_code) { { - Parsed_Diag_Code_List errors = parse_diag_code_list("E0420"); + Parsed_Diag_Code_List errors = + parse_diag_code_list("E0420", &this->allocator); EXPECT_THAT(errors.included_codes, ElementsAreArray({"E0420"})); EXPECT_TRUE(errors.override_defaults); EXPECT_FALSE(errors.error_missing_predicate()); @@ -284,10 +299,10 @@ TEST(Test_Diag_Code_List, set_default_to_error_code) { } } -TEST(Test_Diag_Code_List, mixed) { +TEST_F(Test_Diag_Code_List, mixed) { { - Parsed_Diag_Code_List errors = - parse_diag_code_list("+E0420,warning,-pedantic,syntax-error"); + Parsed_Diag_Code_List errors = parse_diag_code_list( + "+E0420,warning,-pedantic,syntax-error", &this->allocator); EXPECT_THAT(errors.included_codes, ElementsAreArray({"E0420"})); EXPECT_THAT(errors.excluded_codes, IsEmpty()); EXPECT_THAT(errors.included_categories, @@ -299,63 +314,73 @@ TEST(Test_Diag_Code_List, mixed) { } } -TEST(Test_Diag_Code_List, whitespace_around_predicates_is_ignored) { +TEST_F(Test_Diag_Code_List, whitespace_around_predicates_is_ignored) { { - Parsed_Diag_Code_List errors = parse_diag_code_list("\t +E0420 \t"); + Parsed_Diag_Code_List errors = + parse_diag_code_list("\t +E0420 \t", &this->allocator); EXPECT_THAT(errors.included_codes, ElementsAreArray({"E0420"})); EXPECT_THAT(errors.unexpected, IsEmpty()); } { - Parsed_Diag_Code_List errors = parse_diag_code_list(" +E0420 , +E0069"); + Parsed_Diag_Code_List errors = + parse_diag_code_list(" +E0420 , +E0069", &this->allocator); EXPECT_THAT(errors.included_codes, UnorderedElementsAreArray({"E0420", "E0069"})); EXPECT_THAT(errors.unexpected, IsEmpty()); } } -TEST(Test_Diag_Code_List, stray_commas_are_ignored) { +TEST_F(Test_Diag_Code_List, stray_commas_are_ignored) { { - Parsed_Diag_Code_List errors = parse_diag_code_list(",one,,two , three"); + Parsed_Diag_Code_List errors = + parse_diag_code_list(",one,,two , three", &this->allocator); EXPECT_THAT(errors.included_categories, UnorderedElementsAreArray({"one", "two", "three"})); EXPECT_THAT(errors.unexpected, IsEmpty()); } } -TEST(Test_Diag_Code_List, unexpected_characters) { +TEST_F(Test_Diag_Code_List, unexpected_characters) { { - Parsed_Diag_Code_List errors = parse_diag_code_list("~E0420"); + Parsed_Diag_Code_List errors = + parse_diag_code_list("~E0420", &this->allocator); EXPECT_THAT(errors.unexpected, ElementsAreArray({"~"})); } { - Parsed_Diag_Code_List errors = parse_diag_code_list("E???"); + Parsed_Diag_Code_List errors = + parse_diag_code_list("E???", &this->allocator); EXPECT_THAT(errors.unexpected, ElementsAreArray({"?"})); } { - Parsed_Diag_Code_List errors = parse_diag_code_list("err0r"); + Parsed_Diag_Code_List errors = + parse_diag_code_list("err0r", &this->allocator); EXPECT_THAT(errors.unexpected, ElementsAreArray({"0"})); } { - Parsed_Diag_Code_List errors = parse_diag_code_list("err?r"); + Parsed_Diag_Code_List errors = + parse_diag_code_list("err?r", &this->allocator); EXPECT_THAT(errors.unexpected, ElementsAreArray({"?"})); } { - Parsed_Diag_Code_List errors = parse_diag_code_list("+err+r"); + Parsed_Diag_Code_List errors = + parse_diag_code_list("+err+r", &this->allocator); EXPECT_THAT(errors.unexpected, ElementsAreArray({"+"})); } { - Parsed_Diag_Code_List errors = parse_diag_code_list("+%^#"); + Parsed_Diag_Code_List errors = + parse_diag_code_list("+%^#", &this->allocator); EXPECT_THAT(errors.unexpected, ElementsAreArray({"%"})); } { - Parsed_Diag_Code_List errors = parse_diag_code_list("warning error"); + Parsed_Diag_Code_List errors = + parse_diag_code_list("warning error", &this->allocator); EXPECT_THAT(errors.unexpected, ElementsAreArray({"e"})); } } diff --git a/test/test-options.cpp b/test/test-options.cpp index 189e8f9e57..4ebe4280ae 100644 --- a/test/test-options.cpp +++ b/test/test-options.cpp @@ -897,8 +897,8 @@ TEST(Test_Options, dump_errors) { { Options o; o.exit_fail_on.add(Parsed_Diag_Code_List{ - .excluded_codes = {"E9999"}, - .included_categories = {"banana"}, + .excluded_codes = Span({"E9999"}), + .included_categories = Span({"banana"}), }); Dumped_Errors errors = dump_errors(o); @@ -980,7 +980,8 @@ TEST(Test_Options, dump_errors) { { Options o; o.lsp_server = true; - o.exit_fail_on.add(parse_diag_code_list("E0001")); + Monotonic_Allocator allocator(__func__); + o.exit_fail_on.add(parse_diag_code_list("E0001", &allocator)); Dumped_Errors errors = dump_errors(o); EXPECT_FALSE(errors.have_errors); From b7f5e46930aae48ca3aa564d631ee0b88461e12b Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sun, 29 Oct 2023 01:17:15 -0400 Subject: [PATCH 053/117] refactor(cli): prefer Bump_Vector over std::vector/std::string Reduce our use of std::vector to reduce binary bloat: https://github.com/quick-lint/quick-lint-js/issues/689 --- src/quick-lint-js/cli/options.cpp | 9 +++-- src/quick-lint-js/diag/diag-code-list.cpp | 40 +++++++++++++++-------- src/quick-lint-js/diag/diag-code-list.h | 5 +-- test/test-diag-code-list.cpp | 34 ++++++++++--------- 4 files changed, 53 insertions(+), 35 deletions(-) diff --git a/src/quick-lint-js/cli/options.cpp b/src/quick-lint-js/cli/options.cpp index 7173d034a7..950f06532c 100644 --- a/src/quick-lint-js/cli/options.cpp +++ b/src/quick-lint-js/cli/options.cpp @@ -205,6 +205,8 @@ bool Options::has_stdin() const { } bool Options::dump_errors(Output_Stream& out) const { + Monotonic_Allocator temporary_allocator("dump_errors"); + bool have_errors = false; if (this->lsp_server) { if (this->exit_fail_on.is_user_provided()) { @@ -269,14 +271,15 @@ bool Options::dump_errors(Output_Stream& out) const { out.append_copy(u8'\n'); have_errors = true; } - for (const std::string& error : - this->exit_fail_on.parse_errors("--exit-fail-on")) { + for (std::string_view error : this->exit_fail_on.parse_errors( + "--exit-fail-on", &temporary_allocator)) { out.append_copy(u8"error: "_sv); out.append_copy(to_string8_view(error)); out.append_copy(u8'\n'); have_errors = true; } - for (const std::string& warning : this->exit_fail_on.parse_warnings()) { + for (std::string_view warning : + this->exit_fail_on.parse_warnings(&temporary_allocator)) { out.append_copy(u8"warning: "_sv); out.append_copy(to_string8_view(warning)); out.append_copy(u8'\n'); diff --git a/src/quick-lint-js/diag/diag-code-list.cpp b/src/quick-lint-js/diag/diag-code-list.cpp index e4a1889026..6a6ba70160 100644 --- a/src/quick-lint-js/diag/diag-code-list.cpp +++ b/src/quick-lint-js/diag/diag-code-list.cpp @@ -138,22 +138,31 @@ void Compiled_Diag_Code_List::add(const Parsed_Diag_Code_List& diag_code_list) { } } -std::vector Compiled_Diag_Code_List::parse_errors( - std::string_view cli_option_name) const { - std::vector errors; +Span Compiled_Diag_Code_List::parse_errors( + std::string_view cli_option_name, Monotonic_Allocator* allocator) const { + Bump_Vector errors("errors", + allocator); if (this->has_missing_predicate_error_) { - errors.emplace_back(std::string(cli_option_name) + - " must be given at least one category or code"); + // TODO(#1102): Make this code pretty. + Bump_Vector error("error", allocator); + error += cli_option_name; + error += " must be given at least one category or code"sv; + errors.emplace_back(error.release_to_string_view()); } - return errors; + return errors.release_to_span(); } -std::vector Compiled_Diag_Code_List::parse_warnings() const { - std::vector warnings; - auto check_category = [&warnings](std::string_view category) { +Span Compiled_Diag_Code_List::parse_warnings( + Monotonic_Allocator* allocator) const { + Bump_Vector warnings("warnings", + allocator); + auto check_category = [&](std::string_view category) { if (category != "all") { - warnings.emplace_back("unknown error category: "); - warnings.back().append(category); + // TODO(#1102): Make this code pretty. + Bump_Vector warning("warning", allocator); + warning += "unknown error category: "sv; + warning += category; + warnings.emplace_back(warning.release_to_string_view()); } }; @@ -167,11 +176,14 @@ std::vector Compiled_Diag_Code_List::parse_warnings() const { } for (std::string_view code : this->unknown_codes_) { - warnings.emplace_back("unknown error code: "); - warnings.back().append(code); + // TODO(#1102): Make this code pretty. + Bump_Vector warning("warning", allocator); + warning += "unknown error code: "sv; + warning += code; + warnings.emplace_back(warning.release_to_string_view()); } - return warnings; + return warnings.release_to_span(); } bool Compiled_Diag_Code_List::is_present(Diag_Type type) const { diff --git a/src/quick-lint-js/diag/diag-code-list.h b/src/quick-lint-js/diag/diag-code-list.h index 398eaaf0ac..7b7fc07d43 100644 --- a/src/quick-lint-js/diag/diag-code-list.h +++ b/src/quick-lint-js/diag/diag-code-list.h @@ -37,8 +37,9 @@ class Compiled_Diag_Code_List { // Retains references to the std::string_view-s. void add(const Parsed_Diag_Code_List&); - std::vector parse_errors(std::string_view cli_option_name) const; - std::vector parse_warnings() const; + Span parse_errors(std::string_view cli_option_name, + Monotonic_Allocator* allocator) const; + Span parse_warnings(Monotonic_Allocator* allocator) const; bool is_present(Diag_Type) const; diff --git a/test/test-diag-code-list.cpp b/test/test-diag-code-list.cpp index c9c56d7198..22fbb2d34b 100644 --- a/test/test-diag-code-list.cpp +++ b/test/test-diag-code-list.cpp @@ -28,8 +28,8 @@ TEST_F(Test_Diag_Code_List, compiled_default_matches_all_errors) { QLJS_X_DIAG_TYPE_NAMES #undef QLJS_DIAG_TYPE_NAME - EXPECT_THAT(errors.parse_errors("--testoption"), IsEmpty()); - EXPECT_THAT(errors.parse_warnings(), IsEmpty()); + EXPECT_THAT(errors.parse_errors("--testoption", &this->allocator), IsEmpty()); + EXPECT_THAT(errors.parse_warnings(&this->allocator), IsEmpty()); } TEST_F(Test_Diag_Code_List, compiled_excluded_error_by_code) { @@ -44,8 +44,8 @@ TEST_F(Test_Diag_Code_List, compiled_excluded_error_by_code) { errors.is_present(Diag_Type::Diag_Big_Int_Literal_Contains_Decimal_Point)) << "E0005 should be enabled"; - EXPECT_THAT(errors.parse_errors("--testoption"), IsEmpty()); - EXPECT_THAT(errors.parse_warnings(), IsEmpty()); + EXPECT_THAT(errors.parse_errors("--testoption", &this->allocator), IsEmpty()); + EXPECT_THAT(errors.parse_warnings(&this->allocator), IsEmpty()); } TEST_F(Test_Diag_Code_List, compiled_excluded_then_included_error_by_code) { @@ -85,8 +85,8 @@ TEST_F(Test_Diag_Code_List, compiled_exclude_all_matches_no_errors) { QLJS_X_DIAG_TYPE_NAMES #undef QLJS_DIAG_TYPE_NAME - EXPECT_THAT(errors.parse_errors("--testoption"), IsEmpty()); - EXPECT_THAT(errors.parse_warnings(), IsEmpty()); + EXPECT_THAT(errors.parse_errors("--testoption", &this->allocator), IsEmpty()); + EXPECT_THAT(errors.parse_warnings(&this->allocator), IsEmpty()); } TEST_F(Test_Diag_Code_List, @@ -162,10 +162,11 @@ TEST_F(Test_Diag_Code_List, compiling_invalid_category_is_an_error) { .excluded_categories = Span({"strawberry"}), }); - EXPECT_THAT(errors.parse_warnings(), UnorderedElementsAreArray({ - "unknown error category: banana", - "unknown error category: strawberry", - })); + EXPECT_THAT(errors.parse_warnings(&this->allocator), + UnorderedElementsAreArray({ + "unknown error category: banana", + "unknown error category: strawberry", + })); } TEST_F(Test_Diag_Code_List, compiling_invalid_code_is_an_error) { @@ -175,10 +176,11 @@ TEST_F(Test_Diag_Code_List, compiling_invalid_code_is_an_error) { .excluded_codes = Span({"E0000"}), }); - EXPECT_THAT(errors.parse_warnings(), UnorderedElementsAreArray({ - "unknown error code: E9999", - "unknown error code: E0000", - })); + EXPECT_THAT(errors.parse_warnings(&this->allocator), + UnorderedElementsAreArray({ + "unknown error code: E9999", + "unknown error code: E0000", + })); } TEST_F(Test_Diag_Code_List, compiling_empty_parsed_diag_code_list_is_an_error) { @@ -191,9 +193,9 @@ TEST_F(Test_Diag_Code_List, compiling_empty_parsed_diag_code_list_is_an_error) { .excluded_codes = Span({"E0003"}), }); - EXPECT_THAT(errors.parse_warnings(), IsEmpty()); + EXPECT_THAT(errors.parse_warnings(&this->allocator), IsEmpty()); EXPECT_THAT( - errors.parse_errors("--testoption"), + errors.parse_errors("--testoption", &this->allocator), ElementsAreArray( {"--testoption must be given at least one category or code"})); } From 8ef114e5ecc755334c2a04bde9b4132c200dbb6f Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sun, 29 Oct 2023 01:28:57 -0400 Subject: [PATCH 054/117] refactor(cli): prefer Bump_Vector over std::vector Reduce our use of std::vector to reduce binary bloat: https://github.com/quick-lint/quick-lint-js/issues/689 --- src/quick-lint-js/cli/main.cpp | 2 +- .../container/linked-bump-allocator.h | 9 +++++++++ src/quick-lint-js/diag/diag-code-list.cpp | 15 ++++++++------ src/quick-lint-js/diag/diag-code-list.h | 20 ++++++++++++++----- 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/quick-lint-js/cli/main.cpp b/src/quick-lint-js/cli/main.cpp index 1055c84c54..033d5ac082 100644 --- a/src/quick-lint-js/cli/main.cpp +++ b/src/quick-lint-js/cli/main.cpp @@ -227,7 +227,7 @@ void init() { void run(int argc, char **argv) { Options o = parse_options(argc, argv); - run(o); + run(std::move(o)); } void run(Options o) { diff --git a/src/quick-lint-js/container/linked-bump-allocator.h b/src/quick-lint-js/container/linked-bump-allocator.h index 4c64d1b38f..f9c30c953b 100644 --- a/src/quick-lint-js/container/linked-bump-allocator.h +++ b/src/quick-lint-js/container/linked-bump-allocator.h @@ -145,6 +145,15 @@ class Linked_Bump_Allocator : public Memory_Resource { return this->new_object(std::forward(value)); } + template + Span new_objects_copy(Span objects) { + Span new_objects = this->allocate_uninitialized_span( + narrow_cast(objects.size())); + std::uninitialized_copy(objects.begin(), objects.end(), + new_objects.begin()); + return new_objects; + } + template [[nodiscard]] T* allocate_uninitialized_array(std::size_t size) { static_assert(alignof(T) <= alignment, diff --git a/src/quick-lint-js/diag/diag-code-list.cpp b/src/quick-lint-js/diag/diag-code-list.cpp index 6a6ba70160..a0bc6b58af 100644 --- a/src/quick-lint-js/diag/diag-code-list.cpp +++ b/src/quick-lint-js/diag/diag-code-list.cpp @@ -108,6 +108,10 @@ Parsed_Diag_Code_List parse_diag_code_list(const char* const raw_diag_code_list, }; } +Compiled_Diag_Code_List::Compiled_Diag_Code_List() + : allocator_( + std::make_unique("Compiled_Diag_Code_List")) {} + void Compiled_Diag_Code_List::add(const Parsed_Diag_Code_List& diag_code_list) { auto add_code = [this](std::string_view code, auto& code_set) -> void { std::optional code_diag_type = diag_type_from_code_slow(code); @@ -125,12 +129,11 @@ void Compiled_Diag_Code_List::add(const Parsed_Diag_Code_List& diag_code_list) { for (std::string_view code : diag_code_list.excluded_codes) { add_code(code, c.excluded_codes); } - c.included_categories.insert(c.included_categories.end(), - diag_code_list.included_categories.begin(), - diag_code_list.included_categories.end()); - c.excluded_categories.insert(c.excluded_categories.end(), - diag_code_list.excluded_categories.begin(), - diag_code_list.excluded_categories.end()); + // TODO(strager): Copy the referenced std::string_view-s. + c.included_categories = + this->allocator_->new_objects_copy(diag_code_list.included_categories); + c.excluded_categories = + this->allocator_->new_objects_copy(diag_code_list.excluded_categories); c.override_defaults = diag_code_list.override_defaults; if (diag_code_list.error_missing_predicate()) { diff --git a/src/quick-lint-js/diag/diag-code-list.h b/src/quick-lint-js/diag/diag-code-list.h index 7b7fc07d43..75b10fc81f 100644 --- a/src/quick-lint-js/diag/diag-code-list.h +++ b/src/quick-lint-js/diag/diag-code-list.h @@ -5,12 +5,13 @@ #include #include +#include #include +#include #include #include #include #include -#include namespace quick_lint_js { struct Parsed_Diag_Code_List { @@ -34,6 +35,8 @@ Parsed_Diag_Code_List parse_diag_code_list(const char* raw_diag_code_list, class Compiled_Diag_Code_List { public: + explicit Compiled_Diag_Code_List(); + // Retains references to the std::string_view-s. void add(const Parsed_Diag_Code_List&); @@ -49,15 +52,22 @@ class Compiled_Diag_Code_List { struct Codes { std::bitset included_codes; std::bitset excluded_codes; - std::vector included_categories; - std::vector excluded_categories; + Span included_categories; + Span excluded_categories; bool override_defaults; }; - std::vector parsed_diag_code_lists_; + // TODO(strager): Make caller provide the allocator. + // HACK(strager): This is a unique_ptr to make Compiled_Diag_Code_List + // movable. + std::unique_ptr allocator_; + + Bump_Vector parsed_diag_code_lists_{ + "parsed_diag_code_lists_", this->allocator_.get()}; // Collected errors and warnings: - std::vector unknown_codes_; + Bump_Vector unknown_codes_{ + "unknown_codes_", this->allocator_.get()}; bool has_missing_predicate_error_ = false; }; } From ff8c967d75d3bf973330c458b549e3aea2fbb8f7 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sun, 29 Oct 2023 01:28:57 -0400 Subject: [PATCH 055/117] refactor(cli): add allocator argument to parse_options This argument will be used in the future to let us drop some uses of std::vector. --- src/quick-lint-js/cli/main.cpp | 3 +- src/quick-lint-js/cli/options.cpp | 3 +- src/quick-lint-js/cli/options.h | 4 +- test/test-options.cpp | 105 ++++++++++++++++-------------- 4 files changed, 63 insertions(+), 52 deletions(-) diff --git a/src/quick-lint-js/cli/main.cpp b/src/quick-lint-js/cli/main.cpp index 033d5ac082..7e5e8a5f30 100644 --- a/src/quick-lint-js/cli/main.cpp +++ b/src/quick-lint-js/cli/main.cpp @@ -226,7 +226,8 @@ void init() { } void run(int argc, char **argv) { - Options o = parse_options(argc, argv); + Monotonic_Allocator options_allocator("run options_allocator"); + Options o = parse_options(argc, argv, &options_allocator); run(std::move(o)); } diff --git a/src/quick-lint-js/cli/options.cpp b/src/quick-lint-js/cli/options.cpp index 950f06532c..1d0f0f82f9 100644 --- a/src/quick-lint-js/cli/options.cpp +++ b/src/quick-lint-js/cli/options.cpp @@ -25,7 +25,8 @@ QLJS_WARNING_IGNORE_GCC("-Wshadow=local") using namespace std::literals::string_view_literals; namespace quick_lint_js { -Options parse_options(int argc, char** argv) { +Options parse_options(int argc, char** argv, + [[maybe_unused]] Monotonic_Allocator* allocator) { Options o; Monotonic_Allocator temporary_allocator("parse_options"); diff --git a/src/quick-lint-js/cli/options.h b/src/quick-lint-js/cli/options.h index 646c530f30..2f571fecf4 100644 --- a/src/quick-lint-js/cli/options.h +++ b/src/quick-lint-js/cli/options.h @@ -4,6 +4,7 @@ #pragma once #include +#include #include #include @@ -86,7 +87,8 @@ Resolved_Input_File_Language get_language(const File_To_Lint &file, Resolved_Input_File_Language get_language(const char *file, Raw_Input_File_Language language); -Options parse_options(int argc, char **argv); +// Returns portions of argv and memory allocated by allocator. +Options parse_options(int argc, char **argv, Monotonic_Allocator *allocator); } // quick-lint-js finds bugs in JavaScript programs. diff --git a/test/test-options.cpp b/test/test-options.cpp index 4ebe4280ae..ea983be5bc 100644 --- a/test/test-options.cpp +++ b/test/test-options.cpp @@ -21,23 +21,29 @@ using namespace std::literals::string_view_literals; namespace quick_lint_js { namespace { -Options parse_options(std::initializer_list arguments) { - std::vector argv; - argv.emplace_back(const_cast("(program)")); - for (const char *argument : arguments) { - argv.emplace_back(const_cast(argument)); +class Test_Options : public ::testing::Test { + public: + Options parse_options(std::initializer_list arguments) { + std::vector argv; + argv.emplace_back(const_cast("(program)")); + for (const char *argument : arguments) { + argv.emplace_back(const_cast(argument)); + } + return quick_lint_js::parse_options(narrow_cast(argv.size()), + argv.data(), &this->allocator); } - return quick_lint_js::parse_options(narrow_cast(argv.size()), - argv.data()); -} -Options parse_options_no_errors(std::initializer_list arguments) { - Options o = parse_options(arguments); - EXPECT_THAT(o.error_unrecognized_options, IsEmpty()); - EXPECT_THAT(o.warning_language_without_file, IsEmpty()); - EXPECT_THAT(o.warning_vim_bufnr_without_file, IsEmpty()); - return o; -} + Options parse_options_no_errors( + std::initializer_list arguments) { + Options o = this->parse_options(arguments); + EXPECT_THAT(o.error_unrecognized_options, IsEmpty()); + EXPECT_THAT(o.warning_language_without_file, IsEmpty()); + EXPECT_THAT(o.warning_vim_bufnr_without_file, IsEmpty()); + return o; + } + + Monotonic_Allocator allocator{"Test_Options"}; +}; struct Dumped_Errors { bool have_errors; @@ -54,7 +60,7 @@ Dumped_Errors dump_errors(const Options &o) { }; } -TEST(Test_Options, default_options_with_no_files) { +TEST_F(Test_Options, default_options_with_no_files) { Options o = parse_options_no_errors({}); EXPECT_FALSE(o.print_parser_visits); EXPECT_FALSE(o.help); @@ -65,7 +71,7 @@ TEST(Test_Options, default_options_with_no_files) { EXPECT_THAT(o.files_to_lint, IsEmpty()); } -TEST(Test_Options, default_options_with_files) { +TEST_F(Test_Options, default_options_with_files) { Options o = parse_options_no_errors({"foo.js"}); EXPECT_FALSE(o.print_parser_visits); EXPECT_FALSE(o.snarky); @@ -73,7 +79,7 @@ TEST(Test_Options, default_options_with_files) { EXPECT_EQ(o.files_to_lint[0].path, "foo.js"sv); } -TEST(Test_Options, hyphen_hyphen_treats_remaining_arguments_as_files) { +TEST_F(Test_Options, hyphen_hyphen_treats_remaining_arguments_as_files) { { Options o = parse_options_no_errors({"--", "foo.js"}); ASSERT_EQ(o.files_to_lint.size(), 1); @@ -91,21 +97,21 @@ TEST(Test_Options, hyphen_hyphen_treats_remaining_arguments_as_files) { } } -TEST(Test_Options, debug_parser_visits) { +TEST_F(Test_Options, debug_parser_visits) { Options o = parse_options_no_errors({"--debug-parser-visits", "foo.js"}); EXPECT_TRUE(o.print_parser_visits); ASSERT_EQ(o.files_to_lint.size(), 1); EXPECT_EQ(o.files_to_lint[0].path, "foo.js"sv); } -TEST(Test_Options, snarky) { +TEST_F(Test_Options, snarky) { Options o = parse_options_no_errors({"--snarky", "foo.js"}); EXPECT_TRUE(o.snarky); ASSERT_EQ(o.files_to_lint.size(), 1); EXPECT_EQ(o.files_to_lint[0].path, "foo.js"sv); } -TEST(Test_Options, debug_parser_visits_shorthand) { +TEST_F(Test_Options, debug_parser_visits_shorthand) { { Options o = parse_options_no_errors({"--debug-p", "foo.js"}); EXPECT_TRUE(o.print_parser_visits); @@ -117,7 +123,7 @@ TEST(Test_Options, debug_parser_visits_shorthand) { } } -TEST(Test_Options, output_format) { +TEST_F(Test_Options, output_format) { { Options o = parse_options_no_errors({}); EXPECT_EQ(o.output_format, Output_Format::default_format); @@ -139,7 +145,7 @@ TEST(Test_Options, output_format) { } } -TEST(Test_Options, invalid_output_format) { +TEST_F(Test_Options, invalid_output_format) { { Options o = parse_options({"--output-format=unknown-garbage"}); EXPECT_THAT(o.error_unrecognized_options, @@ -155,7 +161,7 @@ TEST(Test_Options, invalid_output_format) { } } -TEST(Test_Options, vim_file_bufnr) { +TEST_F(Test_Options, vim_file_bufnr) { { Options o = parse_options_no_errors({"one.js", "two.js"}); ASSERT_EQ(o.files_to_lint.size(), 2); @@ -217,7 +223,7 @@ TEST(Test_Options, vim_file_bufnr) { } } -TEST(Test_Options, path_for_config_search) { +TEST_F(Test_Options, path_for_config_search) { { Options o = parse_options_no_errors({"one.js", "two.js"}); ASSERT_EQ(o.files_to_lint.size(), 2); @@ -289,7 +295,7 @@ TEST(Test_Options, path_for_config_search) { } } -TEST(Test_Options, config_file) { +TEST_F(Test_Options, config_file) { { Options o = parse_options_no_errors({"one.js", "two.js"}); ASSERT_EQ(o.files_to_lint.size(), 2); @@ -353,7 +359,7 @@ TEST(Test_Options, config_file) { } } -TEST(Test_Options, language) { +TEST_F(Test_Options, language) { constexpr Raw_Input_File_Language default_language = Raw_Input_File_Language::default_; @@ -448,7 +454,7 @@ TEST(Test_Options, language) { } } -TEST(Test_Options, language_after_file) { +TEST_F(Test_Options, language_after_file) { Options o = parse_options({"file.js", "--language=javascript-jsx"}); EXPECT_THAT(o.warning_language_without_file, ElementsAreArray({"javascript-jsx"sv})); @@ -461,7 +467,7 @@ TEST(Test_Options, language_after_file) { u8"input file name or --stdin\n"); } -TEST(Test_Options, multiple_languages) { +TEST_F(Test_Options, multiple_languages) { Options o = parse_options( {"--language=javascript", "--language=javascript-jsx", "test.jsx"}); EXPECT_THAT(o.warning_language_without_file, @@ -474,7 +480,7 @@ TEST(Test_Options, multiple_languages) { u8"input file name or --stdin\n"); } -TEST(Test_Options, invalid_language) { +TEST_F(Test_Options, invalid_language) { Options o = parse_options({"--language=badlanguageid", "test.js"}); EXPECT_THAT(o.warning_language_without_file, IsEmpty()); // TODO(strager): Highlight the full option, not just the value. @@ -482,7 +488,8 @@ TEST(Test_Options, invalid_language) { ElementsAreArray({"badlanguageid"sv})); } -TEST(Test_Options, default_language_is_javascript_jsx_regardless_of_extension) { +TEST_F(Test_Options, + default_language_is_javascript_jsx_regardless_of_extension) { constexpr auto default_language = Raw_Input_File_Language::default_; constexpr auto javascript_jsx = Resolved_Input_File_Language::javascript_jsx; EXPECT_EQ(get_language("", default_language), javascript_jsx); @@ -495,8 +502,8 @@ TEST(Test_Options, default_language_is_javascript_jsx_regardless_of_extension) { EXPECT_EQ(get_language("hi.txt", default_language), javascript_jsx); } -TEST(Test_Options, - experimental_default_language_guesses_language_from_extension) { +TEST_F(Test_Options, + experimental_default_language_guesses_language_from_extension) { constexpr auto default_language = Raw_Input_File_Language::experimental_default; constexpr auto javascript_jsx = Resolved_Input_File_Language::javascript_jsx; @@ -522,7 +529,7 @@ TEST(Test_Options, } } -TEST(Test_Options, get_language_overwritten) { +TEST_F(Test_Options, get_language_overwritten) { constexpr auto in_javascript = Raw_Input_File_Language::javascript; constexpr auto in_javascript_jsx = Raw_Input_File_Language::javascript_jsx; constexpr auto javascript = Resolved_Input_File_Language::javascript; @@ -539,7 +546,7 @@ TEST(Test_Options, get_language_overwritten) { EXPECT_EQ(get_language("hi.txt", in_javascript), javascript); } -TEST(Test_Options, lsp_server) { +TEST_F(Test_Options, lsp_server) { { Options o = parse_options_no_errors({"--lsp-server"}); EXPECT_TRUE(o.lsp_server); @@ -551,7 +558,7 @@ TEST(Test_Options, lsp_server) { } } -TEST(Test_Options, stdin_file) { +TEST_F(Test_Options, stdin_file) { { Options o = parse_options_no_errors({"--stdin", "one.js"}); ASSERT_EQ(o.files_to_lint.size(), 2); @@ -577,7 +584,7 @@ TEST(Test_Options, stdin_file) { } } -TEST(Test_Options, is_stdin_emplaced_only_once) { +TEST_F(Test_Options, is_stdin_emplaced_only_once) { { Options o = parse_options_no_errors({"--stdin", "one.js", "-", "two.js"}); ASSERT_EQ(o.files_to_lint.size(), 3); @@ -590,7 +597,7 @@ TEST(Test_Options, is_stdin_emplaced_only_once) { } } -TEST(Test_Options, path_for_stdin) { +TEST_F(Test_Options, path_for_stdin) { { Options o = parse_options_no_errors({"--stdin-path", "a.js", "--stdin"}); ASSERT_EQ(o.files_to_lint.size(), 1); @@ -641,7 +648,7 @@ TEST(Test_Options, path_for_stdin) { } } -TEST(Test_Options, print_help) { +TEST_F(Test_Options, print_help) { { Options o = parse_options_no_errors({"--help"}); EXPECT_TRUE(o.help); @@ -658,12 +665,12 @@ TEST(Test_Options, print_help) { } } -TEST(Test_Options, list_debug_apps) { +TEST_F(Test_Options, list_debug_apps) { Options o = parse_options_no_errors({"--debug-apps"}); EXPECT_TRUE(o.list_debug_apps); } -TEST(Test_Options, print_version) { +TEST_F(Test_Options, print_version) { { Options o = parse_options_no_errors({"--version"}); EXPECT_TRUE(o.version); @@ -680,7 +687,7 @@ TEST(Test_Options, print_version) { } } -TEST(Test_Options, exit_fail_on) { +TEST_F(Test_Options, exit_fail_on) { { Options o = parse_options_no_errors({"--exit-fail-on=E0003", "file.js"}); EXPECT_TRUE( @@ -692,7 +699,7 @@ TEST(Test_Options, exit_fail_on) { } } -TEST(Test_Options, invalid_vim_file_bufnr) { +TEST_F(Test_Options, invalid_vim_file_bufnr) { { Options o = parse_options({"--vim-file-bufnr=garbage", "file.js"}); EXPECT_THAT(o.error_unrecognized_options, ElementsAreArray({"garbage"sv})); @@ -705,7 +712,7 @@ TEST(Test_Options, invalid_vim_file_bufnr) { } } -TEST(Test_Options, no_following_filename_vim_file_bufnr) { +TEST_F(Test_Options, no_following_filename_vim_file_bufnr) { { Options o = parse_options({"foo.js", "--vim-file-bufnr=1"}); o.output_format = Output_Format::vim_qflist_json; @@ -776,7 +783,7 @@ TEST(Test_Options, no_following_filename_vim_file_bufnr) { } } -TEST(Test_Options, using_vim_file_bufnr_without_format) { +TEST_F(Test_Options, using_vim_file_bufnr_without_format) { { for (const auto &format : { Output_Format::default_format, @@ -803,7 +810,7 @@ TEST(Test_Options, using_vim_file_bufnr_without_format) { } } -TEST(Test_Options, using_vim_file_bufnr_in_lsp_mode) { +TEST_F(Test_Options, using_vim_file_bufnr_in_lsp_mode) { { Options o = parse_options({"--lsp-server", "--vim-file-bufnr=1"}); @@ -824,7 +831,7 @@ TEST(Test_Options, using_vim_file_bufnr_in_lsp_mode) { } } -TEST(Test_Options, using_language_in_lsp_mode) { +TEST_F(Test_Options, using_language_in_lsp_mode) { { Options o = parse_options({"--lsp-server", "--language=javascript"}); @@ -846,7 +853,7 @@ TEST(Test_Options, using_language_in_lsp_mode) { } } -TEST(Test_Options, invalid_option) { +TEST_F(Test_Options, invalid_option) { { Options o = parse_options({"--option-does-not-exist", "foo.js"}); EXPECT_THAT(o.error_unrecognized_options, @@ -875,7 +882,7 @@ TEST(Test_Options, invalid_option) { } } -TEST(Test_Options, dump_errors) { +TEST_F(Test_Options, dump_errors) { { Options o; o.error_unrecognized_options.clear(); From 045e99701dc4d9d9159aef8dbfef0f8c71567191 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sun, 29 Oct 2023 01:28:57 -0400 Subject: [PATCH 056/117] refactor(cli): prefer Bump_Vector over std::vector Reduce our use of std::vector to reduce binary bloat: https://github.com/quick-lint/quick-lint-js/issues/689 --- src/quick-lint-js/cli/options.cpp | 40 +++++++++++++++++++++---------- src/quick-lint-js/cli/options.h | 10 ++++---- test/test-options.cpp | 22 ++++++++++------- 3 files changed, 45 insertions(+), 27 deletions(-) diff --git a/src/quick-lint-js/cli/options.cpp b/src/quick-lint-js/cli/options.cpp index 1d0f0f82f9..949184ed9b 100644 --- a/src/quick-lint-js/cli/options.cpp +++ b/src/quick-lint-js/cli/options.cpp @@ -25,8 +25,7 @@ QLJS_WARNING_IGNORE_GCC("-Wshadow=local") using namespace std::literals::string_view_literals; namespace quick_lint_js { -Options parse_options(int argc, char** argv, - [[maybe_unused]] Monotonic_Allocator* allocator) { +Options parse_options(int argc, char** argv, Monotonic_Allocator* allocator) { Options o; Monotonic_Allocator temporary_allocator("parse_options"); @@ -36,6 +35,15 @@ Options parse_options(int argc, char** argv, const char* arg_var; } next_vim_file_bufnr; + Bump_Vector files_to_lint("files_to_lint", + allocator); + Bump_Vector error_unrecognized_options( + "error_unrecognized_options", allocator); + Bump_Vector warning_vim_bufnr_without_file( + "warning_vim_bufnr_without_file", allocator); + Bump_Vector warning_language_without_file( + "warning_language_without_file", allocator); + const char* next_path_for_config_search = nullptr; const char* active_config_file = nullptr; Raw_Input_File_Language language = Raw_Input_File_Language::default_; @@ -52,7 +60,7 @@ Options parse_options(int argc, char** argv, .language = language, .is_stdin = is_stdin, .vim_bufnr = next_vim_file_bufnr.number}; - o.files_to_lint.emplace_back(file); + files_to_lint.emplace_back(file); } if (is_stdin) { has_stdin = true; @@ -91,7 +99,7 @@ Options parse_options(int argc, char** argv, } else if (arg_value == "emacs-lisp"sv) { o.output_format = Output_Format::emacs_lisp; } else { - o.error_unrecognized_options.emplace_back(arg_value); + error_unrecognized_options.emplace_back(arg_value); } } @@ -103,7 +111,7 @@ Options parse_options(int argc, char** argv, } else if (arg_value == "never"sv) { o.diagnostic_hyperlinks = Option_When::never; } else { - o.error_unrecognized_options.emplace_back(arg_value); + error_unrecognized_options.emplace_back(arg_value); } } @@ -115,7 +123,7 @@ Options parse_options(int argc, char** argv, QLJS_OPTION(const char* arg_value, "--language"sv) { o.has_language = true; if (unused_language_option) { - o.warning_language_without_file.emplace_back(unused_language_option); + warning_language_without_file.emplace_back(unused_language_option); } unused_language_option = arg_value; if (arg_value == "default"sv) { @@ -133,7 +141,7 @@ Options parse_options(int argc, char** argv, } else if (arg_value == "experimental-typescript-jsx"sv) { language = Raw_Input_File_Language::typescript_jsx; } else { - o.error_unrecognized_options.emplace_back(arg_value); + error_unrecognized_options.emplace_back(arg_value); } } @@ -150,11 +158,11 @@ Options parse_options(int argc, char** argv, int bufnr; if (parse_integer_exact(std::string_view(arg_value), bufnr) != Parse_Integer_Exact_Error::ok) { - o.error_unrecognized_options.emplace_back(arg_value); + error_unrecognized_options.emplace_back(arg_value); continue; } if (next_vim_file_bufnr.number != std::nullopt) { - o.warning_vim_bufnr_without_file.emplace_back( + warning_vim_bufnr_without_file.emplace_back( next_vim_file_bufnr.arg_var); } next_vim_file_bufnr.number = bufnr; @@ -173,26 +181,32 @@ Options parse_options(int argc, char** argv, QLJS_FLAG("--stdin"sv, ""sv) { add_stdin_file(); } QLJS_UNRECOGNIZED_OPTION(const char* unrecognized) { - o.error_unrecognized_options.emplace_back(unrecognized); + error_unrecognized_options.emplace_back(unrecognized); goto done_parsing_options; } } done_parsing_options: if (unused_language_option) { - o.warning_language_without_file.emplace_back(unused_language_option); + warning_language_without_file.emplace_back(unused_language_option); } if (next_vim_file_bufnr.number != std::nullopt) { - o.warning_vim_bufnr_without_file.emplace_back(next_vim_file_bufnr.arg_var); + warning_vim_bufnr_without_file.emplace_back(next_vim_file_bufnr.arg_var); } if (o.path_for_stdin != nullptr) { - for (File_To_Lint& file : o.files_to_lint) { + for (File_To_Lint& file : files_to_lint) { if (file.path_for_config_search == nullptr) { file.path_for_config_search = o.path_for_stdin; } } } + o.files_to_lint = files_to_lint.release_to_span(); + o.error_unrecognized_options = error_unrecognized_options.release_to_span(); + o.warning_vim_bufnr_without_file = + warning_vim_bufnr_without_file.release_to_span(); + o.warning_language_without_file = + warning_language_without_file.release_to_span(); return o; } diff --git a/src/quick-lint-js/cli/options.h b/src/quick-lint-js/cli/options.h index 2f571fecf4..64d174341d 100644 --- a/src/quick-lint-js/cli/options.h +++ b/src/quick-lint-js/cli/options.h @@ -6,7 +6,7 @@ #include #include #include -#include +#include namespace quick_lint_js { class Output_Stream; @@ -65,13 +65,13 @@ struct Options { bool snarky = false; Output_Format output_format = Output_Format::default_format; Option_When diagnostic_hyperlinks = Option_When::auto_; - std::vector files_to_lint; + Span files_to_lint; Compiled_Diag_Code_List exit_fail_on; const char *path_for_stdin = nullptr; - std::vector error_unrecognized_options; - std::vector warning_vim_bufnr_without_file; - std::vector warning_language_without_file; + Span error_unrecognized_options; + Span warning_vim_bufnr_without_file; + Span warning_language_without_file; bool has_multiple_stdin = false; bool has_config_file = false; bool has_language = false; diff --git a/test/test-options.cpp b/test/test-options.cpp index ea983be5bc..159659c801 100644 --- a/test/test-options.cpp +++ b/test/test-options.cpp @@ -885,7 +885,7 @@ TEST_F(Test_Options, invalid_option) { TEST_F(Test_Options, dump_errors) { { Options o; - o.error_unrecognized_options.clear(); + o.error_unrecognized_options = Span(); Dumped_Errors errors = dump_errors(o); EXPECT_FALSE(errors.have_errors); @@ -893,8 +893,10 @@ TEST_F(Test_Options, dump_errors) { } { + const char *unrecognized_options[] = {"--bad-option"}; Options o; - o.error_unrecognized_options.push_back("--bad-option"); + o.error_unrecognized_options = + Span(unrecognized_options); Dumped_Errors errors = dump_errors(o); EXPECT_TRUE(errors.have_errors); @@ -965,17 +967,19 @@ TEST_F(Test_Options, dump_errors) { } { - const File_To_Lint file = { - .path = "file.js", - .config_file = nullptr, - .language = Raw_Input_File_Language::default_, - .is_stdin = false, - .vim_bufnr = std::optional(), + const File_To_Lint files[] = { + File_To_Lint{ + .path = "file.js", + .config_file = nullptr, + .language = Raw_Input_File_Language::default_, + .is_stdin = false, + .vim_bufnr = std::optional(), + }, }; Options o; o.lsp_server = true; - o.files_to_lint.emplace_back(file); + o.files_to_lint = Span(files); Dumped_Errors errors = dump_errors(o); EXPECT_FALSE(errors.have_errors); From 46a20e412c8097c714ffc3fd9484adcac346f550 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sun, 29 Oct 2023 01:47:07 -0400 Subject: [PATCH 057/117] refactor(container): drop allocate_uninitialized_array; use alloc_uninit_span Linked_Bump_Allocator::allocate_uninitialized_span is a bit safer than allocate_uninitialized_array. Port callers of the latter to use the former and drop the redundant allocate_uninitialized_array. --- src/quick-lint-js/c-api-diag-reporter.cpp | 13 +++-- .../configuration/configuration.cpp | 9 ++-- .../container/linked-bump-allocator.h | 9 +--- src/quick-lint-js/container/vector.h | 20 +++---- src/quick-lint-js/fe/expression.h | 9 ++-- src/quick-lint-js/fe/jsx.cpp | 9 ++-- src/quick-lint-js/fe/lex.cpp | 14 ++--- test/test-linked-bump-allocator.cpp | 53 ++++++++++--------- tools/compile-translations.cpp | 8 +-- 9 files changed, 76 insertions(+), 68 deletions(-) diff --git a/src/quick-lint-js/c-api-diag-reporter.cpp b/src/quick-lint-js/c-api-diag-reporter.cpp index 76c0739cfa..c06e6e5132 100644 --- a/src/quick-lint-js/c-api-diag-reporter.cpp +++ b/src/quick-lint-js/c-api-diag-reporter.cpp @@ -57,12 +57,15 @@ const Diagnostic *C_API_Diag_Reporter::get_diagnostics() { template Char8 *C_API_Diag_Reporter::allocate_c_string( String8_View string) { - Char8 *result = - this->string_allocator_.template allocate_uninitialized_array( + // TODO(strager): Use Linked_Bump_Allocator::new_objects_copy. + Span result = + this->string_allocator_.template allocate_uninitialized_span( string.size() + 1); - std::uninitialized_copy(string.begin(), string.end(), result); - result[string.size()] = u8'\0'; - return result; + Char8 *result_end = + std::uninitialized_copy(string.begin(), string.end(), result.begin()); + *result_end++ = u8'\0'; + QLJS_ASSERT(result_end == result.end()); + return result.data(); } template diff --git a/src/quick-lint-js/configuration/configuration.cpp b/src/quick-lint-js/configuration/configuration.cpp index b1d8aa5d3e..83cfcaf99b 100644 --- a/src/quick-lint-js/configuration/configuration.cpp +++ b/src/quick-lint-js/configuration/configuration.cpp @@ -304,10 +304,11 @@ bool Configuration::load_globals_from_json( String8_View Configuration::save_string(std::string_view s) { String8_View s8 = to_string8_view(s); - Char8* out_begin = - string_allocator_.allocate_uninitialized_array(s8.size()); - std::uninitialized_copy(s8.begin(), s8.end(), out_begin); - return String8_View(out_begin, s8.size()); + // TODO(strager): Use Linked_Bump_Allocator::new_objects_copy. + Span out = + string_allocator_.allocate_uninitialized_span(s8.size()); + std::uninitialized_copy(s8.begin(), s8.end(), out.data()); + return String8_View(out.data(), narrow_cast(out.size())); } bool Configuration::should_remove_global_variable(String8_View name) { diff --git a/src/quick-lint-js/container/linked-bump-allocator.h b/src/quick-lint-js/container/linked-bump-allocator.h index f9c30c953b..30956ceae8 100644 --- a/src/quick-lint-js/container/linked-bump-allocator.h +++ b/src/quick-lint-js/container/linked-bump-allocator.h @@ -155,17 +155,12 @@ class Linked_Bump_Allocator : public Memory_Resource { } template - [[nodiscard]] T* allocate_uninitialized_array(std::size_t size) { + [[nodiscard]] Span allocate_uninitialized_span(std::size_t size) { static_assert(alignof(T) <= alignment, "T is not allowed by this allocator; this allocator's " "alignment is insufficient for T"); std::size_t byte_size = this->align_up(size * sizeof(T)); - return reinterpret_cast(this->allocate_bytes(byte_size)); - } - - template - [[nodiscard]] Span allocate_uninitialized_span(std::size_t size) { - T* items = this->allocate_uninitialized_array(size); + T* items = reinterpret_cast(this->allocate_bytes(byte_size)); return Span(items, narrow_cast(size)); } diff --git a/src/quick-lint-js/container/vector.h b/src/quick-lint-js/container/vector.h index 499358556d..45e1930a84 100644 --- a/src/quick-lint-js/container/vector.h +++ b/src/quick-lint-js/container/vector.h @@ -183,21 +183,23 @@ class Raw_Bump_Vector { if (grew) { this->capacity_end_ = this->data_ + new_capacity; } else { - T *new_data = - this->allocator_->template allocate_uninitialized_array( + Span new_data = + this->allocator_->template allocate_uninitialized_span( narrow_cast(new_capacity)); - T *new_data_end = - std::uninitialized_move(this->data_, this->data_end_, new_data); + T *new_data_end = std::uninitialized_move(this->data_, this->data_end_, + new_data.begin()); this->clear(); - this->data_ = new_data; + this->data_ = new_data.begin(); this->data_end_ = new_data_end; - this->capacity_end_ = new_data + new_capacity; + this->capacity_end_ = new_data.end(); } } else { - this->data_ = this->allocator_->template allocate_uninitialized_array( - narrow_cast(new_capacity)); + Span new_data = + this->allocator_->template allocate_uninitialized_span( + narrow_cast(new_capacity)); + this->data_ = new_data.begin(); this->data_end_ = this->data_; - this->capacity_end_ = this->data_ + new_capacity; + this->capacity_end_ = new_data.end(); } } diff --git a/src/quick-lint-js/fe/expression.h b/src/quick-lint-js/fe/expression.h index 51054e5048..b9f9fd3841 100644 --- a/src/quick-lint-js/fe/expression.h +++ b/src/quick-lint-js/fe/expression.h @@ -189,13 +189,16 @@ class Expression_Arena { return this->allocator_.new_object(std::forward(args)...); } + // TODO(strager): Accept a Span. + // TODO(strager): Return a Span. template T *allocate_array_move(T *begin, T *end) { static_assert(is_allocatable); - T *result = this->allocator_.allocate_uninitialized_array( + // TODO(strager): Implement Linked_Bump_Allocator::new_objects_move. + Span result = this->allocator_.allocate_uninitialized_span( narrow_cast(end - begin)); - std::uninitialized_move(begin, end, result); - return result; + std::uninitialized_move(begin, end, result.data()); + return result.data(); } Monotonic_Allocator allocator_{"expression_arena"}; diff --git a/src/quick-lint-js/fe/jsx.cpp b/src/quick-lint-js/fe/jsx.cpp index 9b53311251..a29f932f1c 100644 --- a/src/quick-lint-js/fe/jsx.cpp +++ b/src/quick-lint-js/fe/jsx.cpp @@ -413,13 +413,14 @@ const Hash_Map& jsx_attribute_aliases() { for (std::string_view raw_attribute_name : C_String_List_View(attribute_names)) { String8_View attribute_name = to_string8_view(raw_attribute_name); - Char8* lowered_attribute_name = - string_allocator.allocate_uninitialized_array( + Span lowered_attribute_name = + string_allocator.allocate_uninitialized_span( attribute_name.size()); std::transform(attribute_name.begin(), attribute_name.end(), - lowered_attribute_name, tolower); + lowered_attribute_name.begin(), tolower); auto [_it, inserted] = aliases.try_emplace( - String8_View(lowered_attribute_name, attribute_name.size()), + String8_View(lowered_attribute_name.begin(), + narrow_cast(lowered_attribute_name.size())), JSX_Attribute{attribute_name}); QLJS_ASSERT(inserted); } diff --git a/src/quick-lint-js/fe/lex.cpp b/src/quick-lint-js/fe/lex.cpp index 79f991c56d..f8ce38df7b 100644 --- a/src/quick-lint-js/fe/lex.cpp +++ b/src/quick-lint-js/fe/lex.cpp @@ -1362,12 +1362,14 @@ void Lexer::check_integer_precision_loss(String8_View number_literal) { std::string_view result_string_view(result_string.data(), static_cast(rc)); if (cleaned_string != result_string_view) { - Char8* rounded_val = this->allocator_.allocate_uninitialized_array( - result_string_view.size()); - std::copy(result_string_view.begin(), result_string_view.end(), - rounded_val); - String8_View rounded_val_string_view = - String8_View(rounded_val, result_string_view.size()); + // TODO(strager): Use Linked_Bump_Allocator::new_objects_copy + Span rounded_val = + this->allocator_.allocate_uninitialized_span( + result_string_view.size()); + std::uninitialized_copy(result_string_view.begin(), + result_string_view.end(), rounded_val.data()); + String8_View rounded_val_string_view = String8_View( + rounded_val.data(), narrow_cast(rounded_val.size())); this->diag_reporter_->report(Diag_Integer_Literal_Will_Lose_Precision{ .characters = Source_Code_Span(number_literal.data(), diff --git a/test/test-linked-bump-allocator.cpp b/test/test-linked-bump-allocator.cpp index b3338ea73c..f08c7ec5ff 100644 --- a/test/test-linked-bump-allocator.cpp +++ b/test/test-linked-bump-allocator.cpp @@ -66,14 +66,15 @@ TEST(Test_Linked_Bump_Allocator, TEST(Test_Linked_Bump_Allocator, array_allocation_is_contiguous) { Linked_Bump_Allocator<1> alloc("test"); - char* chars = alloc.allocate_uninitialized_array(42); - assert_valid_memory(chars, chars + 42, alignof(char)); + Span chars = alloc.allocate_uninitialized_span(42); + assert_valid_memory(chars.data(), chars.data() + 42, alignof(char)); } TEST(Test_Linked_Bump_Allocator, less_aligned_array_keeps_next_allocation_aligned) { Linked_Bump_Allocator<4> alloc("test"); - [[maybe_unused]] char* chars = alloc.allocate_uninitialized_array(3); + [[maybe_unused]] Span chars = + alloc.allocate_uninitialized_span(3); std::uint32_t* after = alloc.new_object(); assert_valid_memory(after); } @@ -82,8 +83,8 @@ TEST(Test_Linked_Bump_Allocator, less_aligned_pre_grown_and_grown_array_keeps_next_allocation_aligned) { Linked_Bump_Allocator<4> alloc("test"); - char* chars = alloc.allocate_uninitialized_array(3); - bool grew = alloc.try_grow_array_in_place(chars, 3, 6); + Span chars = alloc.allocate_uninitialized_span(3); + bool grew = alloc.try_grow_array_in_place(chars.data(), 3, 6); EXPECT_TRUE(grew); std::uint32_t* after = alloc.new_object(); @@ -94,8 +95,8 @@ TEST(Test_Linked_Bump_Allocator, less_aligned_grown_array_keeps_next_allocation_aligned) { Linked_Bump_Allocator<4> alloc("test"); - char* chars = alloc.allocate_uninitialized_array(4); - bool grew = alloc.try_grow_array_in_place(chars, 4, 7); + Span chars = alloc.allocate_uninitialized_span(4); + bool grew = alloc.try_grow_array_in_place(chars.data(), 4, 7); EXPECT_TRUE(grew); std::uint32_t* after = alloc.new_object(); @@ -203,8 +204,8 @@ TEST(Test_Linked_Bump_Allocator, alloc.prepare_for_rewind(); // Second chunk: - [[maybe_unused]] char* big_allocation = - alloc.allocate_uninitialized_array(first_chunk_size + 64); + [[maybe_unused]] Span big_allocation = + alloc.allocate_uninitialized_span(first_chunk_size + 64); // Third chunk: std::size_t third_chunk_size = first_chunk_size; @@ -222,14 +223,14 @@ TEST(Test_Linked_Bump_Allocator, TEST(Test_Linked_Bump_Allocator, last_allocation_can_grow_in_place) { Linked_Bump_Allocator<1> alloc("test"); - char* array = alloc.allocate_uninitialized_array(10); - bool ok = alloc.try_grow_array_in_place(array, 10, 20); + Span array = alloc.allocate_uninitialized_span(10); + bool ok = alloc.try_grow_array_in_place(array.data(), 10, 20); EXPECT_TRUE(ok); - assert_valid_memory(array, array + 20, /*alignment=*/1); + assert_valid_memory(array.data(), array.data() + 20, /*alignment=*/1); - char* next = alloc.allocate_uninitialized_array(1); - EXPECT_THAT(reinterpret_cast(next) - - reinterpret_cast(array), + Span next = alloc.allocate_uninitialized_span(1); + EXPECT_THAT(reinterpret_cast(next.data()) - + reinterpret_cast(array.data()), ::testing::AnyOf(1, 20)) << "future allocations should not overlap resized array"; } @@ -244,30 +245,30 @@ TEST(Test_Linked_Bump_Allocator, for (std::size_t i = 0; i < first_chunk_size - 15; ++i) { [[maybe_unused]] char* byte = alloc.new_object(); } - char* array = alloc.allocate_uninitialized_array(10); + Span array = alloc.allocate_uninitialized_span(10); EXPECT_EQ(alloc.remaining_bytes_in_current_chunk(), 5); - bool ok = alloc.try_grow_array_in_place(array, 10, 20); + bool ok = alloc.try_grow_array_in_place(array.data(), 10, 20); EXPECT_FALSE(ok); - assert_valid_memory(array, array + 10, /*alignment=*/1); + assert_valid_memory(array.data(), array.data() + 10, /*alignment=*/1); - char* next = alloc.allocate_uninitialized_array(1); - EXPECT_THAT(reinterpret_cast(next) - - reinterpret_cast(array), + Span next = alloc.allocate_uninitialized_span(1); + EXPECT_THAT(reinterpret_cast(next.data()) - + reinterpret_cast(array.data()), ::testing::AnyOf(1, 10)) << "future allocations should pretend realloc request never happened"; } TEST(Test_Linked_Bump_Allocator, non_last_allocation_cannot_grow) { Linked_Bump_Allocator<1> alloc("test"); - char* array = alloc.allocate_uninitialized_array(10); + Span array = alloc.allocate_uninitialized_span(10); [[maybe_unused]] char* last = alloc.new_object(); - bool ok = alloc.try_grow_array_in_place(array, 10, 20); + bool ok = alloc.try_grow_array_in_place(array.data(), 10, 20); EXPECT_FALSE(ok); - assert_valid_memory(array, array + 10, /*alignment=*/1); + assert_valid_memory(array.data(), array.data() + 10, /*alignment=*/1); - char* next = alloc.allocate_uninitialized_array(1); - EXPECT_NE(next, last) + Span next = alloc.allocate_uninitialized_span(1); + EXPECT_NE(next.data(), last) << "future allocations should not overlap resized array"; } diff --git a/tools/compile-translations.cpp b/tools/compile-translations.cpp index 21a80653c4..e34ec6d8b9 100644 --- a/tools/compile-translations.cpp +++ b/tools/compile-translations.cpp @@ -203,10 +203,10 @@ String8_View po_path_to_locale_name(const char* po_path) { String_Table::Entry::Entry(String8_View string, Monotonic_Allocator* allocator) : origin_file_paths("String_Table::Entry::file_paths", allocator) { - Char8* new_string = - allocator->allocate_uninitialized_array(string.size()); - Char8* new_string_end = std::copy(string.begin(), string.end(), new_string); - this->string = make_string_view(new_string, new_string_end); + Span new_string = + allocator->allocate_uninitialized_span(string.size()); + std::copy(string.begin(), string.end(), new_string.begin()); + this->string = make_string_view(new_string.begin(), new_string.end()); } void String_Table::add_string(String8_View string, From d0b8ceb8ff76cdca3871a050990e26aaf4990879 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sun, 29 Oct 2023 01:48:49 -0400 Subject: [PATCH 058/117] refactor(container): silence GCC 'final' warning GCC now reports the following warning: > linked-bump-allocator.h:39:7: error: Declaring type 'class quick_lint_js::Linked_Bump_Allocator<8>' final would enable devirtualization of 1 call [-Werror=suggest-final-types] Heed GCC's warning by marking the class final. --- src/quick-lint-js/container/linked-bump-allocator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quick-lint-js/container/linked-bump-allocator.h b/src/quick-lint-js/container/linked-bump-allocator.h index 30956ceae8..f905ad5d7f 100644 --- a/src/quick-lint-js/container/linked-bump-allocator.h +++ b/src/quick-lint-js/container/linked-bump-allocator.h @@ -36,7 +36,7 @@ namespace quick_lint_js { // // Internally, Linked_Bump_Allocator maintains a linked list of chunks. template -class Linked_Bump_Allocator : public Memory_Resource { +class Linked_Bump_Allocator final : public Memory_Resource { private: struct Chunk_Header; using Chunk = Flexible_Array; From 8e9f82650852f1b03938065cd1ecdcf2c6c85521 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sun, 29 Oct 2023 02:07:09 -0400 Subject: [PATCH 059/117] refactor(port): delete unused Memory_Resource::is_equal --- src/quick-lint-js/container/linked-bump-allocator.h | 4 ---- src/quick-lint-js/port/memory-resource.cpp | 4 ---- src/quick-lint-js/port/memory-resource.h | 5 ----- test/quick-lint-js/tracking-memory-resource.h | 5 ----- 4 files changed, 18 deletions(-) diff --git a/src/quick-lint-js/container/linked-bump-allocator.h b/src/quick-lint-js/container/linked-bump-allocator.h index f905ad5d7f..0f5fee1961 100644 --- a/src/quick-lint-js/container/linked-bump-allocator.h +++ b/src/quick-lint-js/container/linked-bump-allocator.h @@ -244,10 +244,6 @@ class Linked_Bump_Allocator final : public Memory_Resource { this->deallocate_bytes(p, bytes); } - bool do_is_equal(const Memory_Resource& other) const override { - return this == static_cast(&other); - } - private: struct alignas(maximum(alignment, alignof(void*))) Chunk_Header { explicit Chunk_Header(Chunk* previous) : previous(previous) {} diff --git a/src/quick-lint-js/port/memory-resource.cpp b/src/quick-lint-js/port/memory-resource.cpp index ab7af4fa32..726d017e95 100644 --- a/src/quick-lint-js/port/memory-resource.cpp +++ b/src/quick-lint-js/port/memory-resource.cpp @@ -29,10 +29,6 @@ class New_Delete_Resource_Impl : public Memory_Resource { ::operator delete(p); #endif } - - bool do_is_equal(const Memory_Resource& other) const override { - return this == static_cast(&other); - } }; } diff --git a/src/quick-lint-js/port/memory-resource.h b/src/quick-lint-js/port/memory-resource.h index 260709cc2d..5d0e28cbdf 100644 --- a/src/quick-lint-js/port/memory-resource.h +++ b/src/quick-lint-js/port/memory-resource.h @@ -19,15 +19,10 @@ class Memory_Resource { return this->do_deallocate(p, bytes, alignment); } - bool is_equal(const Memory_Resource& other) const { - return this->do_is_equal(other); - } - protected: virtual void* do_allocate(std::size_t bytes, std::size_t alignment) = 0; virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) = 0; - virtual bool do_is_equal(const Memory_Resource& other) const = 0; }; // Like std::pmr::new_delete_resource. diff --git a/test/quick-lint-js/tracking-memory-resource.h b/test/quick-lint-js/tracking-memory-resource.h index 34a95722af..be8ee51e7c 100644 --- a/test/quick-lint-js/tracking-memory-resource.h +++ b/test/quick-lint-js/tracking-memory-resource.h @@ -34,11 +34,6 @@ class Tracking_Memory_Resource : public Memory_Resource { } } - bool do_is_equal(const Memory_Resource&) const override { - QLJS_UNIMPLEMENTED(); - return false; - } - Memory_Resource* underlying_memory_ = new_delete_resource(); std::uint64_t allocated_bytes_ = 0; From 3c4d7d26302f349c3e3f51134c718317d1beb6b7 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Tue, 31 Oct 2023 16:50:06 -0400 Subject: [PATCH 060/117] refactor(util): add enum_to_int_cast and int_to_enum_cast Make static_cast-s involving enums less bug-prone. Add a specialization of write_integer because we were using 'int' instead of the correct underlying type ('unsigned char') in one place. --- src/CMakeLists.txt | 9 ++-- .../cli/emacs-lisp-diag-reporter.cpp | 3 +- src/quick-lint-js/cli/options.cpp | 3 +- src/quick-lint-js/cli/options.h | 15 +++--- src/quick-lint-js/fe/lex.cpp | 3 +- src/quick-lint-js/fe/parse-statement.cpp | 5 +- .../logging/trace-writer-generated.h | 3 +- src/quick-lint-js/util/enum-cast.h | 49 +++++++++++++++++++ src/quick-lint-js/util/integer.cpp | 2 + src/quick-lint-js/util/integer.h | 2 + tools/generate-trace-sources.cpp | 13 +++-- 11 files changed, 82 insertions(+), 25 deletions(-) create mode 100644 src/quick-lint-js/util/enum-cast.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 911b9e243b..f632a5f4dd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -202,15 +202,15 @@ quick_lint_js_add_library( quick-lint-js/container/padded-string.cpp quick-lint-js/container/padded-string.h quick-lint-js/container/string-view.h + quick-lint-js/container/vector-profiler.cpp + quick-lint-js/container/vector-profiler.h + quick-lint-js/container/vector.h + quick-lint-js/container/winkable.h quick-lint-js/fe/keyword-lexer.h quick-lint-js/fe/keyword-list.h quick-lint-js/i18n/po-parser.cpp quick-lint-js/i18n/po-parser.h quick-lint-js/i18n/translation-table-compiler.cpp - quick-lint-js/container/vector-profiler.cpp - quick-lint-js/container/vector-profiler.h - quick-lint-js/container/vector.h - quick-lint-js/container/winkable.h quick-lint-js/i18n/translation-table-compiler.h quick-lint-js/io/file-handle-posix.cpp quick-lint-js/io/file-handle-win32.cpp @@ -240,6 +240,7 @@ quick_lint_js_add_library( quick-lint-js/port/windows.h quick-lint-js/reflection/cxx-parser.cpp quick-lint-js/reflection/cxx-parser.h + quick-lint-js/util/enum-cast.h quick-lint-js/util/float.cpp quick-lint-js/util/float.h quick-lint-js/util/integer.cpp diff --git a/src/quick-lint-js/cli/emacs-lisp-diag-reporter.cpp b/src/quick-lint-js/cli/emacs-lisp-diag-reporter.cpp index d79a71a6b2..b272370d90 100644 --- a/src/quick-lint-js/cli/emacs-lisp-diag-reporter.cpp +++ b/src/quick-lint-js/cli/emacs-lisp-diag-reporter.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace quick_lint_js { Emacs_Lisp_Diag_Reporter::Emacs_Lisp_Diag_Reporter(Translator t, @@ -50,7 +51,7 @@ void Emacs_Lisp_Diag_Formatter::write_before_message( this->output_.append_literal(u8" . "_sv); this->output_.append_decimal_integer(end); this->output_.append_literal(u8") "_sv); - this->output_.append_decimal_integer(static_cast(sev)); + this->output_.append_decimal_integer(enum_to_int_cast(sev)); this->output_.append_literal(u8" \""_sv); this->output_.append_copy(to_string8_view(code)); this->output_.append_literal(u8"\" \""_sv); diff --git a/src/quick-lint-js/cli/options.cpp b/src/quick-lint-js/cli/options.cpp index 949184ed9b..8283993d71 100644 --- a/src/quick-lint-js/cli/options.cpp +++ b/src/quick-lint-js/cli/options.cpp @@ -332,7 +332,8 @@ Resolved_Input_File_Language get_language(const char* file, return Resolved_Input_File_Language::javascript_jsx; } } else { - return static_cast(language); + return int_to_enum_cast( + enum_to_int_cast(language)); } } } diff --git a/src/quick-lint-js/cli/options.h b/src/quick-lint-js/cli/options.h index 64d174341d..473ace3c80 100644 --- a/src/quick-lint-js/cli/options.h +++ b/src/quick-lint-js/cli/options.h @@ -7,6 +7,7 @@ #include #include #include +#include namespace quick_lint_js { class Output_Stream; @@ -33,14 +34,12 @@ enum class Raw_Input_File_Language : unsigned char { }; enum class Resolved_Input_File_Language : unsigned char { - javascript = static_cast(Raw_Input_File_Language::javascript), - javascript_jsx = - static_cast(Raw_Input_File_Language::javascript_jsx), - typescript = static_cast(Raw_Input_File_Language::typescript), - typescript_definition = static_cast( - Raw_Input_File_Language::typescript_definition), - typescript_jsx = - static_cast(Raw_Input_File_Language::typescript_jsx), + javascript = enum_to_int_cast(Raw_Input_File_Language::javascript), + javascript_jsx = enum_to_int_cast(Raw_Input_File_Language::javascript_jsx), + typescript = enum_to_int_cast(Raw_Input_File_Language::typescript), + typescript_definition = + enum_to_int_cast(Raw_Input_File_Language::typescript_definition), + typescript_jsx = enum_to_int_cast(Raw_Input_File_Language::typescript_jsx), }; enum class Option_When { auto_, always, never }; diff --git a/src/quick-lint-js/fe/lex.cpp b/src/quick-lint-js/fe/lex.cpp index f8ce38df7b..92d9d796d3 100644 --- a/src/quick-lint-js/fe/lex.cpp +++ b/src/quick-lint-js/fe/lex.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -245,7 +246,7 @@ bool Lexer::try_parse_current_token() { case '{': case '}': case '~': - this->last_token_.type = static_cast(*this->input_); + this->last_token_.type = int_to_enum_cast(*this->input_); this->input_ += 1; this->last_token_.end = this->input_; break; diff --git a/src/quick-lint-js/fe/parse-statement.cpp b/src/quick-lint-js/fe/parse-statement.cpp index f97a0b74f6..34aab8a602 100644 --- a/src/quick-lint-js/fe/parse-statement.cpp +++ b/src/quick-lint-js/fe/parse-statement.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include // For Parser::binding_element_info. @@ -5353,13 +5354,13 @@ void Parser::visit_binding_element(Expression *ast, Parse_Visitor_Base &v, this->visit_expression(rhs, v, Variable_Context::rhs); Variable_Declaration_Flags lhs_flags = - static_cast( + int_to_enum_cast( info.flags & Variable_Declaration_Flags::inside_for_loop_head); switch (info.declaration_kind) { case Variable_Kind::_const: case Variable_Kind::_let: case Variable_Kind::_var: - lhs_flags = static_cast( + lhs_flags = int_to_enum_cast( lhs_flags | Variable_Declaration_Flags::initialized_with_equals); break; default: diff --git a/src/quick-lint-js/logging/trace-writer-generated.h b/src/quick-lint-js/logging/trace-writer-generated.h index 3f0f19b178..e6c9f6dc31 100644 --- a/src/quick-lint-js/logging/trace-writer-generated.h +++ b/src/quick-lint-js/logging/trace-writer-generated.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -230,7 +231,7 @@ inline void Trace_Writer::write_event( inline void Trace_Writer::write_Trace_LSP_Document_State( const Trace_LSP_Document_State& s) { Binary_Writer w = Binary_Writer(reinterpret_cast(this->out_->append(1))); - w.u8(static_cast(s.type)); + w.u8(enum_to_int_cast(s.type)); /* Done with w. */ this->write_utf8_string(s.uri); this->write_utf8_string(s.text); diff --git a/src/quick-lint-js/util/enum-cast.h b/src/quick-lint-js/util/enum-cast.h new file mode 100644 index 0000000000..c57ad25923 --- /dev/null +++ b/src/quick-lint-js/util/enum-cast.h @@ -0,0 +1,49 @@ +// Copyright (C) 2020 Matthew "strager" Glazar +// See end of file for extended copyright information. + +#pragma once + +#include + +namespace quick_lint_js { +// Convert an integer to an enum. +// +// Example: +// +// enum class Color : unsigned char { red, green, blue }; +// unsigned char raw = 1; // green +// Color c = int_to_enum_cast(raw); // Color::green +template +constexpr Enum int_to_enum_cast(std::underlying_type_t value) { + return static_cast(value); +} + +// Convert an enum to its integer value. +// +// Example: +// +// enum class Color : unsigned char { red, green, blue }; +// unsigned char raw = enum_to_int_cast(Color::green); // 1 +template +constexpr std::underlying_type_t enum_to_int_cast(Enum value) { + return static_cast>(value); +} +} + +// quick-lint-js finds bugs in JavaScript programs. +// Copyright (C) 2020 Matthew "strager" Glazar +// +// This file is part of quick-lint-js. +// +// quick-lint-js is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// quick-lint-js is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with quick-lint-js. If not, see . diff --git a/src/quick-lint-js/util/integer.cpp b/src/quick-lint-js/util/integer.cpp index b2886dd8f3..a1545d076a 100644 --- a/src/quick-lint-js/util/integer.cpp +++ b/src/quick-lint-js/util/integer.cpp @@ -263,6 +263,7 @@ template Parse_Integer_Exact_Error parse_integer_exact_hex( String8_View, unsigned long long &value); #endif +template Char8 *write_integer(unsigned char, Char8 *out); template Char8 *write_integer(unsigned short, Char8 *out); template Char8 *write_integer(int, Char8 *out); template Char8 *write_integer(long, Char8 *out); @@ -273,6 +274,7 @@ template Char8 *write_integer(unsigned long long, Char8 *out); #if QLJS_HAVE_CHAR8_T +template char *write_integer(unsigned char, char *out); template char *write_integer(unsigned short, char *out); template char *write_integer(unsigned, char *out); #endif diff --git a/src/quick-lint-js/util/integer.h b/src/quick-lint-js/util/integer.h index 16099dca9c..d0bacc9b97 100644 --- a/src/quick-lint-js/util/integer.h +++ b/src/quick-lint-js/util/integer.h @@ -78,6 +78,7 @@ inline constexpr int integer_string_length = template Char8 *write_integer(T, Char8 *out); +extern template Char8 *write_integer(unsigned char, Char8 *out); extern template Char8 *write_integer(unsigned short, Char8 *out); extern template Char8 *write_integer(int, Char8 *out); @@ -92,6 +93,7 @@ extern template Char8 *write_integer(unsigned long long, template char *write_integer(T, char *out); +extern template char *write_integer(unsigned char, char *out); extern template char *write_integer(unsigned short, char *out); extern template char *write_integer(unsigned, char *out); #endif diff --git a/tools/generate-trace-sources.cpp b/tools/generate-trace-sources.cpp index 6156112f0d..210ecee84a 100644 --- a/tools/generate-trace-sources.cpp +++ b/tools/generate-trace-sources.cpp @@ -1408,6 +1408,7 @@ void write_writer_h(CXX_Trace_Types_Parser& types, Output_Stream& out) { #include #include #include +#include #include #include @@ -1563,13 +1564,13 @@ namespace quick_lint_js { } String8_View type = types.resolve_type_aliases_cxx(member.cxx_type); - bool need_cast = false; + bool need_enum_to_int_cast = false; if (const Parsed_Enum* e = types.find_enum_with_cxx_name(type)) { // NOTE[Trace_Writer-enum-code-gen]: Instead of creating a dedicated // function for writing each enum type, we write the enum as its // primitive type directly. This allows writing of the enum to be // batched into one append_bytes call with other integers. - need_cast = true; + need_enum_to_int_cast = true; type = e->underlying_cxx_type; } auto built_in_it = built_in_types.find(type); @@ -1605,13 +1606,11 @@ namespace quick_lint_js { code.append_literal(u8"w."_sv); code.append_copy(built_in_it->second.write_method); code.append_literal(u8"("_sv); - if (need_cast) { - code.append_literal(u8"static_cast("_sv); + if (need_enum_to_int_cast) { + code.append_literal(u8"enum_to_int_cast("_sv); } code.append_copy(var); - if (need_cast) { + if (need_enum_to_int_cast) { code.append_literal(u8")"_sv); } code.append_literal(u8");\n"_sv); From 1eb0af87425585e016a6b8a4510f44b451603aff Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Tue, 31 Oct 2023 16:50:30 -0400 Subject: [PATCH 061/117] refactor(util): combine narrow-cast.h and enum-cast.h into cast.h Group similar functions to a 'cast' module. --- benchmark/benchmark-cli-location.cpp | 2 +- benchmark/benchmark-configuration-loader.cpp | 2 +- benchmark/benchmark-lsp-document-text.cpp | 2 +- benchmark/benchmark-lsp-location.cpp | 2 +- benchmark/benchmark-lsp/lsp-benchmarks.cpp | 2 +- .../benchmark-lsp/lsp-server-process.cpp | 2 +- benchmark/benchmark-lsp/process.cpp | 2 +- benchmark/benchmark-vim-location.cpp | 2 +- benchmark/generate-code.cpp | 2 +- .../quick-lint-js/vscode/napi-support.h | 2 +- src/CMakeLists.txt | 3 +- src/quick-lint-js/cli/cli-location.cpp | 2 +- .../cli/emacs-lisp-diag-reporter.cpp | 2 +- src/quick-lint-js/cli/emacs-location.cpp | 2 +- src/quick-lint-js/cli/options.cpp | 2 +- src/quick-lint-js/cli/options.h | 2 +- src/quick-lint-js/cli/vim-location.cpp | 2 +- .../change-detecting-filesystem-inotify.cpp | 2 +- .../change-detecting-filesystem-kqueue.cpp | 2 +- .../change-detecting-filesystem-win32.cpp | 2 +- .../configuration/configuration.cpp | 2 +- .../container/async-byte-queue.cpp | 2 +- .../container/async-byte-queue.h | 2 +- src/quick-lint-js/container/byte-buffer.cpp | 2 +- src/quick-lint-js/container/byte-buffer.h | 2 +- .../container/linked-bump-allocator.h | 2 +- src/quick-lint-js/container/padded-string.cpp | 2 +- src/quick-lint-js/container/padded-string.h | 2 +- src/quick-lint-js/container/string-view.h | 2 +- .../container/vector-profiler.cpp | 2 +- src/quick-lint-js/container/vector-profiler.h | 2 +- src/quick-lint-js/container/vector.h | 2 +- src/quick-lint-js/debug/debug-server.cpp | 2 +- src/quick-lint-js/debug/find-debug-server.cpp | 2 +- .../diag/diagnostic-formatter.cpp | 2 +- src/quick-lint-js/diag/diagnostic-formatter.h | 2 +- src/quick-lint-js/diag/diagnostic.cpp | 2 +- src/quick-lint-js/fe/expression.h | 2 +- src/quick-lint-js/fe/identifier.h | 2 +- src/quick-lint-js/fe/lex.cpp | 3 +- src/quick-lint-js/fe/lex.h | 2 +- src/quick-lint-js/fe/parse-statement.cpp | 2 +- src/quick-lint-js/fe/source-code-span.h | 2 +- src/quick-lint-js/i18n/locale.cpp | 2 +- src/quick-lint-js/io/file-canonical.cpp | 2 +- src/quick-lint-js/io/file-handle-posix.cpp | 2 +- src/quick-lint-js/io/file-handle-win32.cpp | 2 +- src/quick-lint-js/io/file-path.cpp | 2 +- src/quick-lint-js/io/file.cpp | 2 +- src/quick-lint-js/io/output-stream.cpp | 2 +- src/quick-lint-js/io/output-stream.h | 2 +- src/quick-lint-js/io/pipe-writer.cpp | 2 +- src/quick-lint-js/logging/logger.cpp | 2 +- src/quick-lint-js/logging/trace-flusher.cpp | 2 +- src/quick-lint-js/logging/trace-reader.h | 2 +- .../logging/trace-writer-generated.h | 3 +- src/quick-lint-js/lsp/lsp-document-text.cpp | 2 +- src/quick-lint-js/lsp/lsp-location.cpp | 2 +- src/quick-lint-js/lsp/lsp-message-parser.cpp | 2 +- src/quick-lint-js/lsp/lsp-message-parser.h | 2 +- src/quick-lint-js/lsp/lsp-pipe-writer.cpp | 2 +- src/quick-lint-js/lsp/lsp-server.cpp | 2 +- src/quick-lint-js/lsp/lsp-server.h | 2 +- src/quick-lint-js/port/char8.cpp | 2 +- src/quick-lint-js/port/child-process.cpp | 2 +- src/quick-lint-js/port/process.cpp | 2 +- src/quick-lint-js/port/simd.h | 2 +- src/quick-lint-js/port/span.h | 2 +- src/quick-lint-js/port/thread.cpp | 2 +- src/quick-lint-js/port/windows-error.cpp | 2 +- src/quick-lint-js/util/binary-reader.h | 2 +- src/quick-lint-js/util/binary-writer.h | 2 +- .../util/{narrow-cast.h => cast.h} | 24 +++++++++ src/quick-lint-js/util/enum-cast.h | 49 ------------------- src/quick-lint-js/util/integer.cpp | 2 +- src/quick-lint-js/util/math-overflow.h | 2 +- src/quick-lint-js/util/utf-16.cpp | 2 +- src/quick-lint-js/util/utf-8.cpp | 2 +- src/quick-lint-js/web-demo-location.cpp | 2 +- test/quick-lint-js/diagnostic-assertion.cpp | 2 +- test/quick-lint-js/filesystem-test.cpp | 2 +- test/test-cli-location.cpp | 2 +- test/test-debug-server.cpp | 2 +- test/test-emacs-location.cpp | 2 +- test/test-json.cpp | 2 +- test/test-lex-unicode.cpp | 2 +- test/test-lex.cpp | 2 +- test/test-linked-vector.cpp | 2 +- test/test-locale.cpp | 2 +- test/test-lsp-location.cpp | 2 +- test/test-lsp-pipe-writer.cpp | 2 +- test/test-math-overflow.cpp | 2 +- test/test-narrow-cast.cpp | 2 +- test/test-options.cpp | 2 +- test/test-output-stream.cpp | 2 +- test/test-parse-conditional-expression.cpp | 2 +- test/test-parse-expression-jsx.cpp | 2 +- test/test-parse-expression-typescript.cpp | 2 +- test/test-parse-expression.cpp | 2 +- ...-parse-typescript-angle-type-assertion.cpp | 2 +- test/test-pipe-writer.cpp | 2 +- test/test-translation-table-compiler.cpp | 2 +- test/test-utf-16.cpp | 2 +- test/test-utf-8.cpp | 2 +- test/test-vim-location.cpp | 2 +- test/test-web-demo-location.cpp | 2 +- tools/analyze-trace.cpp | 2 +- tools/generate-lex-keyword.cpp | 2 +- tools/generate-trace-sources.cpp | 4 +- 109 files changed, 132 insertions(+), 160 deletions(-) rename src/quick-lint-js/util/{narrow-cast.h => cast.h} (71%) delete mode 100644 src/quick-lint-js/util/enum-cast.h diff --git a/benchmark/benchmark-cli-location.cpp b/benchmark/benchmark-cli-location.cpp index a3c15c9a97..bbe96449f1 100644 --- a/benchmark/benchmark-cli-location.cpp +++ b/benchmark/benchmark-cli-location.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include namespace quick_lint_js { namespace { diff --git a/benchmark/benchmark-configuration-loader.cpp b/benchmark/benchmark-configuration-loader.cpp index b75a444325..cb7a028613 100644 --- a/benchmark/benchmark-configuration-loader.cpp +++ b/benchmark/benchmark-configuration-loader.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include namespace quick_lint_js { diff --git a/benchmark/benchmark-lsp-document-text.cpp b/benchmark/benchmark-lsp-document-text.cpp index 244d4c9011..4ffdc8c683 100644 --- a/benchmark/benchmark-lsp-document-text.cpp +++ b/benchmark/benchmark-lsp-document-text.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include diff --git a/benchmark/benchmark-lsp-location.cpp b/benchmark/benchmark-lsp-location.cpp index c4389abde9..b4f06fc04d 100644 --- a/benchmark/benchmark-lsp-location.cpp +++ b/benchmark/benchmark-lsp-location.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include namespace quick_lint_js { namespace { diff --git a/benchmark/benchmark-lsp/lsp-benchmarks.cpp b/benchmark/benchmark-lsp/lsp-benchmarks.cpp index 7335d2306f..4757a1e085 100644 --- a/benchmark/benchmark-lsp/lsp-benchmarks.cpp +++ b/benchmark/benchmark-lsp/lsp-benchmarks.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/benchmark/benchmark-lsp/lsp-server-process.cpp b/benchmark/benchmark-lsp/lsp-server-process.cpp index 250c86d0a1..4b0b2c59d7 100644 --- a/benchmark/benchmark-lsp/lsp-server-process.cpp +++ b/benchmark/benchmark-lsp/lsp-server-process.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/benchmark/benchmark-lsp/process.cpp b/benchmark/benchmark-lsp/process.cpp index e89a4b06a7..a9cf62635d 100644 --- a/benchmark/benchmark-lsp/process.cpp +++ b/benchmark/benchmark-lsp/process.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include diff --git a/benchmark/benchmark-vim-location.cpp b/benchmark/benchmark-vim-location.cpp index 2ea1143e12..7884933bd0 100644 --- a/benchmark/benchmark-vim-location.cpp +++ b/benchmark/benchmark-vim-location.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include namespace quick_lint_js { namespace { diff --git a/benchmark/generate-code.cpp b/benchmark/generate-code.cpp index 28dfc3dd11..c62e06b152 100644 --- a/benchmark/generate-code.cpp +++ b/benchmark/generate-code.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/plugin/vscode/quick-lint-js/vscode/napi-support.h b/plugin/vscode/quick-lint-js/vscode/napi-support.h index af8da3ef58..4613069d2d 100644 --- a/plugin/vscode/quick-lint-js/vscode/napi-support.h +++ b/plugin/vscode/quick-lint-js/vscode/napi-support.h @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f632a5f4dd..3f7c793819 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -240,12 +240,11 @@ quick_lint_js_add_library( quick-lint-js/port/windows.h quick-lint-js/reflection/cxx-parser.cpp quick-lint-js/reflection/cxx-parser.h - quick-lint-js/util/enum-cast.h + quick-lint-js/util/cast.h quick-lint-js/util/float.cpp quick-lint-js/util/float.h quick-lint-js/util/integer.cpp quick-lint-js/util/integer.h - quick-lint-js/util/narrow-cast.h quick-lint-js/util/utf-16.cpp quick-lint-js/util/utf-16.h quick-lint-js/util/utf-8.cpp diff --git a/src/quick-lint-js/cli/cli-location.cpp b/src/quick-lint-js/cli/cli-location.cpp index 8172151086..9cbce18ed5 100644 --- a/src/quick-lint-js/cli/cli-location.cpp +++ b/src/quick-lint-js/cli/cli-location.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include namespace quick_lint_js { CLI_Source_Position CLI_Source_Range::begin() const { return this->begin_; } diff --git a/src/quick-lint-js/cli/emacs-lisp-diag-reporter.cpp b/src/quick-lint-js/cli/emacs-lisp-diag-reporter.cpp index b272370d90..a607d9a955 100644 --- a/src/quick-lint-js/cli/emacs-lisp-diag-reporter.cpp +++ b/src/quick-lint-js/cli/emacs-lisp-diag-reporter.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include namespace quick_lint_js { Emacs_Lisp_Diag_Reporter::Emacs_Lisp_Diag_Reporter(Translator t, diff --git a/src/quick-lint-js/cli/emacs-location.cpp b/src/quick-lint-js/cli/emacs-location.cpp index 548edcac14..0b796e7219 100644 --- a/src/quick-lint-js/cli/emacs-location.cpp +++ b/src/quick-lint-js/cli/emacs-location.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include namespace quick_lint_js { diff --git a/src/quick-lint-js/cli/options.cpp b/src/quick-lint-js/cli/options.cpp index 8283993d71..605f0dbc04 100644 --- a/src/quick-lint-js/cli/options.cpp +++ b/src/quick-lint-js/cli/options.cpp @@ -12,9 +12,9 @@ #include #include #include +#include #include #include -#include #include #include diff --git a/src/quick-lint-js/cli/options.h b/src/quick-lint-js/cli/options.h index 473ace3c80..199df777b4 100644 --- a/src/quick-lint-js/cli/options.h +++ b/src/quick-lint-js/cli/options.h @@ -7,7 +7,7 @@ #include #include #include -#include +#include namespace quick_lint_js { class Output_Stream; diff --git a/src/quick-lint-js/cli/vim-location.cpp b/src/quick-lint-js/cli/vim-location.cpp index 1b02696f97..2b6fa01ea3 100644 --- a/src/quick-lint-js/cli/vim-location.cpp +++ b/src/quick-lint-js/cli/vim-location.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include namespace quick_lint_js { Vim_Locator::Vim_Locator(Padded_String_View input) : input_(input) {} diff --git a/src/quick-lint-js/configuration/change-detecting-filesystem-inotify.cpp b/src/quick-lint-js/configuration/change-detecting-filesystem-inotify.cpp index da60cc9e10..8335efd31f 100644 --- a/src/quick-lint-js/configuration/change-detecting-filesystem-inotify.cpp +++ b/src/quick-lint-js/configuration/change-detecting-filesystem-inotify.cpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/quick-lint-js/configuration/change-detecting-filesystem-kqueue.cpp b/src/quick-lint-js/configuration/change-detecting-filesystem-kqueue.cpp index f2afb1d20f..bdfccc6f98 100644 --- a/src/quick-lint-js/configuration/change-detecting-filesystem-kqueue.cpp +++ b/src/quick-lint-js/configuration/change-detecting-filesystem-kqueue.cpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/quick-lint-js/configuration/change-detecting-filesystem-win32.cpp b/src/quick-lint-js/configuration/change-detecting-filesystem-win32.cpp index 7ee1bf7427..98a54b680c 100644 --- a/src/quick-lint-js/configuration/change-detecting-filesystem-win32.cpp +++ b/src/quick-lint-js/configuration/change-detecting-filesystem-win32.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/quick-lint-js/configuration/configuration.cpp b/src/quick-lint-js/configuration/configuration.cpp index 83cfcaf99b..6f3422b87f 100644 --- a/src/quick-lint-js/configuration/configuration.cpp +++ b/src/quick-lint-js/configuration/configuration.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/quick-lint-js/container/async-byte-queue.cpp b/src/quick-lint-js/container/async-byte-queue.cpp index 676ca0d388..770066d3fd 100644 --- a/src/quick-lint-js/container/async-byte-queue.cpp +++ b/src/quick-lint-js/container/async-byte-queue.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/quick-lint-js/container/async-byte-queue.h b/src/quick-lint-js/container/async-byte-queue.h index c3bf819d4a..b8550b779d 100644 --- a/src/quick-lint-js/container/async-byte-queue.h +++ b/src/quick-lint-js/container/async-byte-queue.h @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include namespace quick_lint_js { diff --git a/src/quick-lint-js/container/byte-buffer.cpp b/src/quick-lint-js/container/byte-buffer.cpp index fb1a82f95a..96e5fbfc37 100644 --- a/src/quick-lint-js/container/byte-buffer.cpp +++ b/src/quick-lint-js/container/byte-buffer.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/quick-lint-js/container/byte-buffer.h b/src/quick-lint-js/container/byte-buffer.h index 891a84df40..0b3b98c440 100644 --- a/src/quick-lint-js/container/byte-buffer.h +++ b/src/quick-lint-js/container/byte-buffer.h @@ -8,8 +8,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/quick-lint-js/container/linked-bump-allocator.h b/src/quick-lint-js/container/linked-bump-allocator.h index 0f5fee1961..c649c95e38 100644 --- a/src/quick-lint-js/container/linked-bump-allocator.h +++ b/src/quick-lint-js/container/linked-bump-allocator.h @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/quick-lint-js/container/padded-string.cpp b/src/quick-lint-js/container/padded-string.cpp index f57e1da4ad..5a38356e4e 100644 --- a/src/quick-lint-js/container/padded-string.cpp +++ b/src/quick-lint-js/container/padded-string.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/quick-lint-js/container/padded-string.h b/src/quick-lint-js/container/padded-string.h index 878cea8721..0823e2771e 100644 --- a/src/quick-lint-js/container/padded-string.h +++ b/src/quick-lint-js/container/padded-string.h @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include namespace quick_lint_js { diff --git a/src/quick-lint-js/container/string-view.h b/src/quick-lint-js/container/string-view.h index 12e58c0fe4..535d2325a0 100644 --- a/src/quick-lint-js/container/string-view.h +++ b/src/quick-lint-js/container/string-view.h @@ -4,7 +4,7 @@ #pragma once #include -#include +#include #include namespace quick_lint_js { diff --git a/src/quick-lint-js/container/vector-profiler.cpp b/src/quick-lint-js/container/vector-profiler.cpp index 40bfc1b729..72bfff3c4f 100644 --- a/src/quick-lint-js/container/vector-profiler.cpp +++ b/src/quick-lint-js/container/vector-profiler.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include QLJS_WARNING_IGNORE_MSVC(4996) // Function or variable may be unsafe. diff --git a/src/quick-lint-js/container/vector-profiler.h b/src/quick-lint-js/container/vector-profiler.h index a84bdf78b6..4703250044 100644 --- a/src/quick-lint-js/container/vector-profiler.h +++ b/src/quick-lint-js/container/vector-profiler.h @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/quick-lint-js/container/vector.h b/src/quick-lint-js/container/vector.h index 45e1930a84..dfa0a301f1 100644 --- a/src/quick-lint-js/container/vector.h +++ b/src/quick-lint-js/container/vector.h @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/quick-lint-js/debug/debug-server.cpp b/src/quick-lint-js/debug/debug-server.cpp index f03c670cf0..2f6078cf81 100644 --- a/src/quick-lint-js/debug/debug-server.cpp +++ b/src/quick-lint-js/debug/debug-server.cpp @@ -27,8 +27,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/src/quick-lint-js/debug/find-debug-server.cpp b/src/quick-lint-js/debug/find-debug-server.cpp index 6397632143..3384906c36 100644 --- a/src/quick-lint-js/debug/find-debug-server.cpp +++ b/src/quick-lint-js/debug/find-debug-server.cpp @@ -19,8 +19,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/quick-lint-js/diag/diagnostic-formatter.cpp b/src/quick-lint-js/diag/diagnostic-formatter.cpp index bb36031ef7..faeb4fb49f 100644 --- a/src/quick-lint-js/diag/diagnostic-formatter.cpp +++ b/src/quick-lint-js/diag/diagnostic-formatter.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/quick-lint-js/diag/diagnostic-formatter.h b/src/quick-lint-js/diag/diagnostic-formatter.h index 44c94366a6..6ceadbf142 100644 --- a/src/quick-lint-js/diag/diagnostic-formatter.h +++ b/src/quick-lint-js/diag/diagnostic-formatter.h @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/quick-lint-js/diag/diagnostic.cpp b/src/quick-lint-js/diag/diagnostic.cpp index edf50696c9..9790d4d762 100644 --- a/src/quick-lint-js/diag/diagnostic.cpp +++ b/src/quick-lint-js/diag/diagnostic.cpp @@ -10,8 +10,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/quick-lint-js/fe/expression.h b/src/quick-lint-js/fe/expression.h index b9f9fd3841..16c1a6bdad 100644 --- a/src/quick-lint-js/fe/expression.h +++ b/src/quick-lint-js/fe/expression.h @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/quick-lint-js/fe/identifier.h b/src/quick-lint-js/fe/identifier.h index 816e353047..b417219367 100644 --- a/src/quick-lint-js/fe/identifier.h +++ b/src/quick-lint-js/fe/identifier.h @@ -7,7 +7,7 @@ #include #include #include -#include +#include namespace quick_lint_js { class Identifier { diff --git a/src/quick-lint-js/fe/lex.cpp b/src/quick-lint-js/fe/lex.cpp index 92d9d796d3..fb62369534 100644 --- a/src/quick-lint-js/fe/lex.cpp +++ b/src/quick-lint-js/fe/lex.cpp @@ -22,9 +22,8 @@ #include #include #include -#include +#include #include -#include #include #include #include diff --git a/src/quick-lint-js/fe/lex.h b/src/quick-lint-js/fe/lex.h index 864c055f3a..d641ae8b9d 100644 --- a/src/quick-lint-js/fe/lex.h +++ b/src/quick-lint-js/fe/lex.h @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/quick-lint-js/fe/parse-statement.cpp b/src/quick-lint-js/fe/parse-statement.cpp index 34aab8a602..6acef62def 100644 --- a/src/quick-lint-js/fe/parse-statement.cpp +++ b/src/quick-lint-js/fe/parse-statement.cpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include // For Parser::binding_element_info. diff --git a/src/quick-lint-js/fe/source-code-span.h b/src/quick-lint-js/fe/source-code-span.h index 295ff26913..a27d26e304 100644 --- a/src/quick-lint-js/fe/source-code-span.h +++ b/src/quick-lint-js/fe/source-code-span.h @@ -6,7 +6,7 @@ #include #include #include -#include +#include namespace quick_lint_js { class Source_Code_Span { diff --git a/src/quick-lint-js/i18n/locale.cpp b/src/quick-lint-js/i18n/locale.cpp index a34d2f1419..d02ca9fe73 100644 --- a/src/quick-lint-js/i18n/locale.cpp +++ b/src/quick-lint-js/i18n/locale.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/quick-lint-js/io/file-canonical.cpp b/src/quick-lint-js/io/file-canonical.cpp index 4d000147eb..b93fb32e80 100644 --- a/src/quick-lint-js/io/file-canonical.cpp +++ b/src/quick-lint-js/io/file-canonical.cpp @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/quick-lint-js/io/file-handle-posix.cpp b/src/quick-lint-js/io/file-handle-posix.cpp index 3180cdb96a..b90e2a9887 100644 --- a/src/quick-lint-js/io/file-handle-posix.cpp +++ b/src/quick-lint-js/io/file-handle-posix.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/quick-lint-js/io/file-handle-win32.cpp b/src/quick-lint-js/io/file-handle-win32.cpp index 76c67fa083..4a498ae78e 100644 --- a/src/quick-lint-js/io/file-handle-win32.cpp +++ b/src/quick-lint-js/io/file-handle-win32.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/quick-lint-js/io/file-path.cpp b/src/quick-lint-js/io/file-path.cpp index c255f7406b..0340799cda 100644 --- a/src/quick-lint-js/io/file-path.cpp +++ b/src/quick-lint-js/io/file-path.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #if QLJS_HAVE_WINDOWS_H diff --git a/src/quick-lint-js/io/file.cpp b/src/quick-lint-js/io/file.cpp index 1d4c3a1d67..0434ce06d4 100644 --- a/src/quick-lint-js/io/file.cpp +++ b/src/quick-lint-js/io/file.cpp @@ -16,8 +16,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/src/quick-lint-js/io/output-stream.cpp b/src/quick-lint-js/io/output-stream.cpp index 341c6aa764..8596b95b00 100644 --- a/src/quick-lint-js/io/output-stream.cpp +++ b/src/quick-lint-js/io/output-stream.cpp @@ -14,8 +14,8 @@ #include #include #include +#include #include -#include namespace quick_lint_js { namespace { diff --git a/src/quick-lint-js/io/output-stream.h b/src/quick-lint-js/io/output-stream.h index 480ed7e2c1..2e6ef34fc1 100644 --- a/src/quick-lint-js/io/output-stream.h +++ b/src/quick-lint-js/io/output-stream.h @@ -10,8 +10,8 @@ #include #include #include +#include #include -#include namespace quick_lint_js { // Output_Stream is similar to std::basic_ostream. diff --git a/src/quick-lint-js/io/pipe-writer.cpp b/src/quick-lint-js/io/pipe-writer.cpp index 3fd25a75ee..79eb2fbd43 100644 --- a/src/quick-lint-js/io/pipe-writer.cpp +++ b/src/quick-lint-js/io/pipe-writer.cpp @@ -17,8 +17,8 @@ #include #include #include +#include #include -#include #if QLJS_HAVE_WRITEV #include diff --git a/src/quick-lint-js/logging/logger.cpp b/src/quick-lint-js/logging/logger.cpp index e6399f1c4e..8823c92197 100644 --- a/src/quick-lint-js/logging/logger.cpp +++ b/src/quick-lint-js/logging/logger.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/quick-lint-js/logging/trace-flusher.cpp b/src/quick-lint-js/logging/trace-flusher.cpp index b72a261b31..02729e6b59 100644 --- a/src/quick-lint-js/logging/trace-flusher.cpp +++ b/src/quick-lint-js/logging/trace-flusher.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/quick-lint-js/logging/trace-reader.h b/src/quick-lint-js/logging/trace-reader.h index a650cc6961..a83fe60c3e 100644 --- a/src/quick-lint-js/logging/trace-reader.h +++ b/src/quick-lint-js/logging/trace-reader.h @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/quick-lint-js/logging/trace-writer-generated.h b/src/quick-lint-js/logging/trace-writer-generated.h index e6c9f6dc31..f19e2b631e 100644 --- a/src/quick-lint-js/logging/trace-writer-generated.h +++ b/src/quick-lint-js/logging/trace-writer-generated.h @@ -11,8 +11,7 @@ #include #include #include -#include -#include +#include #include // clang-format off diff --git a/src/quick-lint-js/lsp/lsp-document-text.cpp b/src/quick-lint-js/lsp/lsp-document-text.cpp index fa16e3d4cf..1621463890 100644 --- a/src/quick-lint-js/lsp/lsp-document-text.cpp +++ b/src/quick-lint-js/lsp/lsp-document-text.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include QLJS_WARNING_IGNORE_GCC("-Wsuggest-attribute=noreturn") diff --git a/src/quick-lint-js/lsp/lsp-location.cpp b/src/quick-lint-js/lsp/lsp-location.cpp index 33e97f1ab1..605230426c 100644 --- a/src/quick-lint-js/lsp/lsp-location.cpp +++ b/src/quick-lint-js/lsp/lsp-location.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include namespace quick_lint_js { diff --git a/src/quick-lint-js/lsp/lsp-message-parser.cpp b/src/quick-lint-js/lsp/lsp-message-parser.cpp index df4bf68d38..49b67f4ea7 100644 --- a/src/quick-lint-js/lsp/lsp-message-parser.cpp +++ b/src/quick-lint-js/lsp/lsp-message-parser.cpp @@ -11,8 +11,8 @@ #include #include #include +#include #include -#include #include QLJS_WARNING_IGNORE_GCC("-Wuseless-cast") diff --git a/src/quick-lint-js/lsp/lsp-message-parser.h b/src/quick-lint-js/lsp/lsp-message-parser.h index 4a31dedd32..3a99302a8a 100644 --- a/src/quick-lint-js/lsp/lsp-message-parser.h +++ b/src/quick-lint-js/lsp/lsp-message-parser.h @@ -11,8 +11,8 @@ #include #include #include +#include #include -#include #include namespace quick_lint_js { diff --git a/src/quick-lint-js/lsp/lsp-pipe-writer.cpp b/src/quick-lint-js/lsp/lsp-pipe-writer.cpp index c1e31c2ef8..cce63c4081 100644 --- a/src/quick-lint-js/lsp/lsp-pipe-writer.cpp +++ b/src/quick-lint-js/lsp/lsp-pipe-writer.cpp @@ -9,8 +9,8 @@ #include #include #include +#include #include -#include namespace quick_lint_js { namespace { diff --git a/src/quick-lint-js/lsp/lsp-server.cpp b/src/quick-lint-js/lsp/lsp-server.cpp index 62e08d948f..bb61bdc40e 100644 --- a/src/quick-lint-js/lsp/lsp-server.cpp +++ b/src/quick-lint-js/lsp/lsp-server.cpp @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/quick-lint-js/lsp/lsp-server.h b/src/quick-lint-js/lsp/lsp-server.h index bfeb36b14f..5273c82b1d 100644 --- a/src/quick-lint-js/lsp/lsp-server.h +++ b/src/quick-lint-js/lsp/lsp-server.h @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/quick-lint-js/port/char8.cpp b/src/quick-lint-js/port/char8.cpp index 6aa803dc54..1265429bb5 100644 --- a/src/quick-lint-js/port/char8.cpp +++ b/src/quick-lint-js/port/char8.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include QLJS_WARNING_IGNORE_GCC("-Wuseless-cast") diff --git a/src/quick-lint-js/port/child-process.cpp b/src/quick-lint-js/port/child-process.cpp index bb5bdd5d1c..dbb97d9218 100644 --- a/src/quick-lint-js/port/child-process.cpp +++ b/src/quick-lint-js/port/child-process.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/quick-lint-js/port/process.cpp b/src/quick-lint-js/port/process.cpp index 72754f9dc8..74c308c5d3 100644 --- a/src/quick-lint-js/port/process.cpp +++ b/src/quick-lint-js/port/process.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #if QLJS_HAVE_UNISTD_H #include diff --git a/src/quick-lint-js/port/simd.h b/src/quick-lint-js/port/simd.h index 490322dfd6..ea6dae19fe 100644 --- a/src/quick-lint-js/port/simd.h +++ b/src/quick-lint-js/port/simd.h @@ -10,7 +10,7 @@ #include #include #include -#include +#include #if QLJS_HAVE_ARM_NEON #include diff --git a/src/quick-lint-js/port/span.h b/src/quick-lint-js/port/span.h index 4db0b2f752..2000b5bef9 100644 --- a/src/quick-lint-js/port/span.h +++ b/src/quick-lint-js/port/span.h @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include namespace quick_lint_js { diff --git a/src/quick-lint-js/port/thread.cpp b/src/quick-lint-js/port/thread.cpp index bb1b6638d0..966d39f98d 100644 --- a/src/quick-lint-js/port/thread.cpp +++ b/src/quick-lint-js/port/thread.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #if defined(QLJS_THREADS_WINDOWS) diff --git a/src/quick-lint-js/port/windows-error.cpp b/src/quick-lint-js/port/windows-error.cpp index 3e324efe8c..39284367e5 100644 --- a/src/quick-lint-js/port/windows-error.cpp +++ b/src/quick-lint-js/port/windows-error.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include namespace quick_lint_js { diff --git a/src/quick-lint-js/util/binary-reader.h b/src/quick-lint-js/util/binary-reader.h index a94c94bd3c..3106ed4c86 100644 --- a/src/quick-lint-js/util/binary-reader.h +++ b/src/quick-lint-js/util/binary-reader.h @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include namespace quick_lint_js { diff --git a/src/quick-lint-js/util/binary-writer.h b/src/quick-lint-js/util/binary-writer.h index c8b5c6f865..a9cf5795d2 100644 --- a/src/quick-lint-js/util/binary-writer.h +++ b/src/quick-lint-js/util/binary-writer.h @@ -5,7 +5,7 @@ #include #include -#include +#include namespace quick_lint_js { // Binary_Writer does no bounds checking. diff --git a/src/quick-lint-js/util/narrow-cast.h b/src/quick-lint-js/util/cast.h similarity index 71% rename from src/quick-lint-js/util/narrow-cast.h rename to src/quick-lint-js/util/cast.h index f739ef82ce..66ce118c30 100644 --- a/src/quick-lint-js/util/narrow-cast.h +++ b/src/quick-lint-js/util/cast.h @@ -7,6 +7,7 @@ #include #include #include +#include namespace quick_lint_js { template @@ -31,6 +32,29 @@ Out narrow_cast(In x #endif return static_cast(x); } + +// Convert an integer to an enum. +// +// Example: +// +// enum class Color : unsigned char { red, green, blue }; +// unsigned char raw = 1; // green +// Color c = int_to_enum_cast(raw); // Color::green +template +constexpr Enum int_to_enum_cast(std::underlying_type_t value) { + return static_cast(value); +} + +// Convert an enum to its integer value. +// +// Example: +// +// enum class Color : unsigned char { red, green, blue }; +// unsigned char raw = enum_to_int_cast(Color::green); // 1 +template +constexpr std::underlying_type_t enum_to_int_cast(Enum value) { + return static_cast>(value); +} } // quick-lint-js finds bugs in JavaScript programs. diff --git a/src/quick-lint-js/util/enum-cast.h b/src/quick-lint-js/util/enum-cast.h deleted file mode 100644 index c57ad25923..0000000000 --- a/src/quick-lint-js/util/enum-cast.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (C) 2020 Matthew "strager" Glazar -// See end of file for extended copyright information. - -#pragma once - -#include - -namespace quick_lint_js { -// Convert an integer to an enum. -// -// Example: -// -// enum class Color : unsigned char { red, green, blue }; -// unsigned char raw = 1; // green -// Color c = int_to_enum_cast(raw); // Color::green -template -constexpr Enum int_to_enum_cast(std::underlying_type_t value) { - return static_cast(value); -} - -// Convert an enum to its integer value. -// -// Example: -// -// enum class Color : unsigned char { red, green, blue }; -// unsigned char raw = enum_to_int_cast(Color::green); // 1 -template -constexpr std::underlying_type_t enum_to_int_cast(Enum value) { - return static_cast>(value); -} -} - -// quick-lint-js finds bugs in JavaScript programs. -// Copyright (C) 2020 Matthew "strager" Glazar -// -// This file is part of quick-lint-js. -// -// quick-lint-js is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// quick-lint-js is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with quick-lint-js. If not, see . diff --git a/src/quick-lint-js/util/integer.cpp b/src/quick-lint-js/util/integer.cpp index a1545d076a..a136d9dfc2 100644 --- a/src/quick-lint-js/util/integer.cpp +++ b/src/quick-lint-js/util/integer.cpp @@ -15,9 +15,9 @@ #include #include #include +#include #include #include -#include #include #include diff --git a/src/quick-lint-js/util/math-overflow.h b/src/quick-lint-js/util/math-overflow.h index 9b46184821..7f36660af5 100644 --- a/src/quick-lint-js/util/math-overflow.h +++ b/src/quick-lint-js/util/math-overflow.h @@ -5,7 +5,7 @@ #include #include -#include +#include namespace quick_lint_js { template diff --git a/src/quick-lint-js/util/utf-16.cpp b/src/quick-lint-js/util/utf-16.cpp index 72ae900280..efba409e40 100644 --- a/src/quick-lint-js/util/utf-16.cpp +++ b/src/quick-lint-js/util/utf-16.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/quick-lint-js/util/utf-8.cpp b/src/quick-lint-js/util/utf-8.cpp index 6a33566b57..cc6e7355b7 100644 --- a/src/quick-lint-js/util/utf-8.cpp +++ b/src/quick-lint-js/util/utf-8.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include namespace quick_lint_js { diff --git a/src/quick-lint-js/web-demo-location.cpp b/src/quick-lint-js/web-demo-location.cpp index 7bebe29305..80e92b4fe6 100644 --- a/src/quick-lint-js/web-demo-location.cpp +++ b/src/quick-lint-js/web-demo-location.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/test/quick-lint-js/diagnostic-assertion.cpp b/test/quick-lint-js/diagnostic-assertion.cpp index 6a5e8b40ac..939a5524aa 100644 --- a/test/quick-lint-js/diagnostic-assertion.cpp +++ b/test/quick-lint-js/diagnostic-assertion.cpp @@ -15,8 +15,8 @@ #include #include #include +#include #include -#include #include using namespace std::literals::string_view_literals; diff --git a/test/quick-lint-js/filesystem-test.cpp b/test/quick-lint-js/filesystem-test.cpp index 84355a55a6..064c0f13b0 100644 --- a/test/quick-lint-js/filesystem-test.cpp +++ b/test/quick-lint-js/filesystem-test.cpp @@ -15,8 +15,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/test/test-cli-location.cpp b/test/test-cli-location.cpp index bd10a33978..12a6e3e1b1 100644 --- a/test/test-cli-location.cpp +++ b/test/test-cli-location.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include namespace quick_lint_js { diff --git a/test/test-debug-server.cpp b/test/test-debug-server.cpp index c069352f49..c578924528 100644 --- a/test/test-debug-server.cpp +++ b/test/test-debug-server.cpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/test/test-emacs-location.cpp b/test/test-emacs-location.cpp index b355149928..112c55ad1f 100644 --- a/test/test-emacs-location.cpp +++ b/test/test-emacs-location.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include namespace quick_lint_js { diff --git a/test/test-json.cpp b/test/test-json.cpp index 4237ccade0..dead6ce4e9 100644 --- a/test/test-json.cpp +++ b/test/test-json.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include namespace quick_lint_js { diff --git a/test/test-lex-unicode.cpp b/test/test-lex-unicode.cpp index 23e6fff98f..76d68f3752 100644 --- a/test/test-lex-unicode.cpp +++ b/test/test-lex-unicode.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/test/test-lex.cpp b/test/test-lex.cpp index 842a6d67ce..707659ac89 100644 --- a/test/test-lex.cpp +++ b/test/test-lex.cpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/test/test-linked-vector.cpp b/test/test-linked-vector.cpp index f692159f96..cc830eede3 100644 --- a/test/test-linked-vector.cpp +++ b/test/test-linked-vector.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include diff --git a/test/test-locale.cpp b/test/test-locale.cpp index 9f94283ef6..3130d1bbd5 100644 --- a/test/test-locale.cpp +++ b/test/test-locale.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include using ::testing::ElementsAreArray; using namespace std::literals::string_view_literals; diff --git a/test/test-lsp-location.cpp b/test/test-lsp-location.cpp index 4af2d3fe3a..f76fbe6f05 100644 --- a/test/test-lsp-location.cpp +++ b/test/test-lsp-location.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include namespace quick_lint_js { diff --git a/test/test-lsp-pipe-writer.cpp b/test/test-lsp-pipe-writer.cpp index 2e6ab80a35..a1a9b47860 100644 --- a/test/test-lsp-pipe-writer.cpp +++ b/test/test-lsp-pipe-writer.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #if QLJS_HAVE_FCNTL_H diff --git a/test/test-math-overflow.cpp b/test/test-math-overflow.cpp index efc1ba9b5a..4ceaa2ef39 100644 --- a/test/test-math-overflow.cpp +++ b/test/test-math-overflow.cpp @@ -4,8 +4,8 @@ #include #include #include +#include #include -#include namespace quick_lint_js { namespace { diff --git a/test/test-narrow-cast.cpp b/test/test-narrow-cast.cpp index 095844d623..0a50dab434 100644 --- a/test/test-narrow-cast.cpp +++ b/test/test-narrow-cast.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include namespace quick_lint_js { namespace { diff --git a/test/test-options.cpp b/test/test-options.cpp index 159659c801..68d7f9c4fc 100644 --- a/test/test-options.cpp +++ b/test/test-options.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include diff --git a/test/test-output-stream.cpp b/test/test-output-stream.cpp index 72a6ddffa1..2fd039cae0 100644 --- a/test/test-output-stream.cpp +++ b/test/test-output-stream.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #if QLJS_HAVE_FCNTL_H diff --git a/test/test-parse-conditional-expression.cpp b/test/test-parse-conditional-expression.cpp index 82db65d125..c1dae61404 100644 --- a/test/test-parse-conditional-expression.cpp +++ b/test/test-parse-conditional-expression.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/test/test-parse-expression-jsx.cpp b/test/test-parse-expression-jsx.cpp index 56aaef01d5..5b1e2f99cd 100644 --- a/test/test-parse-expression-jsx.cpp +++ b/test/test-parse-expression-jsx.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/test/test-parse-expression-typescript.cpp b/test/test-parse-expression-typescript.cpp index 16bb395454..eee5d80b79 100644 --- a/test/test-parse-expression-typescript.cpp +++ b/test/test-parse-expression-typescript.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include diff --git a/test/test-parse-expression.cpp b/test/test-parse-expression.cpp index 2b31aa5e7d..566869b72d 100644 --- a/test/test-parse-expression.cpp +++ b/test/test-parse-expression.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/test/test-parse-typescript-angle-type-assertion.cpp b/test/test-parse-typescript-angle-type-assertion.cpp index 27d18e488a..5f5ee1220b 100644 --- a/test/test-parse-typescript-angle-type-assertion.cpp +++ b/test/test-parse-typescript-angle-type-assertion.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include diff --git a/test/test-pipe-writer.cpp b/test/test-pipe-writer.cpp index a04657ae94..3c5e71f4d0 100644 --- a/test/test-pipe-writer.cpp +++ b/test/test-pipe-writer.cpp @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #if QLJS_HAVE_FCNTL_H diff --git a/test/test-translation-table-compiler.cpp b/test/test-translation-table-compiler.cpp index 52b67d2664..d835fca6ff 100644 --- a/test/test-translation-table-compiler.cpp +++ b/test/test-translation-table-compiler.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include using ::testing::ElementsAreArray; diff --git a/test/test-utf-16.cpp b/test/test-utf-16.cpp index 2be1deebdd..2fd503b850 100644 --- a/test/test-utf-16.cpp +++ b/test/test-utf-16.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/test/test-utf-8.cpp b/test/test-utf-8.cpp index 7d9695bfa7..019d734de2 100644 --- a/test/test-utf-8.cpp +++ b/test/test-utf-8.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #define EXPECT_ENCODE_UTF_8(code_point, expected) \ diff --git a/test/test-vim-location.cpp b/test/test-vim-location.cpp index 533ca5d828..21946f63c2 100644 --- a/test/test-vim-location.cpp +++ b/test/test-vim-location.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include namespace quick_lint_js { diff --git a/test/test-web-demo-location.cpp b/test/test-web-demo-location.cpp index 9023839273..889040cbfe 100644 --- a/test/test-web-demo-location.cpp +++ b/test/test-web-demo-location.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include diff --git a/tools/analyze-trace.cpp b/tools/analyze-trace.cpp index d8714b4e59..ef19f07de7 100644 --- a/tools/analyze-trace.cpp +++ b/tools/analyze-trace.cpp @@ -17,8 +17,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/tools/generate-lex-keyword.cpp b/tools/generate-lex-keyword.cpp index c9fbf79bd5..3357da3741 100644 --- a/tools/generate-lex-keyword.cpp +++ b/tools/generate-lex-keyword.cpp @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/tools/generate-trace-sources.cpp b/tools/generate-trace-sources.cpp index 210ecee84a..10f3f5e355 100644 --- a/tools/generate-trace-sources.cpp +++ b/tools/generate-trace-sources.cpp @@ -1408,8 +1408,8 @@ void write_writer_h(CXX_Trace_Types_Parser& types, Output_Stream& out) { #include #include #include -#include -#include +#include +#include #include // clang-format off From 118fe45452036138e217698f5361f2befcee4229 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Tue, 31 Oct 2023 16:50:08 -0400 Subject: [PATCH 062/117] refactor(fe): make expression_cast syntax saner expression_cast(ast) returns a Foo*, not a Foo or Foo&. This is confusing because other kinds of casts return what's inside the < >. Change expression_cast(ast) to expression_cast(ast) to match sttatic_cast(ast). --- src/quick-lint-js/fe/expression.h | 4 ++-- src/quick-lint-js/fe/parse-expression.cpp | 2 +- src/quick-lint-js/fe/parse-statement.cpp | 2 +- src/quick-lint-js/fe/parse.cpp | 4 ++-- test/test-parse-expression.cpp | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/quick-lint-js/fe/expression.h b/src/quick-lint-js/fe/expression.h index 16c1a6bdad..abfa992ed8 100644 --- a/src/quick-lint-js/fe/expression.h +++ b/src/quick-lint-js/fe/expression.h @@ -301,10 +301,10 @@ Object_Property_Value_Pair::is_merged_property_and_value_shorthand() { } template -Derived *expression_cast(Expression *p) { +Derived expression_cast(Expression *p) { // TODO(strager): Assert that Derived matches the Expression's run-time // type. - return static_cast(&*p); + return static_cast(&*p); } // Prevent expression_cast((call*)p). diff --git a/src/quick-lint-js/fe/parse-expression.cpp b/src/quick-lint-js/fe/parse-expression.cpp index 139794b457..105fad4a25 100644 --- a/src/quick-lint-js/fe/parse-expression.cpp +++ b/src/quick-lint-js/fe/parse-expression.cpp @@ -2448,7 +2448,7 @@ Expression* Parser::parse_arrow_function_expression_remainder( // f(x, y) => {} case Expression_Kind::Call: { - auto* call = expression_cast(parameters_expression); + auto* call = expression_cast(parameters_expression); if (this->peek().type == Token_Type::left_curly) { parameter_list_begin = call->left_paren_span().begin(); for (Span_Size i = 1; i < call->child_count(); ++i) { diff --git a/src/quick-lint-js/fe/parse-statement.cpp b/src/quick-lint-js/fe/parse-statement.cpp index 6acef62def..a097954d60 100644 --- a/src/quick-lint-js/fe/parse-statement.cpp +++ b/src/quick-lint-js/fe/parse-statement.cpp @@ -5411,7 +5411,7 @@ void Parser::visit_binding_element(Expression *ast, Parse_Visitor_Base &v, } case Expression_Kind::Await: { - auto *await = expression_cast(ast); + auto *await = expression_cast(ast); Identifier ident(await->unary_operator_span()); visit_variable_declaration(ident); this->diag_reporter_->report(Diag_Cannot_Declare_Await_In_Async_Function{ diff --git a/src/quick-lint-js/fe/parse.cpp b/src/quick-lint-js/fe/parse.cpp index d9715390aa..486a2ff104 100644 --- a/src/quick-lint-js/fe/parse.cpp +++ b/src/quick-lint-js/fe/parse.cpp @@ -264,7 +264,7 @@ Expression* Parser::maybe_wrap_erroneous_arrow_function( return arrow_function; case Expression_Kind::Trailing_Comma: { - auto* parameter_list = expression_cast(lhs); + auto* parameter_list = expression_cast(lhs); Expression* last_parameter = parameter_list->child(parameter_list->child_count() - 1); if (last_parameter->kind() == Expression_Kind::Spread) { @@ -279,7 +279,7 @@ Expression* Parser::maybe_wrap_erroneous_arrow_function( // f() => {} // Invalid. case Expression_Kind::Call: { - auto* call = expression_cast(lhs); + auto* call = expression_cast(lhs); Source_Code_Span missing_operator_span(call->span().begin(), call->left_paren_span().end()); this->diag_reporter_->report( diff --git a/test/test-parse-expression.cpp b/test/test-parse-expression.cpp index 566869b72d..da53a4795b 100644 --- a/test/test-parse-expression.cpp +++ b/test/test-parse-expression.cpp @@ -435,7 +435,7 @@ TEST_F(Test_Parse_Expression, parse_function_call) { EXPECT_EQ(summarize(ast->child_0()), "var f"); EXPECT_EQ(ast->child_count(), 1); EXPECT_THAT(ast->span(), p.matches_offsets(0, 3)); - Expression::Call* call = expression_cast(ast); + Expression::Call* call = expression_cast(ast); EXPECT_THAT(call->left_paren_span(), p.matches_offsets(1, 2)); } From 0c856f3ad9998bd0fbfba69691803060a797bba3 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Tue, 31 Oct 2023 16:50:08 -0400 Subject: [PATCH 063/117] refactor(fe): use expression_cast for better documentation static_cast can mean many things, but expression_cast is explicitly a downward cast. Use expression_cast if possible. --- src/quick-lint-js/fe/expression.h | 172 ++++++++++++---------- src/quick-lint-js/fe/parse-expression.cpp | 70 ++++----- src/quick-lint-js/fe/parse-statement.cpp | 40 ++--- src/quick-lint-js/fe/parse.cpp | 18 +-- test/quick-lint-js/parse-support.cpp | 8 +- test/test-parse-expression-jsx.cpp | 12 +- test/test-parse-expression-typescript.cpp | 2 +- test/test-parse-expression.cpp | 23 ++- test/test-parse-typescript-function.cpp | 2 +- 9 files changed, 193 insertions(+), 154 deletions(-) diff --git a/src/quick-lint-js/fe/expression.h b/src/quick-lint-js/fe/expression.h index abfa992ed8..18be70c4c9 100644 --- a/src/quick-lint-js/fe/expression.h +++ b/src/quick-lint-js/fe/expression.h @@ -307,6 +307,27 @@ Derived expression_cast(Expression *p) { return static_cast(&*p); } +template +Derived expression_cast(const Expression *p) { + // TODO(strager): Assert that Derived matches the Expression's run-time + // type. + return static_cast(&*p); +} + +template +Derived expression_cast(Expression &p) { + // TODO(strager): Assert that Derived matches the Expression's run-time + // type. + return static_cast(p); +} + +template +Derived expression_cast(const Expression &p) { + // TODO(strager): Assert that Derived matches the Expression's run-time + // type. + return static_cast(p); +} + // Prevent expression_cast((call*)p). template Derived *expression_cast(Expression *) = delete; @@ -1127,17 +1148,17 @@ static_assert(Expression_Arena::is_allocatable); inline Identifier Expression::variable_identifier() const { switch (this->kind_) { case Expression_Kind::Dot: - return static_cast(this)->variable_identifier_; + return expression_cast(this)->variable_identifier_; case Expression_Kind::JSX_Element: - return static_cast(this)->tag; + return expression_cast(this)->tag; case Expression_Kind::Named_Function: - return static_cast(this) + return expression_cast(this) ->variable_identifier_; case Expression_Kind::Private_Variable: - return static_cast(this) + return expression_cast(this) ->variable_identifier_; case Expression_Kind::Variable: - return static_cast(this) + return expression_cast(this) ->variable_identifier_; default: @@ -1148,7 +1169,7 @@ inline Identifier Expression::variable_identifier() const { inline Token_Type Expression::variable_identifier_token_type() const { switch (this->kind_) { case Expression_Kind::Variable: - return static_cast(this)->type_; + return expression_cast(this)->type_; default: QLJS_UNEXPECTED_EXPRESSION_KIND(); @@ -1168,7 +1189,7 @@ inline Expression_Arena::Array_Ptr Expression::children() const { case Expression_Kind::Assignment: case Expression_Kind::Compound_Assignment: case Expression_Kind::Conditional_Assignment: { - auto *assignment = static_cast(this); + auto *assignment = expression_cast(this); return Expression_Arena::Array_Ptr(assignment->children_); } @@ -1180,9 +1201,8 @@ inline Expression_Arena::Array_Ptr Expression::children() const { case Expression_Kind::Unary_Operator: case Expression_Kind::Yield_Many: case Expression_Kind::Yield_One: { - auto *ast = - static_cast( - this); + auto *ast = expression_cast< + const Expression::Expression_With_Prefix_Operator_Base *>(this); return Expression_Arena::Array_Ptr(&ast->child_, 1); } @@ -1190,72 +1210,75 @@ inline Expression_Arena::Array_Ptr Expression::children() const { case Expression_Kind::JSX_Element_With_Members: case Expression_Kind::JSX_Element_With_Namespace: case Expression_Kind::JSX_Fragment: { - auto *jsx = static_cast(this); + auto *jsx = expression_cast(this); return jsx->children; } case Expression_Kind::New: - return static_cast(this)->children_; + return expression_cast(this)->children_; case Expression_Kind::Template: - return static_cast(this)->children_; + return expression_cast(this)->children_; case Expression_Kind::Angle_Type_Assertion: { auto *assertion = - static_cast(this); + expression_cast(this); return Expression_Arena::Array_Ptr(&assertion->child_, 1); } case Expression_Kind::Array: - return static_cast(this)->children_; + return expression_cast(this)->children_; case Expression_Kind::Arrow_Function: - return static_cast(this)->children_; + return expression_cast(this)->children_; case Expression_Kind::As_Type_Assertion: { - auto *assertion = static_cast(this); + auto *assertion = + expression_cast(this); return Expression_Arena::Array_Ptr(&assertion->child_, 1); } case Expression_Kind::Binary_Operator: - return static_cast(this)->children_; + return expression_cast(this) + ->children_; case Expression_Kind::Call: - return static_cast(this)->children_; + return expression_cast(this)->children_; case Expression_Kind::Conditional: { - auto *conditional = static_cast(this); + auto *conditional = expression_cast(this); return Expression_Arena::Array_Ptr(conditional->children_); } case Expression_Kind::Dot: { - auto *dot = static_cast(this); + auto *dot = expression_cast(this); return Expression_Arena::Array_Ptr(&dot->child_, 1); } case Expression_Kind::Index: { - auto *index = static_cast(this); + auto *index = expression_cast(this); return Expression_Arena::Array_Ptr(index->children_); } case Expression_Kind::Non_Null_Assertion: { - auto *assertion = static_cast(this); + auto *assertion = + expression_cast(this); return Expression_Arena::Array_Ptr(&assertion->child_, 1); } case Expression_Kind::Paren: { - auto *paren = static_cast(this); + auto *paren = expression_cast(this); return Expression_Arena::Array_Ptr(&paren->child_, 1); } case Expression_Kind::Optional: { - auto *optional = static_cast(this); + auto *optional = expression_cast(this); return Expression_Arena::Array_Ptr(&optional->child_, 1); } case Expression_Kind::RW_Unary_Suffix: { auto *rw_unary_suffix = - static_cast(this); + expression_cast(this); return Expression_Arena::Array_Ptr(&rw_unary_suffix->child_, 1); } case Expression_Kind::Satisfies: { - auto *satisfies = static_cast(this); + auto *satisfies = expression_cast(this); return Expression_Arena::Array_Ptr(&satisfies->child_, 1); } case Expression_Kind::Tagged_Template_Literal: - return static_cast(this) + return expression_cast(this) ->tag_and_template_children_; case Expression_Kind::Trailing_Comma: - return static_cast(this)->children_; + return expression_cast(this)->children_; case Expression_Kind::Type_Annotated: { - auto *annotated = static_cast(this); + auto *annotated = expression_cast(this); return Expression_Arena::Array_Ptr(&annotated->child_, 1); } @@ -1267,7 +1290,7 @@ inline Expression_Arena::Array_Ptr Expression::children() const { inline Expression *Expression::without_paren() const { const Expression *ast = this; while (ast->kind_ == Expression_Kind::Paren) { - ast = static_cast(ast)->child_; + ast = expression_cast(ast)->child_; } // TODO(strager): Remove const_cast. return const_cast(ast); @@ -1276,7 +1299,7 @@ inline Expression *Expression::without_paren() const { inline Span_Size Expression::object_entry_count() const { switch (this->kind_) { case Expression_Kind::Object: - return static_cast(this)->entries_.size(); + return expression_cast(this)->entries_.size(); default: QLJS_UNEXPECTED_EXPRESSION_KIND(); @@ -1287,7 +1310,7 @@ inline Object_Property_Value_Pair Expression::object_entry( Span_Size index) const { switch (this->kind_) { case Expression_Kind::Object: - return static_cast(this)->entries_[index]; + return expression_cast(this)->entries_[index]; default: QLJS_UNEXPECTED_EXPRESSION_KIND(); @@ -1299,7 +1322,7 @@ inline Source_Code_Span Expression::span() const { case Expression_Kind::Assignment: case Expression_Kind::Compound_Assignment: case Expression_Kind::Conditional_Assignment: { - auto *assignment = static_cast(this); + auto *assignment = expression_cast(this); return Source_Code_Span(assignment->children_.front()->span().begin(), assignment->children_.back()->span().end()); } @@ -1312,9 +1335,8 @@ inline Source_Code_Span Expression::span() const { case Expression_Kind::Unary_Operator: case Expression_Kind::Yield_Many: case Expression_Kind::Yield_One: { - auto *prefix = - static_cast( - this); + auto *prefix = expression_cast< + const Expression::Expression_With_Prefix_Operator_Base *>(this); return Source_Code_Span(prefix->unary_operator_begin_, prefix->child_->span().end()); } @@ -1323,27 +1345,27 @@ inline Source_Code_Span Expression::span() const { case Expression_Kind::JSX_Element_With_Members: case Expression_Kind::JSX_Element_With_Namespace: case Expression_Kind::JSX_Fragment: - return static_cast(this)->span; + return expression_cast(this)->span; case Expression_Kind::Class: - return static_cast(this)->span_; + return expression_cast(this)->span_; case Expression_Kind::Invalid: - return static_cast(this)->span_; + return expression_cast(this)->span_; case Expression_Kind::Missing: - return static_cast(this)->span_; + return expression_cast(this)->span_; case Expression_Kind::New: - return static_cast(this)->span_; + return expression_cast(this)->span_; case Expression_Kind::Template: - return static_cast(this)->span_; + return expression_cast(this)->span_; case Expression_Kind::Angle_Type_Assertion: { - auto *assertion = static_cast(this); + auto *assertion = expression_cast(this); return Source_Code_Span(assertion->bracketed_type_span_.begin(), assertion->child_->span().end()); } case Expression_Kind::Array: - return static_cast(this)->span_; + return expression_cast(this)->span_; case Expression_Kind::Arrow_Function: { - auto *arrow = static_cast(this); + auto *arrow = expression_cast(this); if (arrow->parameter_list_begin_) { return Source_Code_Span(arrow->parameter_list_begin_, arrow->span_end_); } else { @@ -1352,97 +1374,97 @@ inline Source_Code_Span Expression::span() const { } } case Expression_Kind::As_Type_Assertion: { - auto *assertion = static_cast(this); + auto *assertion = expression_cast(this); return Source_Code_Span(assertion->child_->span().begin(), assertion->span_end_); } case Expression_Kind::Binary_Operator: { - auto *binary = static_cast(this); + auto *binary = expression_cast(this); return Source_Code_Span(binary->children_.front()->span().begin(), binary->children_.back()->span().end()); } case Expression_Kind::Call: { - auto *call = static_cast(this); + auto *call = expression_cast(this); return Source_Code_Span(call->children_.front()->span().begin(), call->span_end_); } case Expression_Kind::Conditional: { - auto *conditional = static_cast(this); + auto *conditional = expression_cast(this); return Source_Code_Span(conditional->children_.front()->span().begin(), conditional->children_.back()->span().end()); } case Expression_Kind::Dot: { - auto *dot = static_cast(this); + auto *dot = expression_cast(this); return Source_Code_Span(dot->child_0()->span().begin(), dot->variable_identifier_.span().end()); } case Expression_Kind::Function: - return static_cast(this)->span_; + return expression_cast(this)->span_; case Expression_Kind::Import: - return static_cast(this)->span_; + return expression_cast(this)->span_; case Expression_Kind::Index: { - auto *index = static_cast(this); + auto *index = expression_cast(this); return Source_Code_Span(index->child_0()->span().begin(), index->index_subscript_end_); } case Expression_Kind::Literal: - return static_cast(this)->span_; + return expression_cast(this)->span_; case Expression_Kind::Named_Function: - return static_cast(this)->span_; + return expression_cast(this)->span_; case Expression_Kind::New_Target: - return static_cast(this)->span_; + return expression_cast(this)->span_; case Expression_Kind::Non_Null_Assertion: { - auto *assertion = static_cast(this); + auto *assertion = expression_cast(this); return Source_Code_Span(assertion->child_->span().begin(), assertion->bang_end_); } case Expression_Kind::Object: - return static_cast(this)->span_; + return expression_cast(this)->span_; case Expression_Kind::Optional: { - auto *optional = static_cast(this); + auto *optional = expression_cast(this); return Source_Code_Span(optional->child_->span().begin(), optional->question_end_); } case Expression_Kind::Paren: - return static_cast(this)->span_; + return expression_cast(this)->span_; case Expression_Kind::Paren_Empty: - return static_cast(this)->span_; + return expression_cast(this)->span_; case Expression_Kind::Private_Variable: - return static_cast(this) + return expression_cast(this) ->variable_identifier_.span(); case Expression_Kind::RW_Unary_Suffix: { - auto *suffix = static_cast(this); + auto *suffix = expression_cast(this); return Source_Code_Span(suffix->child_->span().begin(), suffix->unary_operator_end_); } case Expression_Kind::Satisfies: { - auto *s = static_cast(this); + auto *s = expression_cast(this); return Source_Code_Span(s->child_->span().begin(), s->span_end_); } case Expression_Kind::Super: - return static_cast(this)->span_; + return expression_cast(this)->span_; case Expression_Kind::Tagged_Template_Literal: { - auto *literal = static_cast(this); + auto *literal = expression_cast(this); return Source_Code_Span( literal->tag_and_template_children_[0]->span().begin(), literal->template_span_end_); } case Expression_Kind::This_Variable: - return static_cast(this)->span_; + return expression_cast(this)->span_; case Expression_Kind::Trailing_Comma: { - auto *comma = static_cast(this); + auto *comma = expression_cast(this); return Source_Code_Span(comma->children_.front()->span().begin(), comma->comma_end_); } case Expression_Kind::Type_Annotated: { - auto *annotated = static_cast(this); + auto *annotated = expression_cast(this); return Source_Code_Span(annotated->child_->span().begin(), annotated->span_end_); } case Expression_Kind::Variable: - return static_cast(this)->variable_identifier_.span(); + return expression_cast(this)->variable_identifier_.span(); case Expression_Kind::Yield_None: - return static_cast(this)->span_; + return expression_cast(this)->span_; } QLJS_UNREACHABLE(); } @@ -1456,13 +1478,13 @@ inline const Char8 *Expression::span_end() const { return this->span().end(); } inline Function_Attributes Expression::attributes() const { switch (this->kind_) { case Expression_Kind::Arrow_Function: - return static_cast(this) + return expression_cast(this) ->function_attributes_; case Expression_Kind::Function: - return static_cast(this) + return expression_cast(this) ->function_attributes_; case Expression_Kind::Named_Function: - return static_cast(this) + return expression_cast(this) ->function_attributes_; default: diff --git a/src/quick-lint-js/fe/parse-expression.cpp b/src/quick-lint-js/fe/parse-expression.cpp index 105fad4a25..73c862b5dc 100644 --- a/src/quick-lint-js/fe/parse-expression.cpp +++ b/src/quick-lint-js/fe/parse-expression.cpp @@ -66,16 +66,17 @@ void Parser::visit_expression(Expression* ast, Parse_Visitor_Base& v, case Expression_Kind::Binary_Operator: visit_children(); this->error_on_pointless_compare_against_literal( - static_cast(ast)); + expression_cast(ast)); error_on_pointless_string_compare( - static_cast(ast)); + expression_cast(ast)); this->error_on_pointless_nullish_coalescing_operator( - static_cast(ast)); + expression_cast(ast)); this->warn_on_xor_operator_as_exponentiation( - static_cast(ast)); + expression_cast(ast)); break; case Expression_Kind::Trailing_Comma: { - auto& trailing_comma_ast = static_cast(*ast); + auto& trailing_comma_ast = + expression_cast(*ast); this->diag_reporter_->report(Diag_Missing_Operand_For_Operator{ .where = trailing_comma_ast.comma_span(), }); @@ -127,7 +128,7 @@ void Parser::visit_expression(Expression* ast, Parse_Visitor_Base& v, if (child->kind() == Expression_Kind::Variable) { v.visit_variable_delete_use( child->variable_identifier(), - static_cast(ast)->unary_operator_span()); + expression_cast(ast)->unary_operator_span()); } else { this->visit_expression(child, v, context); } @@ -161,11 +162,12 @@ void Parser::visit_expression(Expression* ast, Parse_Visitor_Base& v, this->visit_expression(ast->child_0(), v, Variable_Context::rhs); this->visit_expression(ast->child_1(), v, Variable_Context::rhs); this->warn_on_comma_operator_in_index( - ast->child_1(), static_cast(ast)->left_square_span); + ast->child_1(), + expression_cast(ast)->left_square_span); break; case Expression_Kind::JSX_Element: { - auto* element = static_cast(ast); + auto* element = expression_cast(ast); if (!element->is_intrinsic()) { v.visit_variable_use(element->tag); } @@ -173,7 +175,7 @@ void Parser::visit_expression(Expression* ast, Parse_Visitor_Base& v, break; } case Expression_Kind::JSX_Element_With_Members: { - auto* element = static_cast(ast); + auto* element = expression_cast(ast); QLJS_ASSERT(element->members.size() >= 1); v.visit_variable_use(element->members[0]); visit_children(); @@ -222,7 +224,7 @@ void Parser::visit_expression(Expression* ast, Parse_Visitor_Base& v, } break; case Expression_Kind::Optional: { - auto* optional = static_cast(ast); + auto* optional = expression_cast(ast); this->visit_expression(optional->child_, v, context); this->diag_reporter_->report(Diag_Unexpected_Question_In_Expression{ .question = optional->question_span(), @@ -234,7 +236,7 @@ void Parser::visit_expression(Expression* ast, Parse_Visitor_Base& v, break; case Expression_Kind::Paren_Empty: { Expression::Paren_Empty* paren_empty = - static_cast(ast); + expression_cast(ast); paren_empty->report_missing_expression_error(this->diag_reporter_); break; } @@ -250,7 +252,7 @@ void Parser::visit_expression(Expression* ast, Parse_Visitor_Base& v, break; case Expression_Kind::Type_Annotated: { Expression::Type_Annotated* annotated = - static_cast(ast); + expression_cast(ast); this->visit_expression(annotated->child_, v, context); this->diag_reporter_->report(Diag_TypeScript_Type_Annotation_In_Expression{ .type_colon = annotated->colon_span(), @@ -1415,7 +1417,8 @@ Expression* Parser::parse_expression_remainder(Parse_Visitor_Base& v, // -a ** b // Invalid. // void a ** b // Invalid. case Expression_Kind::Unary_Operator: { - auto* lhs = static_cast(maybe_unary_lhs); + auto* lhs = + expression_cast(maybe_unary_lhs); if (lhs->is_void_operator()) { // void a ** b // Invalid. this->diag_reporter_->report( @@ -1440,7 +1443,7 @@ Expression* Parser::parse_expression_remainder(Parse_Visitor_Base& v, // delete a ** b // Invalid. case Expression_Kind::Delete: { - auto* lhs = static_cast(maybe_unary_lhs); + auto* lhs = expression_cast(maybe_unary_lhs); this->diag_reporter_->report( Diag_Missing_Parentheses_Around_Exponent_With_Unary_Lhs{ .exponent_expression = Source_Code_Span( @@ -1452,7 +1455,7 @@ Expression* Parser::parse_expression_remainder(Parse_Visitor_Base& v, // typeof a ** b // Invalid. case Expression_Kind::Typeof: { - auto* lhs = static_cast(maybe_unary_lhs); + auto* lhs = expression_cast(maybe_unary_lhs); this->diag_reporter_->report( Diag_Missing_Parentheses_Around_Exponent_With_Unary_Lhs{ .exponent_expression = Source_Code_Span( @@ -2037,7 +2040,7 @@ Expression* Parser::parse_expression_remainder(Parse_Visitor_Base& v, Buffering_Visitor* return_type_visits = nullptr; if (lhs->kind() == Expression_Kind::Type_Annotated) { Expression::Type_Annotated* annotated = - static_cast(lhs); + expression_cast(lhs); if (annotated->child_->kind() == Expression_Kind::Paren || annotated->child_->kind() == Expression_Kind::Paren_Empty) { // (): ReturnType => {} // TypeScript only. @@ -2086,7 +2089,7 @@ Expression* Parser::parse_expression_remainder(Parse_Visitor_Base& v, case Token_Type::left_curly: { auto has_comma_operator = [&binary_builder]() -> bool { Expression::Binary_Operator* expr = - static_cast( + expression_cast( binary_builder.last_expression()->without_paren()); bool comma = false; for (int i = 0; i < expr->children_.size() - 1; i++) { @@ -2312,7 +2315,7 @@ Expression* Parser::parse_arrow_function_expression_remainder( if (parameters_expression->kind() == Expression_Kind::Paren) { parameter_list_begin = parameters_expression->span_begin(); parameters_expression = - static_cast(parameters_expression)->child_; + expression_cast(parameters_expression)->child_; } Expression_Arena::Vector parameters( @@ -2381,7 +2384,7 @@ Expression* Parser::parse_arrow_function_expression_remainder( if (!parameter_list_begin) { // param? => {} // Invalid. Expression::Optional* param = - static_cast(parameters_expression); + expression_cast(parameters_expression); this->diag_reporter_->report( Diag_Optional_Arrow_Parameter_Requires_Parentheses{ .parameter_and_question = param->span(), @@ -2398,11 +2401,11 @@ Expression* Parser::parse_arrow_function_expression_remainder( // NOTE(strager): '(param): ReturnType => {}' is handled above. if (!parameter_list_begin) { Expression::Type_Annotated* param = - static_cast(parameters_expression); + expression_cast(parameters_expression); if (param->child_->kind() == Expression_Kind::Optional) { // param?: Type => {} // Invalid. Expression::Optional* optional = - static_cast(param->child_); + expression_cast(param->child_); this->diag_reporter_->report( Diag_Optional_Arrow_Parameter_With_Type_Annotation_Requires_Parentheses{ .parameter_and_annotation = param->span(), @@ -2424,7 +2427,7 @@ Expression* Parser::parse_arrow_function_expression_remainder( // ((x)) => {} // Invalid. case Expression_Kind::Paren: { - auto paren = static_cast(parameters_expression); + auto paren = expression_cast(parameters_expression); this->diag_reporter_->report( Diag_Unexpected_Function_Parameter_Is_Parenthesized{ .left_paren_to_right_paren = paren->span()}); @@ -2435,7 +2438,7 @@ Expression* Parser::parse_arrow_function_expression_remainder( // (()) => {} // Invalid. case Expression_Kind::Paren_Empty: { Expression::Paren_Empty* paren_empty = - static_cast(parameters_expression); + expression_cast(parameters_expression); if (parameter_list_begin) { // (()) => {} // Invalid. paren_empty->report_missing_expression_error(this->diag_reporter_); @@ -2527,10 +2530,11 @@ Expression::Call* Parser::parse_call_expression_remainder(Parse_Visitor_Base& v, .left_paren = left_paren_span, }); } - return static_cast(this->make_expression( - this->expressions_.make_array(std::move(call_children)), - /*left_paren_span=*/left_paren_span, - /*span_end=*/call_span_end)); + return expression_cast( + this->make_expression( + this->expressions_.make_array(std::move(call_children)), + /*left_paren_span=*/left_paren_span, + /*span_end=*/call_span_end)); } Expression* Parser::parse_index_expression_remainder(Parse_Visitor_Base& v, @@ -4096,16 +4100,16 @@ void Parser::check_assignment_lhs(Expression* ast) { Diag_Invalid_Expression_Left_Of_Assignment{ast->span()}); break; case Expression_Kind::Paren: - ast = static_cast(ast)->child_; + ast = expression_cast(ast)->child_; goto try_again; case Expression_Kind::Non_Null_Assertion: - ast = static_cast(ast)->child_; + ast = expression_cast(ast)->child_; goto try_again; case Expression_Kind::Angle_Type_Assertion: - ast = static_cast(ast)->child_; + ast = expression_cast(ast)->child_; goto try_again; case Expression_Kind::As_Type_Assertion: - ast = static_cast(ast)->child_; + ast = expression_cast(ast)->child_; goto try_again; case Expression_Kind::Invalid: case Expression_Kind::Missing: @@ -4120,10 +4124,10 @@ void Parser::check_assignment_lhs(Expression* ast) { case Expression_Kind::Private_Variable: break; case Expression_Kind::Optional: - ast = static_cast(ast)->child_; + ast = expression_cast(ast)->child_; goto try_again; case Expression_Kind::Satisfies: - ast = static_cast(ast)->child_; + ast = expression_cast(ast)->child_; goto try_again; case Expression_Kind::Type_Annotated: // TODO(strager): Distinguish between the following: diff --git a/src/quick-lint-js/fe/parse-statement.cpp b/src/quick-lint-js/fe/parse-statement.cpp index a097954d60..a4449fff3e 100644 --- a/src/quick-lint-js/fe/parse-statement.cpp +++ b/src/quick-lint-js/fe/parse-statement.cpp @@ -2462,7 +2462,7 @@ void Parser::parse_and_visit_function_parameters( this->diag_reporter_->report( Diag_TypeScript_Parameter_Property_Cannot_Be_Destructured{ .destructure_token = - static_cast(parameter) + expression_cast(parameter) ->left_square_span(), .property_keyword = *parameter_property_keyword, }); @@ -2474,7 +2474,7 @@ void Parser::parse_and_visit_function_parameters( this->diag_reporter_->report( Diag_TypeScript_Parameter_Property_Cannot_Be_Destructured{ .destructure_token = - static_cast(parameter) + expression_cast(parameter) ->left_curly_span(), .property_keyword = *parameter_property_keyword, }); @@ -2485,8 +2485,9 @@ void Parser::parse_and_visit_function_parameters( // constructor(private ...field) // Invalid. this->diag_reporter_->report( Diag_TypeScript_Parameter_Property_Cannot_Be_Rest{ - .spread = static_cast(parameter) - ->spread_operator_span(), + .spread = + expression_cast(parameter) + ->spread_operator_span(), .property_keyword = *parameter_property_keyword, }); } @@ -5055,7 +5056,7 @@ void Parser::parse_and_visit_let_bindings( } } - auto *assignment_ast = static_cast( + auto *assignment_ast = expression_cast( this->parse_expression_remainder( v, variable, Precedence{.commas = false, @@ -5324,7 +5325,7 @@ void Parser::visit_binding_element(Expression *ast, Parse_Visitor_Base &v, case Expression_Kind::Compound_Assignment: if (info.declaring_token.has_value()) { - auto *assignment = static_cast(ast); + auto *assignment = expression_cast(ast); this->diag_reporter_->report( Diag_Cannot_Update_Variable_During_Declaration{ .declaring_token = *info.declaring_token, @@ -5337,7 +5338,7 @@ void Parser::visit_binding_element(Expression *ast, Parse_Visitor_Base &v, } [[fallthrough]]; case Expression_Kind::Assignment: { - auto *assignment = static_cast(ast); + auto *assignment = expression_cast(ast); Expression *lhs = assignment->children_[0]; Expression *rhs = assignment->children_[1]; @@ -5347,7 +5348,7 @@ void Parser::visit_binding_element(Expression *ast, Parse_Visitor_Base &v, this->diag_reporter_->report( Diag_Optional_Parameter_Cannot_Have_Initializer{ .equal = assignment->operator_span_, - .question = static_cast(lhs) + .question = expression_cast(lhs) ->question_span(), }); } @@ -5400,7 +5401,7 @@ void Parser::visit_binding_element(Expression *ast, Parse_Visitor_Base &v, } case Expression_Kind::Spread: { - Expression::Spread *spread = static_cast(ast); + Expression::Spread *spread = expression_cast(ast); if (spread->child_0()->kind() == Expression_Kind::Missing) { this->diag_reporter_->report(Diag_Spread_Must_Precede_Variable_Name{ spread->spread_operator_span()}); @@ -5462,7 +5463,8 @@ void Parser::visit_binding_element(Expression *ast, Parse_Visitor_Base &v, // function f(x!) {} // Invalid. case Expression_Kind::Non_Null_Assertion: { - auto *assertion = static_cast(ast); + auto *assertion = + expression_cast(ast); this->diag_reporter_->report( Diag_Non_Null_Assertion_Not_Allowed_In_Parameter{ .bang = assertion->bang_span(), @@ -5474,7 +5476,7 @@ void Parser::visit_binding_element(Expression *ast, Parse_Visitor_Base &v, // function f(p) {} // Invalid. case Expression_Kind::Angle_Type_Assertion: { auto *assertion = - static_cast(ast); + expression_cast(ast); this->diag_reporter_->report(Diag_Invalid_Parameter{ .parameter = assertion->span(), }); @@ -5484,7 +5486,8 @@ void Parser::visit_binding_element(Expression *ast, Parse_Visitor_Base &v, // function f(x as y) {} // Invalid. case Expression_Kind::As_Type_Assertion: { - auto *assertion = static_cast(ast); + auto *assertion = + expression_cast(ast); this->diag_reporter_->report( Diag_TypeScript_As_Or_Satisfies_Used_For_Parameter_Type_Annotation{ .bad_keyword = assertion->as_span(), @@ -5495,7 +5498,7 @@ void Parser::visit_binding_element(Expression *ast, Parse_Visitor_Base &v, // function f(x satisfies T) {} // Invalid. case Expression_Kind::Satisfies: { - auto *s = static_cast(ast); + auto *s = expression_cast(ast); this->diag_reporter_->report( Diag_TypeScript_As_Or_Satisfies_Used_For_Parameter_Type_Annotation{ .bad_keyword = s->satisfies_span(), @@ -5507,7 +5510,8 @@ void Parser::visit_binding_element(Expression *ast, Parse_Visitor_Base &v, // function f([(p,)]) {} // Invalid. case Expression_Kind::Trailing_Comma: this->diag_reporter_->report(Diag_Stray_Comma_In_Parameter{ - .comma = static_cast(ast)->comma_span(), + .comma = + expression_cast(ast)->comma_span(), }); this->visit_binding_element(ast->child_0(), v, info); break; @@ -5530,7 +5534,7 @@ void Parser::visit_binding_element(Expression *ast, Parse_Visitor_Base &v, // function f(param?) {} // TypeScript only. // let [x?] = xs; // Invalid. case Expression_Kind::Optional: { - auto *optional = static_cast(ast); + auto *optional = expression_cast(ast); if (info.is_destructuring) { // let [x?] = xs; // Invalid. this->diag_reporter_->report(Diag_Unexpected_Question_When_Destructuring{ @@ -5551,7 +5555,7 @@ void Parser::visit_binding_element(Expression *ast, Parse_Visitor_Base &v, // function f([(arg)]) {} // Invalid. case Expression_Kind::Paren: { - auto paren = static_cast(ast); + auto paren = expression_cast(ast); this->diag_reporter_->report( Diag_Unexpected_Function_Parameter_Is_Parenthesized{ .left_paren_to_right_paren = paren->span()}); @@ -5562,7 +5566,7 @@ void Parser::visit_binding_element(Expression *ast, Parse_Visitor_Base &v, // function f(()) {} // Invalid. case Expression_Kind::Paren_Empty: { Expression::Paren_Empty *paren_empty = - static_cast(ast); + expression_cast(ast); paren_empty->report_missing_expression_error(this->diag_reporter_); break; } @@ -5610,7 +5614,7 @@ void Parser::visit_binding_element(Expression *ast, Parse_Visitor_Base &v, // const [x]: []number = xs; case Expression_Kind::Type_Annotated: { Expression::Type_Annotated *annotated = - static_cast(ast); + expression_cast(ast); annotated->visit_type_annotation(v); this->visit_binding_element(annotated->child_, v, info); break; diff --git a/src/quick-lint-js/fe/parse.cpp b/src/quick-lint-js/fe/parse.cpp index 486a2ff104..723e56cac5 100644 --- a/src/quick-lint-js/fe/parse.cpp +++ b/src/quick-lint-js/fe/parse.cpp @@ -298,7 +298,7 @@ Expression* Parser::maybe_wrap_erroneous_arrow_function( void Parser::error_on_sketchy_condition(Expression* ast) { if (ast->kind() == Expression_Kind::Assignment && ast->child_1()->kind() == Expression_Kind::Literal) { - auto* assignment = static_cast(ast); + auto* assignment = expression_cast(ast); this->diag_reporter_->report(Diag_Assignment_Makes_Condition_Constant{ .assignment_operator = assignment->operator_span_, }); @@ -310,9 +310,9 @@ void Parser::error_on_sketchy_condition(Expression* ast) { ast->children().size() == 3 && ((ast->child(2)->kind() == Expression_Kind::Literal) || ((ast->child(2)->kind() == Expression_Kind::Variable) && - (static_cast(ast->child(2))->type_ == + (expression_cast(ast->child(2))->type_ == Token_Type::kw_undefined)))) { - auto* binary = static_cast(ast); + auto* binary = expression_cast(ast); Source_Code_Span left_operator = binary->operator_spans_[0]; Source_Code_Span right_operator = binary->operator_spans_[1]; if (right_operator.string_view() == u8"||"_sv && @@ -331,7 +331,7 @@ void Parser::warn_on_comma_operator_in_conditional_statement(Expression* ast) { auto is_comma = [](String8_View s) -> bool { return s == u8","_sv; }; - auto* binary_operator = static_cast(ast); + auto* binary_operator = expression_cast(ast); for (Span_Size i = binary_operator->child_count() - 2; i >= 0; i--) { Source_Code_Span op_span = binary_operator->operator_spans_[i]; if (is_comma(op_span.string_view())) { @@ -349,7 +349,7 @@ void Parser::warn_on_comma_operator_in_index(Expression* ast, auto is_comma = [](String8_View s) -> bool { return s == u8","_sv; }; - auto* binary_operator = static_cast(ast); + auto* binary_operator = expression_cast(ast); for (Span_Size i = binary_operator->child_count() - 2; i >= 0; i--) { Source_Code_Span op_span = binary_operator->operator_spans_[i]; if (is_comma(op_span.string_view())) { @@ -431,7 +431,7 @@ void Parser::error_on_invalid_as_const(Expression* ast, break; case Expression_Kind::Literal: { - auto* literal = static_cast(ast); + auto* literal = expression_cast(ast); if (literal->is_null() || literal->is_regexp()) { goto invalid; } @@ -537,7 +537,7 @@ void Parser::check_compare_against_literal(Expression* lhs, Expression* rhs, .equals_operator = op_span, .comparison_result = comparison_result}); return; case Expression_Kind::Literal: - if (static_cast(child)->is_regexp()) { + if (expression_cast(child)->is_regexp()) { this->diag_reporter_->report( Diag_Pointless_Comp_Against_Regular_Expression_Literal{ .equals_operator = op_span, @@ -808,7 +808,7 @@ void Parser::check_lhs_for_null_potential(Expression* lhs, report_diag = true; break; case Expression_Kind::Unary_Operator: { - auto* maybe_void_lhs = static_cast(lhs); + auto* maybe_void_lhs = expression_cast(lhs); if (!maybe_void_lhs->is_void_operator()) { report_diag = true; } @@ -818,7 +818,7 @@ void Parser::check_lhs_for_null_potential(Expression* lhs, report_diag = true; break; case Expression_Kind::Binary_Operator: { - auto* operator_lhs = static_cast(lhs); + auto* operator_lhs = expression_cast(lhs); report_diag = binary_operator_is_never_null(operator_lhs); break; } diff --git a/test/quick-lint-js/parse-support.cpp b/test/quick-lint-js/parse-support.cpp index 6103a486b7..521e0a8cb6 100644 --- a/test/quick-lint-js/parse-support.cpp +++ b/test/quick-lint-js/parse-support.cpp @@ -144,7 +144,8 @@ void summarize(const Expression& expression, std::string& out) { break; case Expression_Kind::JSX_Element: { const auto& jsx = - static_cast(expression); + expression_cast( + expression); out += "jsxelement("; out += to_string_view(jsx.tag.normalized_name()); if (jsx.child_count() != 0) { @@ -155,9 +156,8 @@ void summarize(const Expression& expression, std::string& out) { break; } case Expression_Kind::JSX_Element_With_Members: { - const auto& jsx = - static_cast( - expression); + const auto& jsx = expression_cast< + const quick_lint_js::Expression::JSX_Element_With_Members&>(expression); out += "jsxmemberelement(("; bool need_comma = false; for (int i = 0; i < jsx.members.size(); ++i) { diff --git a/test/test-parse-expression-jsx.cpp b/test/test-parse-expression-jsx.cpp index 5b1e2f99cd..8eb2e1008c 100644 --- a/test/test-parse-expression-jsx.cpp +++ b/test/test-parse-expression-jsx.cpp @@ -33,7 +33,7 @@ TEST_F(Test_Parse_Expression_JSX, intrinsic_element) { Expression* ast = p.parse_expression(); ASSERT_EQ(ast->kind(), Expression_Kind::JSX_Element); EXPECT_EQ(ast->variable_identifier().normalized_name(), u8"div"_sv); - EXPECT_TRUE(static_cast(ast)->is_intrinsic()); + EXPECT_TRUE(expression_cast(ast)->is_intrinsic()); } { @@ -41,7 +41,7 @@ TEST_F(Test_Parse_Expression_JSX, intrinsic_element) { Expression* ast = p.parse_expression(); ASSERT_EQ(ast->kind(), Expression_Kind::JSX_Element); EXPECT_EQ(ast->variable_identifier().normalized_name(), u8"div"_sv); - EXPECT_TRUE(static_cast(ast)->is_intrinsic()); + EXPECT_TRUE(expression_cast(ast)->is_intrinsic()); } { @@ -50,7 +50,7 @@ TEST_F(Test_Parse_Expression_JSX, intrinsic_element) { ASSERT_EQ(ast->kind(), Expression_Kind::JSX_Element); EXPECT_EQ(ast->variable_identifier().normalized_name(), u8"My-Web-Component"_sv); - EXPECT_TRUE(static_cast(ast)->is_intrinsic()); + EXPECT_TRUE(expression_cast(ast)->is_intrinsic()); } } @@ -60,7 +60,8 @@ TEST_F(Test_Parse_Expression_JSX, user_element) { Expression* ast = p.parse_expression(); ASSERT_EQ(ast->kind(), Expression_Kind::JSX_Element); EXPECT_EQ(ast->variable_identifier().normalized_name(), u8"MyComponent"_sv); - EXPECT_FALSE(static_cast(ast)->is_intrinsic()); + EXPECT_FALSE( + expression_cast(ast)->is_intrinsic()); } { @@ -68,7 +69,8 @@ TEST_F(Test_Parse_Expression_JSX, user_element) { Expression* ast = p.parse_expression(); ASSERT_EQ(ast->kind(), Expression_Kind::JSX_Element); EXPECT_EQ(ast->variable_identifier().normalized_name(), u8"MyComponent"_sv); - EXPECT_FALSE(static_cast(ast)->is_intrinsic()); + EXPECT_FALSE( + expression_cast(ast)->is_intrinsic()); } } diff --git a/test/test-parse-expression-typescript.cpp b/test/test-parse-expression-typescript.cpp index eee5d80b79..73a4af55fe 100644 --- a/test/test-parse-expression-typescript.cpp +++ b/test/test-parse-expression-typescript.cpp @@ -37,7 +37,7 @@ TEST_F(Test_Parse_Expression_TypeScript, type_annotation) { EXPECT_THAT(ast->span(), p.matches_offsets(0, u8"x: Type"_sv)); Spy_Visitor v; - static_cast(ast)->visit_type_annotation(v); + expression_cast(ast)->visit_type_annotation(v); EXPECT_THAT(v.visits, ElementsAreArray({ "visit_variable_type_use", })); diff --git a/test/test-parse-expression.cpp b/test/test-parse-expression.cpp index da53a4795b..e2a7b8a7b4 100644 --- a/test/test-parse-expression.cpp +++ b/test/test-parse-expression.cpp @@ -2740,7 +2740,7 @@ TEST_F(Test_Parse_Expression, binary_operator_span) { SCOPED_TRACE(p.code); Expression* ast = p.parse_expression(); ASSERT_EQ(ast->kind(), Expression_Kind::Binary_Operator); - auto* binary = static_cast(ast); + auto* binary = expression_cast(ast); EXPECT_THAT( binary->operator_spans_[0], p.matches_offsets(u8"x"_sv.size(), concat(u8"x"_sv, op).size())); @@ -2748,7 +2748,8 @@ TEST_F(Test_Parse_Expression, binary_operator_span) { { Test_Parser p(u8"x + y * z"_sv); - auto* ast = static_cast(p.parse_expression()); + auto* ast = + expression_cast(p.parse_expression()); EXPECT_THAT(ast->operator_spans_[0], p.matches_offsets(u8"x "_sv.size(), u8"+"_sv)); EXPECT_THAT(ast->operator_spans_[1], @@ -2757,14 +2758,16 @@ TEST_F(Test_Parse_Expression, binary_operator_span) { { Test_Parser p(u8"x.'foo'"_sv, capture_diags); - auto* ast = static_cast(p.parse_expression()); + auto* ast = + expression_cast(p.parse_expression()); EXPECT_THAT(ast->operator_spans_[0], p.matches_offsets(1, 2)); // Ignore p.errors. } { Test_Parser p(u8"x .. y"_sv, capture_diags); - auto* ast = static_cast(p.parse_expression()); + auto* ast = + expression_cast(p.parse_expression()); EXPECT_THAT(ast->operator_spans_[0], p.matches_offsets(u8"x ."_sv.size(), u8"."_sv)); // Ignore p.errors. @@ -2772,7 +2775,8 @@ TEST_F(Test_Parse_Expression, binary_operator_span) { { Test_Parser p(u8"x in y"_sv); - auto* ast = static_cast(p.parse_expression()); + auto* ast = + expression_cast(p.parse_expression()); EXPECT_THAT(ast->operator_spans_[0], p.matches_offsets(u8"x "_sv.size(), u8"in"_sv)); } @@ -2780,7 +2784,8 @@ TEST_F(Test_Parse_Expression, binary_operator_span) { { Test_Parser p(u8"f(x y)"_sv, capture_diags); Expression* ast = p.parse_expression(); - auto* binary = static_cast(ast->child_1()); + auto* binary = + expression_cast(ast->child_1()); EXPECT_THAT(binary->operator_spans_[0], p.matches_offsets(u8"f(x"_sv.size(), u8""_sv)); // Ignore p.errors. @@ -2788,7 +2793,8 @@ TEST_F(Test_Parse_Expression, binary_operator_span) { { Test_Parser p(u8"x.y => z"_sv, capture_diags); - auto* ast = static_cast(p.parse_expression()); + auto* ast = + expression_cast(p.parse_expression()); EXPECT_THAT(ast->operator_spans_[0], p.matches_offsets(u8"x.y "_sv.size(), u8"=>"_sv)); // Ignore p.errors. @@ -2796,7 +2802,8 @@ TEST_F(Test_Parse_Expression, binary_operator_span) { { Test_Parser p(u8"f() => {}"_sv, capture_diags); - auto* ast = static_cast(p.parse_expression()); + auto* ast = + expression_cast(p.parse_expression()); // FIXME(strager): These spans look weird. EXPECT_THAT(ast->operator_spans_[0], p.matches_offsets(0, u8"f("_sv)); // Ignore p.errors. diff --git a/test/test-parse-typescript-function.cpp b/test/test-parse-typescript-function.cpp index 62eabd162d..46a1e846b6 100644 --- a/test/test-parse-typescript-function.cpp +++ b/test/test-parse-typescript-function.cpp @@ -624,7 +624,7 @@ TEST_F(Test_Parse_TypeScript_Function, optional_expression) { ASSERT_THAT(summarize(ast), "paren(typed(optional(var x)))"); auto* type_annotated = - static_cast(ast->without_paren()); + expression_cast(ast->without_paren()); Spy_Visitor v; type_annotated->visit_type_annotation(v); EXPECT_THAT(v.visits, ElementsAreArray({ From 645999ab99ef0a0f28de2bce7fbdb629b39c3d6d Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Tue, 31 Oct 2023 16:50:08 -0400 Subject: [PATCH 064/117] refactor(fe): avoid silly dereference then addressof --- src/quick-lint-js/fe/expression.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/quick-lint-js/fe/expression.h b/src/quick-lint-js/fe/expression.h index 18be70c4c9..e1fc8e2838 100644 --- a/src/quick-lint-js/fe/expression.h +++ b/src/quick-lint-js/fe/expression.h @@ -304,14 +304,14 @@ template Derived expression_cast(Expression *p) { // TODO(strager): Assert that Derived matches the Expression's run-time // type. - return static_cast(&*p); + return static_cast(p); } template Derived expression_cast(const Expression *p) { // TODO(strager): Assert that Derived matches the Expression's run-time // type. - return static_cast(&*p); + return static_cast(p); } template From 3dd09c63e9501721767230c36ec676a5b6c7c454 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Tue, 31 Oct 2023 16:51:06 -0400 Subject: [PATCH 065/117] refactor(util): add derived_cast helper static_cast has multiple meanings. Make it clearer that some casts are for downcasting only by implementing a derived_cast function. --- src/quick-lint-js/diag/diagnostic-formatter.h | 2 +- src/quick-lint-js/fe/expression.h | 12 ++++------ src/quick-lint-js/fe/lex.cpp | 4 ++-- src/quick-lint-js/fe/parse.cpp | 2 +- src/quick-lint-js/io/file-canonical.cpp | 2 +- src/quick-lint-js/lsp/lsp-server.cpp | 2 +- src/quick-lint-js/util/cast.h | 23 +++++++++++++++++++ 7 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/quick-lint-js/diag/diagnostic-formatter.h b/src/quick-lint-js/diag/diagnostic-formatter.h index 6ceadbf142..32f0e2412c 100644 --- a/src/quick-lint-js/diag/diagnostic-formatter.h +++ b/src/quick-lint-js/diag/diagnostic-formatter.h @@ -95,7 +95,7 @@ inline void Diagnostic_Formatter::format_message( static constexpr auto npos = String8_View::npos; using String8_Pos = String8_View::size_type; - Derived* self = static_cast(this); + Derived* self = derived_cast(this); Source_Code_Span origin_span = get_argument_source_code_span(args, diagnostic, 0); diff --git a/src/quick-lint-js/fe/expression.h b/src/quick-lint-js/fe/expression.h index e1fc8e2838..1e0b852b96 100644 --- a/src/quick-lint-js/fe/expression.h +++ b/src/quick-lint-js/fe/expression.h @@ -304,34 +304,30 @@ template Derived expression_cast(Expression *p) { // TODO(strager): Assert that Derived matches the Expression's run-time // type. - return static_cast(p); + return derived_cast(p); } template Derived expression_cast(const Expression *p) { // TODO(strager): Assert that Derived matches the Expression's run-time // type. - return static_cast(p); + return derived_cast(p); } template Derived expression_cast(Expression &p) { // TODO(strager): Assert that Derived matches the Expression's run-time // type. - return static_cast(p); + return derived_cast(p); } template Derived expression_cast(const Expression &p) { // TODO(strager): Assert that Derived matches the Expression's run-time // type. - return static_cast(p); + return derived_cast(p); } -// Prevent expression_cast((call*)p). -template -Derived *expression_cast(Expression *) = delete; - template Expression *Expression_Arena::make_expression(Args &&... args) { Expression *result(this->allocate(std::forward(args)...)); diff --git a/src/quick-lint-js/fe/lex.cpp b/src/quick-lint-js/fe/lex.cpp index fb62369534..1973613490 100644 --- a/src/quick-lint-js/fe/lex.cpp +++ b/src/quick-lint-js/fe/lex.cpp @@ -1126,7 +1126,7 @@ Lexer_Transaction Lexer::begin_transaction() { void Lexer::commit_transaction(Lexer_Transaction&& transaction) { Buffering_Diag_Reporter* buffered_diagnostics = - static_cast(this->diag_reporter_); + derived_cast(this->diag_reporter_); buffered_diagnostics->move_into(transaction.old_diag_reporter); this->diag_reporter_ = transaction.old_diag_reporter; @@ -1146,7 +1146,7 @@ void Lexer::roll_back_transaction(Lexer_Transaction&& transaction) { bool Lexer::transaction_has_lex_diagnostics(const Lexer_Transaction&) const { Buffering_Diag_Reporter* buffered_diagnostics = - static_cast(this->diag_reporter_); + derived_cast(this->diag_reporter_); return !buffered_diagnostics->empty(); } diff --git a/src/quick-lint-js/fe/parse.cpp b/src/quick-lint-js/fe/parse.cpp index 723e56cac5..90ef2a0ae3 100644 --- a/src/quick-lint-js/fe/parse.cpp +++ b/src/quick-lint-js/fe/parse.cpp @@ -852,7 +852,7 @@ Parser_Transaction Parser::begin_transaction() { void Parser::commit_transaction(Parser_Transaction&& transaction) { auto* buffered_diagnostics = - static_cast(this->diag_reporter_); + derived_cast(this->diag_reporter_); buffered_diagnostics->move_into(transaction.old_diag_reporter); this->diag_reporter_ = transaction.old_diag_reporter; diff --git a/src/quick-lint-js/io/file-canonical.cpp b/src/quick-lint-js/io/file-canonical.cpp index b93fb32e80..9eee6132d9 100644 --- a/src/quick-lint-js/io/file-canonical.cpp +++ b/src/quick-lint-js/io/file-canonical.cpp @@ -413,7 +413,7 @@ class Path_Canonicalizer_Base { return component; } - Derived &derived() { return *static_cast(this); } + Derived &derived() { return *derived_cast(this); } protected: void skip_to_next_component() { diff --git a/src/quick-lint-js/lsp/lsp-server.cpp b/src/quick-lint-js/lsp/lsp-server.cpp index bb61bdc40e..d862ee4519 100644 --- a/src/quick-lint-js/lsp/lsp-server.cpp +++ b/src/quick-lint-js/lsp/lsp-server.cpp @@ -374,7 +374,7 @@ void Linting_LSP_Server_Handler::handle_text_document_did_change_notification( } case LSP_Documents::Document_Type::lintable: - this->linter_.lint(static_cast(doc), + this->linter_.lint(derived_cast(doc), notification.uri.json, this->outgoing_messages_); break; diff --git a/src/quick-lint-js/util/cast.h b/src/quick-lint-js/util/cast.h index 66ce118c30..278e387b9b 100644 --- a/src/quick-lint-js/util/cast.h +++ b/src/quick-lint-js/util/cast.h @@ -55,6 +55,29 @@ template constexpr std::underlying_type_t enum_to_int_cast(Enum value) { return static_cast>(value); } + +// Cast a pointer or reference to a pointer/reference to a derived class. +// +// In the presence of multiple inheritance, perform pointer adjustments (like +// what static_cast does). +template +Derived_Pointer derived_cast(Base* base) { + using Derived = std::remove_pointer_t; + static_assert(std::is_base_of_v, + "Derived should derive from Base"); + static_assert(!std::is_base_of_v, + "Derived should not be the same type as Base"); + return static_cast(base); +} +template +Derived_Reference derived_cast(Base& base) { + using Derived = std::remove_reference_t; + static_assert(std::is_base_of_v, + "Derived should derive from Base"); + static_assert(!std::is_base_of_v, + "Derived should not be the same type as Base"); + return static_cast(base); +} } // quick-lint-js finds bugs in JavaScript programs. From aaf8db69fd0d03febde8b68ede3e654190f4190b Mon Sep 17 00:00:00 2001 From: toastino Date: Thu, 2 Nov 2023 02:21:16 -0400 Subject: [PATCH 066/117] feat(fe): warn on confusing operator precedence of & and >> closes #1056 Co-authored-by: Matthew "strager" Glazar --- docs/errors/E0716.md | 25 +++++++++++++++++++ po/messages.pot | 8 ++++++ .../diag/diagnostic-metadata-generated.cpp | 18 +++++++++++++ .../diag/diagnostic-metadata-generated.h | 3 ++- src/quick-lint-js/diag/diagnostic-types-2.h | 12 +++++++++ src/quick-lint-js/fe/parse-expression.cpp | 2 ++ src/quick-lint-js/fe/parse.cpp | 19 +++++++++++++- src/quick-lint-js/fe/parse.h | 1 + .../i18n/translation-table-generated.cpp | 8 ++++-- .../i18n/translation-table-generated.h | 6 +++-- .../i18n/translation-table-test-generated.h | 24 +++++++++++++++++- test/test-parse-warning.cpp | 21 ++++++++++++++++ 12 files changed, 140 insertions(+), 7 deletions(-) create mode 100644 docs/errors/E0716.md diff --git a/docs/errors/E0716.md b/docs/errors/E0716.md new file mode 100644 index 0000000000..249d3ce47b --- /dev/null +++ b/docs/errors/E0716.md @@ -0,0 +1,25 @@ +# E0716: unintuitive operator precedence when using & and << or >> + +```config-for-examples +{ + "globals": { + "another_variable": true + } +} +``` + +JavaScript's operator precedence can cause confusing situations and bugs when it +comes to bitshifting with a bitwise and. +```js +let a_bitwise_variable = another_variable & 0x1 << 0x2 +``` +The code above looks like it evaluates `another_variable & 0x1` first, +but it instead evaluates `0x1 << 0x2` first. +If this is intended behavior, it may be easier to read if you write parentheses: +```js +another_variable & (0x1 << 0x2) +``` +Otherwise, to get the order of operations correct, add parentheses around the operands of `&`: +```js +(another_variable & 0x1) << 0x2 +``` diff --git a/po/messages.pot b/po/messages.pot index 57504375ed..0d21adfd3b 100644 --- a/po/messages.pot +++ b/po/messages.pot @@ -2089,6 +2089,14 @@ msgstr "" msgid "export default previously appeared here" msgstr "" +#: src/quick-lint-js/diag/diagnostic-metadata-generated.cpp +msgid "unintuitive operator precedence when using & and '{0}'; '{0}' evaluates before &" +msgstr "" + +#: src/quick-lint-js/diag/diagnostic-metadata-generated.cpp +msgid "'&' here" +msgstr "" + #: test/test-diagnostic-formatter.cpp #: test/test-vim-qflist-json-diag-reporter.cpp msgid "something happened" diff --git a/src/quick-lint-js/diag/diagnostic-metadata-generated.cpp b/src/quick-lint-js/diag/diagnostic-metadata-generated.cpp index 8f4b3cface..1102307596 100644 --- a/src/quick-lint-js/diag/diagnostic-metadata-generated.cpp +++ b/src/quick-lint-js/diag/diagnostic-metadata-generated.cpp @@ -6425,6 +6425,24 @@ const QLJS_CONSTINIT Diagnostic_Info all_diagnostic_infos[] = { }, }, }, + + // Diag_Unintuitive_Bitshift_Precedence + { + .code = 716, + .severity = Diagnostic_Severity::warning, + .message_formats = { + QLJS_TRANSLATABLE("unintuitive operator precedence when using & and '{0}'; '{0}' evaluates before &"), + QLJS_TRANSLATABLE("'&' here"), + }, + .message_args = { + { + Diagnostic_Message_Arg_Info(offsetof(Diag_Unintuitive_Bitshift_Precedence, bitshift_operator), Diagnostic_Arg_Type::source_code_span), + }, + { + Diagnostic_Message_Arg_Info(offsetof(Diag_Unintuitive_Bitshift_Precedence, and_operator), Diagnostic_Arg_Type::source_code_span), + }, + }, + }, }; } diff --git a/src/quick-lint-js/diag/diagnostic-metadata-generated.h b/src/quick-lint-js/diag/diagnostic-metadata-generated.h index ce26201539..dfeb9eb5c9 100644 --- a/src/quick-lint-js/diag/diagnostic-metadata-generated.h +++ b/src/quick-lint-js/diag/diagnostic-metadata-generated.h @@ -440,10 +440,11 @@ namespace quick_lint_js { QLJS_DIAG_TYPE_NAME(Diag_Class_Generator_On_Getter_Or_Setter) \ QLJS_DIAG_TYPE_NAME(Diag_Class_Async_On_Getter_Or_Setter) \ QLJS_DIAG_TYPE_NAME(Diag_Multiple_Export_Defaults) \ + QLJS_DIAG_TYPE_NAME(Diag_Unintuitive_Bitshift_Precedence) \ /* END */ // clang-format on -inline constexpr int Diag_Type_Count = 429; +inline constexpr int Diag_Type_Count = 430; extern const Diagnostic_Info all_diagnostic_infos[Diag_Type_Count]; } diff --git a/src/quick-lint-js/diag/diagnostic-types-2.h b/src/quick-lint-js/diag/diagnostic-types-2.h index 59839d2462..c49dcd7cf4 100644 --- a/src/quick-lint-js/diag/diagnostic-types-2.h +++ b/src/quick-lint-js/diag/diagnostic-types-2.h @@ -3318,6 +3318,18 @@ struct Diag_Multiple_Export_Defaults { Source_Code_Span second_export_default; Source_Code_Span first_export_default; }; + +struct Diag_Unintuitive_Bitshift_Precedence { + [[qljs::diag("E0716", Diagnostic_Severity::warning)]] // + // clang-format off + [[qljs::message("unintuitive operator precedence when using & and '{0}'; " + "'{0}' evaluates before &", + ARG(bitshift_operator))]] // + // clang-format on + [[qljs::message("'&' here", ARG(and_operator))]] // + Source_Code_Span bitshift_operator; + Source_Code_Span and_operator; +}; } QLJS_WARNING_POP diff --git a/src/quick-lint-js/fe/parse-expression.cpp b/src/quick-lint-js/fe/parse-expression.cpp index 73c862b5dc..a8ff40c322 100644 --- a/src/quick-lint-js/fe/parse-expression.cpp +++ b/src/quick-lint-js/fe/parse-expression.cpp @@ -73,6 +73,8 @@ void Parser::visit_expression(Expression* ast, Parse_Visitor_Base& v, expression_cast(ast)); this->warn_on_xor_operator_as_exponentiation( expression_cast(ast)); + this->warn_on_unintuitive_bitshift_precedence( + expression_cast(ast)); break; case Expression_Kind::Trailing_Comma: { auto& trailing_comma_ast = diff --git a/src/quick-lint-js/fe/parse.cpp b/src/quick-lint-js/fe/parse.cpp index 90ef2a0ae3..fb7417949b 100644 --- a/src/quick-lint-js/fe/parse.cpp +++ b/src/quick-lint-js/fe/parse.cpp @@ -360,7 +360,24 @@ void Parser::warn_on_comma_operator_in_index(Expression* ast, } } } - +void Parser::warn_on_unintuitive_bitshift_precedence(Expression* ast) { + if (ast->kind() != Expression_Kind::Binary_Operator) return; + if (ast->child_count() <= 2) return; + auto* binary_op = static_cast(ast); + Source_Code_Span left_op = binary_op->operator_spans_[0]; + Source_Code_Span right_op = binary_op->operator_spans_[1]; + if (left_op.string_view() == u8"&"_sv && + (right_op.string_view() == u8">>"_sv || + right_op.string_view() == u8"<<"_sv)) { + if (binary_op->child(0)->kind() == Expression_Kind::Variable && + binary_op->child(1)->kind() == Expression_Kind::Literal && + binary_op->child(2)->kind() == Expression_Kind::Literal) { + this->diag_reporter_->report( + quick_lint_js::Diag_Unintuitive_Bitshift_Precedence{ + .bitshift_operator = right_op, .and_operator = left_op}); + } + } +} void Parser::error_on_pointless_string_compare( Expression::Binary_Operator* ast) { auto is_comparison_operator = [](String8_View s) { diff --git a/src/quick-lint-js/fe/parse.h b/src/quick-lint-js/fe/parse.h index 69d55e4f1c..f3f5f5cdb5 100644 --- a/src/quick-lint-js/fe/parse.h +++ b/src/quick-lint-js/fe/parse.h @@ -526,6 +526,7 @@ class Parser { void warn_on_comma_operator_in_conditional_statement(Expression *); void warn_on_comma_operator_in_index(Expression *, Source_Code_Span); void warn_on_xor_operator_as_exponentiation(Expression::Binary_Operator *); + void warn_on_unintuitive_bitshift_precedence(Expression *ast); void error_on_pointless_string_compare(Expression::Binary_Operator *); void error_on_pointless_compare_against_literal( Expression::Binary_Operator *); diff --git a/src/quick-lint-js/i18n/translation-table-generated.cpp b/src/quick-lint-js/i18n/translation-table-generated.cpp index 04ee6b82d4..f99f767822 100644 --- a/src/quick-lint-js/i18n/translation-table-generated.cpp +++ b/src/quick-lint-js/i18n/translation-table-generated.cpp @@ -18,7 +18,8 @@ const Translation_Table translation_data = { {74, 87, 79, 56, 0, 59}, // {71, 80, 60, 58, 0, 52}, // {0, 0, 0, 0, 0, 28}, // - {31, 56, 0, 32, 0, 63}, // + {0, 0, 0, 0, 0, 63}, // + {31, 56, 0, 32, 0, 9}, // {0, 0, 0, 0, 0, 67}, // {0, 0, 0, 70, 0, 26}, // {79, 25, 30, 63, 49593, 66}, // @@ -499,7 +500,8 @@ const Translation_Table translation_data = { {180, 42, 159, 156, 171, 156}, // {0, 0, 0, 0, 0, 65}, // {92, 45, 78, 81, 70, 43}, // - {98, 37, 86, 82, 83, 77}, // + {0, 0, 0, 0, 0, 77}, // + {98, 37, 86, 82, 83, 81}, // {38, 35, 17, 23, 13, 14}, // {38, 27, 34, 28, 33, 27}, // {26, 41, 26, 32, 0, 22}, // @@ -1813,6 +1815,7 @@ const Translation_Table translation_data = { u8"\"globals\" descriptor must be a boolean or an object\0" u8"\"globals\" must be an object\0" u8"'!' here treated as the TypeScript non-null assertion operator\0" + u8"'&' here\0" u8"'**' operator cannot be used after unary '{1}' without parentheses\0" u8"',' should be ';' instead\0" u8"'.' is not allowed after generic arguments; write [\"{1}\"] instead\0" @@ -2294,6 +2297,7 @@ const Translation_Table translation_data = { u8"unexpected token in variable declaration; expected variable name\0" u8"unexpected whitespace between '!' and '=='\0" u8"unicode byte order mark (BOM) cannot appear before #! at beginning of script\0" + u8"unintuitive operator precedence when using & and '{0}'; '{0}' evaluates before &\0" u8"unmatched '}'\0" u8"unmatched indexing bracket\0" u8"unmatched parenthesis\0" diff --git a/src/quick-lint-js/i18n/translation-table-generated.h b/src/quick-lint-js/i18n/translation-table-generated.h index 514e20b711..2819960be4 100644 --- a/src/quick-lint-js/i18n/translation-table-generated.h +++ b/src/quick-lint-js/i18n/translation-table-generated.h @@ -18,8 +18,8 @@ namespace quick_lint_js { using namespace std::literals::string_view_literals; constexpr std::uint32_t translation_table_locale_count = 5; -constexpr std::uint16_t translation_table_mapping_table_size = 524; -constexpr std::size_t translation_table_string_table_size = 80043; +constexpr std::uint16_t translation_table_mapping_table_size = 526; +constexpr std::size_t translation_table_string_table_size = 80133; constexpr std::size_t translation_table_locale_table_size = 35; QLJS_CONSTEVAL std::uint16_t translation_table_const_look_up( @@ -33,6 +33,7 @@ QLJS_CONSTEVAL std::uint16_t translation_table_const_look_up( "\"globals\" descriptor must be a boolean or an object"sv, "\"globals\" must be an object"sv, "'!' here treated as the TypeScript non-null assertion operator"sv, + "'&' here"sv, "'**' operator cannot be used after unary '{1}' without parentheses"sv, "',' should be ';' instead"sv, "'.' is not allowed after generic arguments; write [\"{1}\"] instead"sv, @@ -514,6 +515,7 @@ QLJS_CONSTEVAL std::uint16_t translation_table_const_look_up( "unexpected token in variable declaration; expected variable name"sv, "unexpected whitespace between '!' and '=='"sv, "unicode byte order mark (BOM) cannot appear before #! at beginning of script"sv, + "unintuitive operator precedence when using & and '{0}'; '{0}' evaluates before &"sv, "unmatched '}'"sv, "unmatched indexing bracket"sv, "unmatched parenthesis"sv, diff --git a/src/quick-lint-js/i18n/translation-table-test-generated.h b/src/quick-lint-js/i18n/translation-table-test-generated.h index 59c04ad26a..c647722028 100644 --- a/src/quick-lint-js/i18n/translation-table-test-generated.h +++ b/src/quick-lint-js/i18n/translation-table-test-generated.h @@ -27,7 +27,7 @@ struct Translated_String { }; // clang-format off -inline const Translated_String test_translation_table[523] = { +inline const Translated_String test_translation_table[525] = { { "\"global-groups\" entries must be strings"_translatable, u8"\"global-groups\" entries must be strings", @@ -105,6 +105,17 @@ inline const Translated_String test_translation_table[523] = { u8"'!' here treated as the TypeScript non-null assertion operator", }, }, + { + "'&' here"_translatable, + u8"'&' here", + { + u8"'&' here", + u8"'&' here", + u8"'&' here", + u8"'&' here", + u8"'&' here", + }, + }, { "'**' operator cannot be used after unary '{1}' without parentheses"_translatable, u8"'**' operator cannot be used after unary '{1}' without parentheses", @@ -5396,6 +5407,17 @@ inline const Translated_String test_translation_table[523] = { u8"unicode byte ordningsm\u00e4rke (BOM) kan inte f\u00f6rekomma f\u00f6re #! i b\u00f6rjan av skript", }, }, + { + "unintuitive operator precedence when using & and '{0}'; '{0}' evaluates before &"_translatable, + u8"unintuitive operator precedence when using & and '{0}'; '{0}' evaluates before &", + { + u8"unintuitive operator precedence when using & and '{0}'; '{0}' evaluates before &", + u8"unintuitive operator precedence when using & and '{0}'; '{0}' evaluates before &", + u8"unintuitive operator precedence when using & and '{0}'; '{0}' evaluates before &", + u8"unintuitive operator precedence when using & and '{0}'; '{0}' evaluates before &", + u8"unintuitive operator precedence when using & and '{0}'; '{0}' evaluates before &", + }, + }, { "unmatched '}'"_translatable, u8"unmatched '}'", diff --git a/test/test-parse-warning.cpp b/test/test-parse-warning.cpp index 518eff78cc..ea968ec564 100644 --- a/test/test-parse-warning.cpp +++ b/test/test-parse-warning.cpp @@ -436,6 +436,27 @@ TEST_F(Test_Parse_Warning, warn_on_xor_operation_used_as_exponentiation) { test_parse_and_visit_expression(u8"4 ^ 3"_sv, no_diags); test_parse_and_visit_expression(u8"(x+2)^a"_sv, no_diags); } +TEST_F(Test_Parse_Warning, warn_on_unintuitive_precedence_when_using_bitshift) { + test_parse_and_visit_expression( + u8"var1 & 0x01 >> 0x02"_sv, + u8" ^^ Diag_Unintuitive_Bitshift_Precedence.bitshift_operator\n"_diag + u8" ^ .and_operator"_diag); + test_parse_and_visit_expression( + u8"var2 & 0x1234 << 0x4321"_sv, + u8" ^^ Diag_Unintuitive_Bitshift_Precedence.bitshift_operator\n"_diag + u8" ^ .and_operator"_diag); + test_parse_and_visit_statement( + u8"const x = a & 10 << 12"_sv, + u8" ^^ Diag_Unintuitive_Bitshift_Precedence.bitshift_operator\n"_diag + u8" ^ .and_operator"_diag); + test_parse_and_visit_expression(u8"0x111 << 0x222 & var1"_sv, no_diags); + test_parse_and_visit_expression(u8"a&b>>c"_sv, no_diags); + test_parse_and_visit_expression(u8"x & y << z"_sv, no_diags); + test_parse_and_visit_expression(u8"0xABCD & 0xDCBA << 0xFFFF"_sv, no_diags); + test_parse_and_visit_expression(u8"(a & 0o12) >> 0xBEEF"_sv, no_diags); + test_parse_and_visit_expression(u8"a & (b >> 0xBEEF)"_sv, no_diags); + test_parse_and_visit_expression(u8"a & b >> c"_sv, no_diags); +} } } From 9565209bd978f0e35642a9133ffe77cef3d071dd Mon Sep 17 00:00:00 2001 From: Ariel Don Date: Thu, 2 Nov 2023 02:21:28 -0400 Subject: [PATCH 067/117] fix(fe): don't report missing `else` for bad `if` expression --- src/quick-lint-js/fe/parse.h | 2 +- test/test-parse-statement.cpp | 21 +++++++++++++++++++++ test/test-parse.cpp | 5 +++-- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/quick-lint-js/fe/parse.h b/src/quick-lint-js/fe/parse.h index f3f5f5cdb5..214d93dbbc 100644 --- a/src/quick-lint-js/fe/parse.h +++ b/src/quick-lint-js/fe/parse.h @@ -1173,7 +1173,7 @@ void Parser::parse_and_visit_parenthesized_expression( const Char8 *expression_begin = this->peek().begin; - Expression *ast = this->parse_expression(v); + Expression *ast = this->parse_expression(v, {.trailing_identifiers = true}); this->visit_expression(ast, v, Variable_Context::rhs); if constexpr (check_for_sketchy_conditions) { diff --git a/test/test-parse-statement.cpp b/test/test-parse-statement.cpp index befaa08fce..4c62f1996b 100644 --- a/test/test-parse-statement.cpp +++ b/test/test-parse-statement.cpp @@ -595,6 +595,27 @@ TEST_F(Test_Parse_Statement, if_with_else) { } } +TEST_F(Test_Parse_Statement, if_else_with_malformed_condition) { + { + Test_Parser p( + u8"if (e isntanceof DataNotLoadedError) { } else { throw e; }"_sv, + capture_diags); + p.parse_and_visit_statement(); + EXPECT_THAT(p.visits, + ElementsAreArray({"visit_variable_use", // e + "visit_variable_use", // typoed instanceof + "visit_variable_use", // DataNotLoadedError + "visit_enter_block_scope", // + "visit_exit_block_scope", // + "visit_enter_block_scope", // + "visit_variable_use", // e + "visit_exit_block_scope"})); + EXPECT_THAT( + p.errors, + ::testing::Not(::testing::Contains(DIAG_TYPE(Diag_Else_Has_No_If)))); + } +} + TEST_F(Test_Parse_Statement, if_without_body) { { Spy_Visitor p = test_parse_and_visit_statement( diff --git a/test/test-parse.cpp b/test/test-parse.cpp index 474815828e..6fe88d6b0a 100644 --- a/test/test-parse.cpp +++ b/test/test-parse.cpp @@ -320,8 +320,9 @@ TEST_F(Test_Parse, utter_garbage) { assert_diagnostics( p.code, p.errors, { - u8" ^ Diag_Expected_Parentheses_Around_If_Condition"_diag, // - u8" ^ Diag_Unexpected_Token"_diag, + u8" ^ Diag_Unexpected_Token"_diag, // : + u8" ^^^^^^^^ Diag_Unexpected_Identifier_In_Expression"_diag, // kjaslkjd + u8" ^^^^^^^^^^^ Diag_Expected_Parentheses_Around_If_Condition"_diag, // :\nkjaskljd }); } } From d5e9ae6beb6291c1e7e0583c37a64fefae858c2b Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Thu, 2 Nov 2023 02:21:28 -0400 Subject: [PATCH 068/117] feat(docs): update change log and authors list --- docs/AUTHORS.md | 1 + docs/CHANGELOG.md | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/docs/AUTHORS.md b/docs/AUTHORS.md index 2972c7948c..b1b351b945 100644 --- a/docs/AUTHORS.md +++ b/docs/AUTHORS.md @@ -89,4 +89,5 @@ authored portions of quick-lint-js: * ooblegork; codyxvalley@mail.fresnostate.edu; signed CLA-v1.md * oren; countoren@gmail.com; signed CLA-v1.md * pedrobl85; pedrobl1718@gmail.com; signed CLA-v1.md +* toastino; toastino@disroot.org; signed CLA-v1.md * wagner riffel; w@104d.net; signed CLA-v1.md diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 3d5cdb16d7..6f40ff9fc7 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -8,8 +8,17 @@ Semantic Versioning. ## Unreleased +### Added + +* Mixing `&` and `<<` such as in `a & 0x1 << 3` now reports [E0716][] + ("unintuitive operator precedence when using & and << or >>"). (Implemented by + [toastin0][].) + ### Fixed +* A missing operator in an `if` condition (such as in `if (x y)`) no longer + causes [E0065][] ("'else' has no corresponding 'if'") to be reported. + (Implemented by [arieldon][].) * `cmake --install` with `--component build-tools` now installs the build tools. (This is a regression introduced in quick-lint-js version 2.16.0.) @@ -1143,6 +1152,7 @@ Beta release. [ooblegork]: https://github.com/ooblegork [pedrobl1718]: https://github.com/pedrobl85 [tiagovla]: https://github.com/tiagovla +[toastin0]: https://github.com/toastin0 [wagner riffel]: https://github.com/wgrr [E0001]: https://quick-lint-js.com/errors/E0001/ @@ -1271,3 +1281,4 @@ Beta release. [E0713]: https://quick-lint-js.com/errors/E0713/ [E0714]: https://quick-lint-js.com/errors/E0714/ [E0715]: https://quick-lint-js.com/errors/E0715/ +[E0716]: https://quick-lint-js.com/errors/E0716/ From ff9668a1c3722e561ab0bd7136994c45c0656826 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Thu, 2 Nov 2023 22:16:43 -0400 Subject: [PATCH 069/117] fix(certificates): fix expired certificates on Windows The quick-lint-js 2.17.0 Windows release was signed with the following certificate chain: * Matthew Glazar * SSL.com Code Signing Intermediate CA RSA R1 * SSL.com Root Certification Authority RSA * Certum Trusted Network CA Unfortunately, the Certum Trusted Network CA certificate, which cross-signs the SSL.com Root Certification Authority RSA certificate, expired on 2023-09-11. The expiration is *before* the quick-lint-js release was made (2023-10-25). This expiry was documented by SSL.com [1]. When Windows loads this certificate chain, it sees the expired cross-signature and makes a decision: * It is common that Windows gets a trusted (e.g. self-signed) version of the SSL.com Root Certification Authority RSA certificate from somewhere else. If this happens, then Windows validates the signature. * If Windows does not have a suitable replacement certificate (e.g. on a fresh install on Windows), then Windows refuses to validate the signature due to the expiration. This causes installation via the MSIX to fail. Fix the verification problem by choosing a self-signed, Windows-trusted version of the SSL.com Root Certification Authority RSA certificate. (This is the same signature we use for timestamp signature verification introduced in commit 3bfc72d5.) Fixes https://github.com/quick-lint/quick-lint-js/issues/1100 Refs: 3bfc72d57720171fb21e2567bc44734a24748f5f [1] https://www.ssl.com/blogs/ssl-com-legacy-cross-signed-root-certificate-expiring-on-september-11-2023/ --- .../Certum Trusted Network CA.pem | 22 ----- dist/certificates/quick-lint-js.crt | 89 +++++++------------ docs/CHANGELOG.md | 5 ++ docs/CODE_SIGNING.md | 1 - 4 files changed, 37 insertions(+), 80 deletions(-) delete mode 100644 dist/certificates/Certum Trusted Network CA.pem diff --git a/dist/certificates/Certum Trusted Network CA.pem b/dist/certificates/Certum Trusted Network CA.pem deleted file mode 100644 index a04e656d8c..0000000000 --- a/dist/certificates/Certum Trusted Network CA.pem +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM -MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D -ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU -cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 -WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg -Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw -IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH -UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM -TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU -BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM -kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x -AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV -HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y -sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL -I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 -J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY -VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI -03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= ------END CERTIFICATE----- diff --git a/dist/certificates/quick-lint-js.crt b/dist/certificates/quick-lint-js.crt index 0abd266d6b..e7cbfa26ad 100644 --- a/dist/certificates/quick-lint-js.crt +++ b/dist/certificates/quick-lint-js.crt @@ -81,61 +81,36 @@ PGb/O7KVq5qNncyU8O14UH/sZEejnQ== SSL_COM_ROOT_CERTIFICATION_AUTHORITY_RSA.crt Source: https://www.ssl.com/article/ssl-com-root-certificates/ -----BEGIN CERTIFICATE----- -MIIF2DCCBMCgAwIBAgIRAOQnBJX2jJHW0Ox7SU6k3xwwDQYJKoZIhvcNAQELBQAw -fjELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu -QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEiMCAG -A1UEAxMZQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQTAeFw0xODA5MTEwOTI2NDda -Fw0yMzA5MTEwOTI2NDdaMHwxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQ -MA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTEwLwYD -VQQDDChTU0wuY29tIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBMIIC -IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA+Q/doyt9y9Aq/uxnhabnLhu6 -d+Hj9a+k7PpKXZHEV0drGHdrdvL9k+Q9D8IWngtmw1aUnheDhc5W7/IW/QBi9SIJ -VOhlF05BueBPRpeqG8i4bmJeabFf2yoCfvxsyvNB2O3Q6Pw/YUjtsAMUHRAOSxng -u07shmX/NvNeZwILnYZVYf16OO3+4hkAt2+hUGJ1dDyg+sglkrRueiLH+B6h47Ld -kTGrKx0E/6VKBDfphaQzK/3i1lU0fBmkSmjHsqjTt8qhk4jrwZe8jPkd2SKEJHTH -BD1qqSmTzOu4W+H+XyWqNFjIwSNUnRuYEcM4nH49hmylD0CGfAL0XAJPKMuucZ8P -Osgz/hElNer8usVgPdl8GNWyqdN1eANyIso6wx/vLOUuqfqeLLZRRv2vA9bqYGjq -hRY2a4XpHsCz3cQk3IAqgUFtlD7I4MmBQQCeXr9/xQiYohgsQkCz+W84J0tOgPQ9 -gUfgiHzqHM61dVxRLhwrfxpyKOcAtdF0xtfkn60Hk7ZTNTX8N+TD9l0WviFz3pIK -+KBjaryWkmo++LxlVZve9Q2JJgT8JRqmJWnLwm3KfOJZX5es6+8uyLzXG1k8K8zy -GciTaydjGc/86Sb4ynGbf5P+NGeETpnr/LN4CTNwumamdu0bc+sapQ3EIhMglFYK -TixsTrH9z5wJuqIz7YcCAwEAAaOCAVEwggFNMBIGA1UdEwEB/wQIMAYBAf8CAQIw -HQYDVR0OBBYEFN0ECQei9Xp9UlMSkpXuOIAlDaZZMB8GA1UdIwQYMBaAFAh2zcsH -/yT2xc3tu5C84oQ3RnX3MA4GA1UdDwEB/wQEAwIBBjA2BgNVHR8ELzAtMCugKaAn -hiVodHRwOi8vc3NsY29tLmNybC5jZXJ0dW0ucGwvY3RuY2EuY3JsMHMGCCsGAQUF -BwEBBGcwZTApBggrBgEFBQcwAYYdaHR0cDovL3NzbGNvbS5vY3NwLWNlcnR1bS5j -b20wOAYIKwYBBQUHMAKGLGh0dHA6Ly9zc2xjb20ucmVwb3NpdG9yeS5jZXJ0dW0u -cGwvY3RuY2EuY2VyMDoGA1UdIAQzMDEwLwYEVR0gADAnMCUGCCsGAQUFBwIBFhlo -dHRwczovL3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEBCwUAA4IBAQAflZoj -VO6FwvPUb7npBI9Gfyz3MsCnQ6wHAO3gqUUt/Rfh7QBAyK+YrPXAGa0boJcwQGzs -W/ujk06MiWIbfPA6X6dCz1jKdWWcIky/dnuYk5wVgzOxDtxROId8lZwSaZQeAHh0 -ftzABne6cC2HLNdoneO6ha1J849ktBUGg5LGl6RAk4ut8WeUtLlaZ1Q8qBvZBc/k -pPmIEgAGiCWF1F7u85NX1oH4LK739VFIq7ZiOnnb7C7yPxRWOsjZy6SiTyWo0Zur -LTAgUAcab/HxlB05g2PoH/1J0OgdRrJGgia9nJ3homhBSFFuevw1lvRU0rwrROVH -13eCpUqrX5czqyQR ------END CERTIFICATE----- - -Certum Trusted Network CA.pem -Source: Apple ------BEGIN CERTIFICATE----- -MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM -MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D -ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU -cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 -WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg -Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw -IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH -UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM -TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU -BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM -kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x -AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV -HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y -sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL -I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 -J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY -VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI -03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE +BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK +DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz +OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv +bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R +xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX +qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC +C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3 +6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh +/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF +YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E +JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc +US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8 +ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm ++Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi +M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G +A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV +cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc +Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs +PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/ +q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0 +cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr +a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I +H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y +K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu +nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf +oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY +Ic2wBlX7Jz9TkHCpBB5XJ7k= -----END CERTIFICATE----- diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 6f40ff9fc7..13e2b794b7 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -21,6 +21,8 @@ Semantic Versioning. (Implemented by [arieldon][].) * `cmake --install` with `--component build-tools` now installs the build tools. (This is a regression introduced in quick-lint-js version 2.16.0.) +* Windows: The installer and executables are now signed with a non-expired + certificate chain. ## 2.17.0 (2023-10-25) @@ -32,6 +34,9 @@ Semantic Versioning. tools. (This is a regression introduced in quick-lint-js version 2.16.0.) Fix: [Git commit 3923f0df76d24b73d57f15eec61ab190ea048093][cmake-install-component-build-tools-patch] +* Windows: Code signing does not validate on some machines. [Workaround: follow + SSL.com's instructions for removing the expired "Certum Trusted Network CA" + certificate.](https://www.ssl.com/blogs/ssl-com-legacy-cross-signed-root-certificate-expiring-on-september-11-2023/#ftoc-heading-7) ### Added diff --git a/docs/CODE_SIGNING.md b/docs/CODE_SIGNING.md index 939e41871c..769ea88073 100644 --- a/docs/CODE_SIGNING.md +++ b/docs/CODE_SIGNING.md @@ -65,7 +65,6 @@ from a certificate authority (e.g. [SSL.com][]): `dist/certificates/quick-lint-js.crt`. 7. Augment .crt file with certificates root CAs: * `SSL_COM_ROOT_CERTIFICATION_AUTHORITY_RSA.crt` - * `Certum Trusted Network CA.pem` 8. [Update the macOS code signing requirements file.][apple-csreq] [SSL.com]: https://www.ssl.com/ From 2faaa97bab0ff41574b99bf33dc5d598cbb34883 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Thu, 2 Nov 2023 23:22:36 -0400 Subject: [PATCH 070/117] feat(dist): auto-update version numbers in more files Teach the version auto-update function to ignore lines not matching a regexp. Use this feature to change only the main "version" value in package.json files, only the "PackageVersion" value in winget YAML files, etc. --- dist/release.go | 116 ++++++++++++++++++++++++------------------- dist/release_test.go | 51 +++++++++++++++++++ 2 files changed, 116 insertions(+), 51 deletions(-) diff --git a/dist/release.go b/dist/release.go index 44edeb6449..91b60c56e0 100644 --- a/dist/release.go +++ b/dist/release.go @@ -58,20 +58,28 @@ var Steps []Step = []Step{ Step{ Title: "Update version number in files", Run: func() { - UpdateReleaseVersionsInFiles([]string{ - "Formula/quick-lint-js.rb", - "dist/arch/PKGBUILD-dev", - "dist/arch/PKGBUILD-git", - "dist/arch/PKGBUILD-release", - "dist/chocolatey/quick-lint-js.nuspec", - "dist/chocolatey/tools/VERIFICATION.txt", - "dist/debian/README.md", - "dist/npm/BUILDING.md", - "dist/npm/package.json", - "dist/scoop/quick-lint-js.template.json", - "dist/sign-release.go", - "plugin/vscode-lsp/README.md", - "plugin/vscode/BUILDING.md", + UpdateReleaseVersionsInFiles(map[string]string{ + "Formula/quick-lint-js.rb": "", + "dist/arch/PKGBUILD-dev": "", + "dist/arch/PKGBUILD-git": "", + "dist/arch/PKGBUILD-release": "", + "dist/chocolatey/quick-lint-js.nuspec": "", + "dist/chocolatey/tools/VERIFICATION.txt": "", + "dist/debian/README.md": "", + "dist/npm/BUILDING.md": "", + "dist/npm/package.json": "", + "dist/scoop/quick-lint-js.template.json": "", + "dist/sign-release.go": "", + "plugin/vscode-lsp/README.md": "", + "plugin/vscode/BUILDING.md": "", + + "dist/msix/AppxManifest.xml": "\\bVersion=", + "dist/winget/quick-lint.quick-lint-js.installer.template.yaml": "PackageVersion:", + "dist/winget/quick-lint.quick-lint-js.locale.en-US.template.yaml": "PackageVersion:", + "dist/winget/quick-lint.quick-lint-js.template.yaml": "PackageVersion:", + "plugin/vim/quick-lint-js.vim/doc/quick-lint-js.txt": "This plugin version is designed for quick-lint-js version", + "plugin/vscode-lsp/package.json": "\"version\":", + "plugin/vscode/package.json": "\"version\":", }) }, }, @@ -105,21 +113,6 @@ var Steps []Step = []Step{ }, }, - Step{ - Title: "Manually update version number and release date", - Run: func() { - fmt.Printf("Change these files containing version numbers:\n") - fmt.Printf("* dist/msix/AppxManifest.xml\n") - fmt.Printf("* dist/winget/quick-lint.quick-lint-js.installer.template.yaml\n") - fmt.Printf("* dist/winget/quick-lint.quick-lint-js.locale.en-US.template.yaml\n") - fmt.Printf("* dist/winget/quick-lint.quick-lint-js.template.yaml\n") - fmt.Printf("* plugin/vim/quick-lint-js.vim/doc/quick-lint-js.txt\n") - fmt.Printf("* plugin/vscode-lsp/package.json\n") - fmt.Printf("* plugin/vscode/package.json\n") - WaitForDone() - }, - }, - Step{ Title: "Re-generate man pages", Run: func() { @@ -507,10 +500,12 @@ func Stop() { os.Exit(0) } -func UpdateReleaseVersionsInFiles(paths []string) { +// Key: file path +// Value: UpdateReleaseVersionsOptions.LineMatchRegexp +func UpdateReleaseVersionsInFiles(pathToLineMatchRegexp map[string]string) { fileContents := make(map[string][]byte) - for _, path := range paths { + for path, _ := range pathToLineMatchRegexp { data, err := os.ReadFile(path) if err != nil { Stopf("failed to read file: %v", err) @@ -519,7 +514,17 @@ func UpdateReleaseVersionsInFiles(paths []string) { } for path, data := range fileContents { - fileContents[path] = UpdateReleaseVersions(data, path) + var err error + fileContents[path], err = UpdateReleaseVersions(UpdateReleaseVersionsOptions{ + FileContent: data, + PathForDebugging: path, + OldReleaseVersion: OldReleaseVersion, + NewReleaseVersion: ReleaseVersion, + LineMatchRegexp: pathToLineMatchRegexp[path], + }) + if err != nil { + Stopf("failed to update version numbers in %s: %v", path, err) + } } for path, data := range fileContents { @@ -530,30 +535,39 @@ func UpdateReleaseVersionsInFiles(paths []string) { } } -func UpdateReleaseVersions(fileContent []byte, pathForDebugging string) []byte { - oldVersion := []byte(OldReleaseVersion) - newVersion := []byte(ReleaseVersion) +type UpdateReleaseVersionsOptions struct { + FileContent []byte + PathForDebugging string + OldReleaseVersion string + NewReleaseVersion string + LineMatchRegexp string +} + +func UpdateReleaseVersions(options UpdateReleaseVersionsOptions) ([]byte, error) { + oldVersion := []byte(options.OldReleaseVersion) + newVersion := []byte(options.NewReleaseVersion) foundOldVersion := false - foundUnexpectedVersion := false - fileContent = ThreePartVersionRegexp.ReplaceAllFunc(fileContent, func(match []byte) []byte { - if bytes.Equal(match, oldVersion) { - foundOldVersion = true - return newVersion - } else { - foundUnexpectedVersion = true - log.Printf("error: found unexpected version number in %s: %s\n", pathForDebugging, string(match)) - return match - } + var foundUnexpectedVersion error = nil + fullLineMatchRegexp := regexp.MustCompile("(?m:^.*" + options.LineMatchRegexp + ".*$)") + newFileContent := fullLineMatchRegexp.ReplaceAllFunc(options.FileContent, func(lineMatch []byte) []byte { + return ThreePartVersionRegexp.ReplaceAllFunc(lineMatch, func(versionMatch []byte) []byte { + if bytes.Equal(versionMatch, oldVersion) { + foundOldVersion = true + return newVersion + } else { + foundUnexpectedVersion = fmt.Errorf("found unexpected version number in %s: %s", options.PathForDebugging, string(versionMatch)) + return versionMatch + } + }) }) - if !foundOldVersion { - log.Printf("error: failed to find old version number %s in %s\n", OldReleaseVersion, pathForDebugging) - os.Exit(1) + if foundUnexpectedVersion != nil { + return nil, foundUnexpectedVersion } - if foundUnexpectedVersion { - os.Exit(1) + if !foundOldVersion { + return nil, fmt.Errorf("failed to find old version number %s in %s", options.OldReleaseVersion, options.PathForDebugging) } - return fileContent + return newFileContent, nil } func GetCurrentCommitHash() string { diff --git a/dist/release_test.go b/dist/release_test.go index 5264d52b59..efb4931cb9 100644 --- a/dist/release_test.go +++ b/dist/release_test.go @@ -102,6 +102,57 @@ func TestUpdateDebianChangelog(t *testing.T) { }) } +func TestUpdateReleaseVersions(t *testing.T) { + t.Run("only version number", func(t *testing.T) { + updated, err := UpdateReleaseVersions(UpdateReleaseVersionsOptions{ + FileContent: []byte("hello, this is version 0.2.0 (beta)\n"), + PathForDebugging: "file.txt", + OldReleaseVersion: "0.2.0", + NewReleaseVersion: "0.3.0", + }) + Check(t, err) + AssertStringsEqual(t, string(updated), "hello, this is version 0.3.0 (beta)\n") + }) + + t.Run("missing version number", func(t *testing.T) { + _, err := UpdateReleaseVersions(UpdateReleaseVersionsOptions{ + FileContent: []byte("hello, world\n"), + PathForDebugging: "file.txt", + OldReleaseVersion: "0.2.0", + NewReleaseVersion: "0.3.0", + }) + if err == nil { + t.Fatalf("expected error") + } + AssertStringsEqual(t, err.Error(), "failed to find old version number 0.2.0 in file.txt") + }) + + t.Run("wrong version number", func(t *testing.T) { + _, err := UpdateReleaseVersions(UpdateReleaseVersionsOptions{ + FileContent: []byte("this feature was introduced in version 0.1.0\n"), + PathForDebugging: "file.txt", + OldReleaseVersion: "0.2.0", + NewReleaseVersion: "0.3.0", + }) + if err == nil { + t.Fatalf("expected error") + } + AssertStringsEqual(t, err.Error(), "found unexpected version number in file.txt: 0.1.0") + }) + + t.Run("ignores versions not matching line regexp", func(t *testing.T) { + updated, err := UpdateReleaseVersions(UpdateReleaseVersionsOptions{ + FileContent: []byte("0.1.0\nversion 0.2.0\n0.2.0\n0.2.0 version\n0.3.0\n"), + PathForDebugging: "file.txt", + OldReleaseVersion: "0.2.0", + NewReleaseVersion: "0.3.0", + LineMatchRegexp: "version", + }) + Check(t, err) + AssertStringsEqual(t, string(updated), "0.1.0\nversion 0.3.0\n0.2.0\n0.3.0 version\n0.3.0\n") + }) +} + // quick-lint-js finds bugs in JavaScript programs. // Copyright (C) 2020 Matthew "strager" Glazar // From 62e796866ca743e38d6ccc9ed1fd924ca0bab339 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Fri, 3 Nov 2023 00:12:13 -0400 Subject: [PATCH 071/117] feat(dist): auto-update changelog '## Unreleased' section Teach the release script to update the heading of the '## Unreleased' section in CHANGELOG.md and also add the 'Downloads' link. --- dist/release.go | 43 +++++++++++++++++++++++++++++++++++++++++-- dist/release_test.go | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/dist/release.go b/dist/release.go index 91b60c56e0..ccea5fdd8f 100644 --- a/dist/release.go +++ b/dist/release.go @@ -50,8 +50,13 @@ var Steps []Step = []Step{ Step{ Title: "Update release notes file", Run: func() { - fmt.Printf("Update the release notes file: docs/CHANGELOG.md\n") - WaitForDone() + changelogPath := "docs/CHANGELOG.md" + if err := UpdateUnreleasedChangelogFile(changelogPath, VersionFileInfo{ + VersionNumber: ReleaseVersion, + ReleaseDate: ReleaseDate, + }); err != nil { + Stopf("failed to update changelog file %s: %v", changelogPath, err) + } }, }, @@ -712,6 +717,40 @@ func UpdateDebianChangelog(changelogFilePath string, versionInfo VersionFileInfo return nil } +func UpdateUnreleasedChangelogFile(changelogFilePath string, versionInfo VersionFileInfo) error { + originalData, err := os.ReadFile(changelogFilePath) + if err != nil { + return err + } + + newData, err := UpdateUnreleasedChangelog(originalData, versionInfo) + if err != nil { + return err + } + + fileMode := fs.FileMode(0644) // Unused, because the file should already exist. + if err := os.WriteFile(changelogFilePath, newData, fileMode); err != nil { + return err + } + + return nil +} + +func UpdateUnreleasedChangelog(changelog []byte, versionInfo VersionFileInfo) ([]byte, error) { + unreleasedHeadingRegexp := regexp.MustCompile("(?m:^## Unreleased\n)") + newHeading := []byte(fmt.Sprintf( + "## %s (%s)\n\n[Downloads](https://c.quick-lint-js.com/releases/%s/)\n", + versionInfo.VersionNumber, + versionInfo.ReleaseDate.Format("2006-01-02"), + versionInfo.VersionNumber, + )) + newChangelog := unreleasedHeadingRegexp.ReplaceAllLiteral(changelog, newHeading) + if bytes.Equal(newChangelog, changelog) { + return nil, fmt.Errorf("could not find '## Unreleased' heading in changelog") + } + return newChangelog, nil +} + func EnsureEmptyDirectory(path string) { Retry: err := os.Mkdir(path, 0700) diff --git a/dist/release_test.go b/dist/release_test.go index efb4931cb9..d3b4c71065 100644 --- a/dist/release_test.go +++ b/dist/release_test.go @@ -102,6 +102,45 @@ func TestUpdateDebianChangelog(t *testing.T) { }) } +func TestUpdateUnreleasedChangelog(t *testing.T) { + t.Run("replaces unreleased heading and adds downlods link", func(t *testing.T) { + losAngeles, err := time.LoadLocation("America/Los_Angeles") + Check(t, err) + + newChangelog, err := UpdateUnreleasedChangelog( + []byte("## Unreleased\n\n## 1.0.0 (2022-01-01)\n"), + VersionFileInfo{ + VersionNumber: "2.0.0", + ReleaseDate: time.Date(2022, 2, 8, 16, 56, 37, 0, losAngeles), + }, + ) + Check(t, err) + AssertStringsEqual(t, string(newChangelog), + "## 2.0.0 (2022-02-08)\n"+ + "\n"+ + "[Downloads](https://c.quick-lint-js.com/releases/2.0.0/)\n"+ + "\n"+ + "## 1.0.0 (2022-01-01)\n") + }) + + t.Run("fails if no unreleased heading", func(t *testing.T) { + losAngeles, err := time.LoadLocation("America/Los_Angeles") + Check(t, err) + + _, err = UpdateUnreleasedChangelog( + []byte("## 1.0.0 (2022-01-01)\n\n"), + VersionFileInfo{ + VersionNumber: "2.0.0", + ReleaseDate: time.Date(2022, 2, 8, 16, 56, 37, 0, losAngeles), + }, + ) + if err == nil { + t.Fatalf("expected error") + } + AssertStringsEqual(t, err.Error(), "could not find '## Unreleased' heading in changelog") + }) +} + func TestUpdateReleaseVersions(t *testing.T) { t.Run("only version number", func(t *testing.T) { updated, err := UpdateReleaseVersions(UpdateReleaseVersionsOptions{ From 2ef4ad3b8c266bddb813bac988bb2d18146b5a8d Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Fri, 3 Nov 2023 00:39:31 -0400 Subject: [PATCH 072/117] feat(dist): improve error message if shell command fails If release.go runs an external command, it reports a failure but does not mention the command that failed. This makes it harder to figure out what went wrong. Make release.go print the failed command. Also, make a helper function to shorten calling code. --- dist/release.go | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/dist/release.go b/dist/release.go index ccea5fdd8f..84d1cc65a6 100644 --- a/dist/release.go +++ b/dist/release.go @@ -121,20 +121,14 @@ var Steps []Step = []Step{ Step{ Title: "Re-generate man pages", Run: func() { - cmd := exec.Command("./docs/man/generate-man-pages") - if err := cmd.Run(); err != nil { - Stopf("failed to generate man pages: %v", err) - } + RunCommandOrStop("./docs/man/generate-man-pages") }, }, Step{ Title: "Re-generate Vim tags", Run: func() { - cmd := exec.Command("./tools/generate-vim-tags") - if err := cmd.Run(); err != nil { - Stopf("failed to generate Vim tags: %v", err) - } + RunCommandOrStop("./tools/generate-vim-tags") }, }, @@ -201,31 +195,25 @@ var Steps []Step = []Step{ Step{ Title: "Create a Scoop manifest", Run: func() { - cmd := exec.Command( + RunCommandOrStop( "go", "run", "./dist/scoop/make-manifest.go", "-BaseURI", fmt.Sprintf("https://c.quick-lint-js.com/releases/%s/", ReleaseVersion), "-x86-ZIP", "signed-builds/manual/windows-x86.zip", "-x64-ZIP", "signed-builds/manual/windows.zip", "-Out", "signed-builds/scoop/quick-lint-js.json", ) - if err := cmd.Run(); err != nil { - Stopf("failed to create Scoop manifest: %v", err) - } }, }, Step{ Title: "Create a winget manifest", Run: func() { - cmd := exec.Command( + RunCommandOrStop( "go", "run", "./dist/winget/make-manifests.go", "-BaseURI", fmt.Sprintf("https://c.quick-lint-js.com/releases/%s/", ReleaseVersion), "-MSIX", "signed-builds/windows/quick-lint-js.msix", "-OutDir", "signed-builds/winget/", ) - if err := cmd.Run(); err != nil { - Stopf("failed to create winget manifest: %v", err) - } }, }, @@ -575,6 +563,26 @@ func UpdateReleaseVersions(options UpdateReleaseVersionsOptions) ([]byte, error) return newFileContent, nil } +func RunCommandOrStop(name string, arg ...string) { + cmd := exec.Command(name, arg...) + if err := cmd.Run(); err != nil { + commandString := CommandToShell(cmd.Args) + Stopf("failed to run command:\n$ %s\n%v", commandString, err) + } +} + +// Escapes the command for POSIX-style shells. +func CommandToShell(args []string) string { + escape := func(arg string) string { + return "'" + strings.ReplaceAll(arg, "'", "'\\''") + "'" + } + escapedArgs := make([]string, len(args)) + for i, arg := range args { + escapedArgs[i] = escape(arg) + } + return strings.Join(escapedArgs, " ") +} + func GetCurrentCommitHash() string { commitHash, gitErr := GetCurrentGitCommitHash() if gitErr == nil { From 58585e13d9e23009801931b6e0f9f0b1a520a884 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Fri, 3 Nov 2023 00:43:33 -0400 Subject: [PATCH 073/117] refactor(dist): avoid using wildcard path for npm/ovsx/vsce publish For some commands in release.go, print the expected path rather than relying on the shell to expand a glob. This will make future changes easier. --- dist/release.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dist/release.go b/dist/release.go index 84d1cc65a6..aa1df07f29 100644 --- a/dist/release.go +++ b/dist/release.go @@ -239,7 +239,7 @@ var Steps []Step = []Step{ Title: "Publish the Visual Studio Code extension to the Marketplace", Run: func() { fmt.Printf("With the `vscode/quick-lint-js-*.vsix` artifact:\n") - fmt.Printf("$ npx vsce publish --packagePath signed-builds/vscode/quick-lint-js-*.vsix\n") + fmt.Printf("$ npx vsce publish --packagePath signed-builds/vscode/quick-lint-js-%s.vsix\n", ReleaseVersion) WaitForDone() }, }, @@ -248,7 +248,7 @@ var Steps []Step = []Step{ Title: "Publish the Visual Studio Code extension to the Open VSX Registry", Run: func() { fmt.Printf("With the `vscode/quick-lint-js-*.vsix` artifact:\n") - fmt.Printf("$ npx ovsx publish signed-builds/vscode/quick-lint-js-*.vsix --pat YOUR_ACCESS_TOKEN\n") + fmt.Printf("$ npx ovsx publish signed-builds/vscode/quick-lint-js-%s.vsix --pat YOUR_ACCESS_TOKEN\n", ReleaseVersion) WaitForDone() }, }, @@ -257,7 +257,7 @@ var Steps []Step = []Step{ Title: "Publish to npm", Run: func() { fmt.Printf("With the `npm/quick-lint-js-*.tgz` artifact:\n") - fmt.Printf("$ npm publish signed-builds/npm/quick-lint-js-*.tgz\n") + fmt.Printf("$ npm publish signed-builds/npm/quick-lint-js-%s.tgz\n", ReleaseVersion) WaitForDone() }, }, From 9ca3b005a1f36823fb41b344a80a089f022cab70 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Fri, 3 Nov 2023 00:47:14 -0400 Subject: [PATCH 074/117] feat(dist): automatically run most shell commands Instead of forcing the user to copy-paste shell commands, run the commands on the user's behalf. --- dist/release.go | 59 +++++++++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/dist/release.go b/dist/release.go index aa1df07f29..3a80e09558 100644 --- a/dist/release.go +++ b/dist/release.go @@ -170,9 +170,12 @@ var Steps []Step = []Step{ if ReleaseCommitHash == "" { Stopf("missing -ReleaseCommitHash\n") } - fmt.Printf("Download the build artifacts from the artifact server:\n") - fmt.Printf("$ rsync -av github-ci@c.quick-lint-js.com:/var/www/c.quick-lint-js.com/builds/%s/ builds/\n", ReleaseCommitHash) - WaitForDone() + RunCommandOrStop( + "rsync", + "-av", + fmt.Sprintf("github-ci@c.quick-lint-js.com:/var/www/c.quick-lint-js.com/builds/%s/", ReleaseCommitHash), + "builds/", + ) }, }, @@ -186,9 +189,15 @@ var Steps []Step = []Step{ Step{ Title: "Sign the build artifacts", Run: func() { - fmt.Printf("Sign the build artifacts:\n") - fmt.Printf("$ go run dist/sign-release.go dist/deep-hasher.go dist/appx.go -RelicConfig=dist/certificates/relic-config.yaml builds/ signed-builds/\n") - WaitForDone() + RunCommandOrStop( + "go", "run", + "dist/sign-release.go", + "dist/deep-hasher.go", + "dist/appx.go", + "-RelicConfig=dist/certificates/relic-config.yaml", + "builds/", + "signed-builds/", + ) }, }, @@ -220,27 +229,34 @@ var Steps []Step = []Step{ Step{ Title: "Upload the signed build artifacts", Run: func() { - fmt.Printf("Upload the signed build artifacts to the artifact server:\n") - fmt.Printf("$ rsync -av signed-builds/ github-ci@c.quick-lint-js.com:/var/www/c.quick-lint-js.com/releases/%s/\n", ReleaseVersion) - WaitForDone() + RunCommandOrStop( + "rsync", + "-av", + "signed-builds/", + fmt.Sprintf("github-ci@c.quick-lint-js.com:/var/www/c.quick-lint-js.com/releases/%s/", ReleaseVersion), + ) }, }, Step{ Title: "Update `latest` symlink", Run: func() { - fmt.Printf("Update the `latest` symlink on the artifact server:\n") - fmt.Printf("$ ssh github-ci@c.quick-lint-js.com \"ln --force --no-dereference --symbolic %s /var/www/c.quick-lint-js.com/releases/latest\"\n", ReleaseVersion) - WaitForDone() + RunCommandOrStop( + "ssh", + "github-ci@c.quick-lint-js.com", + fmt.Sprintf("ln --force --no-dereference --symbolic %s /var/www/c.quick-lint-js.com/releases/latest", ReleaseVersion), + ) }, }, Step{ Title: "Publish the Visual Studio Code extension to the Marketplace", Run: func() { - fmt.Printf("With the `vscode/quick-lint-js-*.vsix` artifact:\n") - fmt.Printf("$ npx vsce publish --packagePath signed-builds/vscode/quick-lint-js-%s.vsix\n", ReleaseVersion) - WaitForDone() + RunCommandOrStop( + "npx", "vsce", + "publish", + "--packagePath", fmt.Sprintf("signed-builds/vscode/quick-lint-js-%s.vsix", ReleaseVersion), + ) }, }, @@ -256,17 +272,18 @@ var Steps []Step = []Step{ Step{ Title: "Publish to npm", Run: func() { - fmt.Printf("With the `npm/quick-lint-js-*.tgz` artifact:\n") - fmt.Printf("$ npm publish signed-builds/npm/quick-lint-js-%s.tgz\n", ReleaseVersion) - WaitForDone() + RunCommandOrStop( + "npm", + "publish", + fmt.Sprintf("signed-builds/npm/quick-lint-js-%s.tgz", ReleaseVersion), + ) }, }, Step{ Title: "Publish Debian packages", Run: func() { - fmt.Printf("Run the `dist/debian/sync-releases-to-apt` script.\n") - WaitForDone() + RunCommandOrStop("./dist/debian/sync-releases-to-apt") }, }, @@ -276,7 +293,7 @@ var Steps []Step = []Step{ if ReleaseCommitHash == "" { Stopf("missing -ReleaseCommitHash\n") } - fmt.Printf("Publish the website: Run `./website/tools/deploy.sh %s`.\n", ReleaseCommitHash) + RunCommandOrStop("./website/tools/deploy.sh", ReleaseCommitHash) WaitForDone() }, }, From 684ddb8eb7beea137c95dca580640c35f669db3f Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Fri, 3 Nov 2023 17:42:42 -0400 Subject: [PATCH 075/117] chore: prepare for 2.18.0 release --- Formula/quick-lint-js.rb | 2 +- dist/arch/PKGBUILD-dev | 2 +- dist/arch/PKGBUILD-git | 2 +- dist/arch/PKGBUILD-release | 2 +- dist/chocolatey/quick-lint-js.nuspec | 2 +- dist/chocolatey/tools/VERIFICATION.txt | 4 +-- dist/debian/README.md | 4 +-- dist/debian/debian/changelog | 6 ++++ dist/debian/debian/changelog-bionic | 6 ++++ dist/msix/AppxManifest.xml | 2 +- dist/npm/BUILDING.md | 8 ++--- dist/npm/package.json | 2 +- dist/scoop/quick-lint-js.template.json | 2 +- dist/sign-release.go | 36 +++++++++---------- ...lint.quick-lint-js.installer.template.yaml | 2 +- ...t.quick-lint-js.locale.en-US.template.yaml | 2 +- .../quick-lint.quick-lint-js.template.yaml | 2 +- docs/CHANGELOG.md | 4 ++- docs/man/quick-lint-js-lsp.8 | 4 +-- docs/man/quick-lint-js.1 | 4 +-- docs/man/quick-lint-js.config.5 | 4 +-- .../quick-lint-js.vim/doc/quick-lint-js.txt | 2 +- plugin/vscode-lsp/README.md | 2 +- plugin/vscode-lsp/package.json | 2 +- plugin/vscode/BUILDING.md | 2 +- plugin/vscode/package.json | 2 +- version | 4 +-- 27 files changed, 65 insertions(+), 51 deletions(-) diff --git a/Formula/quick-lint-js.rb b/Formula/quick-lint-js.rb index 03c80e0f6b..5b0cf89013 100644 --- a/Formula/quick-lint-js.rb +++ b/Formula/quick-lint-js.rb @@ -4,7 +4,7 @@ class QuickLintJs < Formula desc "Find bugs in your JavaScript code" homepage "https://quick-lint-js.com/" - url "https://c.quick-lint-js.com/releases/2.17.0/source/quick-lint-js-2.17.0.tar.gz" + url "https://c.quick-lint-js.com/releases/2.18.0/source/quick-lint-js-2.18.0.tar.gz" license "GPL-3.0-or-later" head "https://github.com/quick-lint/quick-lint-js.git", branch: "master" diff --git a/dist/arch/PKGBUILD-dev b/dist/arch/PKGBUILD-dev index aba4cb9710..ba0e33e6b9 100644 --- a/dist/arch/PKGBUILD-dev +++ b/dist/arch/PKGBUILD-dev @@ -5,7 +5,7 @@ # Contributor: Shivam Mehta pkgname=quick-lint-js-dev -pkgver=2.17.0 +pkgver=2.18.0 pkgrel=1 pkgdesc="Find bugs in JavaScript programs" arch=(aarch64 arm armv6h armv7h i686 pentium4 x86_64) diff --git a/dist/arch/PKGBUILD-git b/dist/arch/PKGBUILD-git index 296dac13ef..e9b136caad 100644 --- a/dist/arch/PKGBUILD-git +++ b/dist/arch/PKGBUILD-git @@ -5,7 +5,7 @@ # Contributor: Shivam Mehta pkgname=quick-lint-js-git -pkgver=2.17.0 +pkgver=2.18.0 pkgrel=1 pkgdesc="Find bugs in JavaScript programs" arch=(aarch64 arm armv6h armv7h i686 pentium4 x86_64) diff --git a/dist/arch/PKGBUILD-release b/dist/arch/PKGBUILD-release index 15264260fe..b2ec2a2248 100644 --- a/dist/arch/PKGBUILD-release +++ b/dist/arch/PKGBUILD-release @@ -5,7 +5,7 @@ # Contributor: Shivam Mehta pkgname=quick-lint-js -pkgver=2.17.0 +pkgver=2.18.0 pkgrel=1 pkgdesc="Find bugs in JavaScript programs" arch=(aarch64 arm armv6h armv7h i686 pentium4 x86_64) diff --git a/dist/chocolatey/quick-lint-js.nuspec b/dist/chocolatey/quick-lint-js.nuspec index 6cfef8b5f3..d67ae2ebf1 100644 --- a/dist/chocolatey/quick-lint-js.nuspec +++ b/dist/chocolatey/quick-lint-js.nuspec @@ -3,7 +3,7 @@ quick-lint-js - 2.17.0 + 2.18.0 quick-lint-js (Install) Matthew "strager" Glazar et al Matthew "strager" Glazar diff --git a/dist/chocolatey/tools/VERIFICATION.txt b/dist/chocolatey/tools/VERIFICATION.txt index 6d60afc94e..eaf65e91c6 100644 --- a/dist/chocolatey/tools/VERIFICATION.txt +++ b/dist/chocolatey/tools/VERIFICATION.txt @@ -5,5 +5,5 @@ in verifying that this package's contents are trustworthy. I, Matthew "strager" Glazar, am the software vendor who packaged this software for Chocolatey. -Upstream SHA256 checksums: https://c.quick-lint-js.com/releases/2.17.0/SHA256SUMS -GPG signature: https://c.quick-lint-js.com/releases/2.17.0/SHA256SUMS.asc +Upstream SHA256 checksums: https://c.quick-lint-js.com/releases/2.18.0/SHA256SUMS +GPG signature: https://c.quick-lint-js.com/releases/2.18.0/SHA256SUMS.asc diff --git a/dist/debian/README.md b/dist/debian/README.md index ef41e7dbcb..bde4bc8bb9 100644 --- a/dist/debian/README.md +++ b/dist/debian/README.md @@ -48,7 +48,7 @@ To test `asgen-config.json` or metadata changes locally: * Change `MediaBaseUrl` to `"http://localhost:8069/appstream/export/media/"`. * Change `HtmlBaseUrl` to `"http://localhost:8069/appstream/export/html/"`. 5. Create a directory `debian/pool/`. -6. Copy `dist/debian/*2.17.0*` (built by the [Building](#Building) instructions +6. Copy `dist/debian/*2.18.0*` (built by the [Building](#Building) instructions above) into the `debian/pool/` directory. 7. Run `./dist/debian/update-repository path/to/debian`. 8. Start an HTTP server in the `debian` directory. For example: @@ -73,7 +73,7 @@ To release to downstream Debian, we [ship a source package to Debian mentors][]. 1. Download a signed release .tar.gz and .tar.gz.asc (e.g. from ). 2. Create a package using `package.sh`: - `./dist/debian/package.sh --output-directory debian-package --orig path/to/quick-lint-js-2.17.0.tar.gz --sign` + `./dist/debian/package.sh --output-directory debian-package --orig path/to/quick-lint-js-2.18.0.tar.gz --sign` * NOTE: `package.sh` will use the `debian` sources from your checkout (`./dist/debian/debian/`), not from the signed release tarball. 3. Upload the package: `dput mentors debian-package/quick-lint-js_2.4.2-1_source.changes` diff --git a/dist/debian/debian/changelog b/dist/debian/debian/changelog index 2229591df1..d2a8c62389 100644 --- a/dist/debian/debian/changelog +++ b/dist/debian/debian/changelog @@ -1,3 +1,9 @@ +quick-lint-js (2.18.0-1) unstable; urgency=medium + + * New release. + + -- Matthew "strager" Glazar Fri, 03 Nov 2023 17:41:59 -0400 + quick-lint-js (2.17.0-1) unstable; urgency=medium * New release. diff --git a/dist/debian/debian/changelog-bionic b/dist/debian/debian/changelog-bionic index dc2cac96e9..0b21ddba21 100644 --- a/dist/debian/debian/changelog-bionic +++ b/dist/debian/debian/changelog-bionic @@ -1,3 +1,9 @@ +quick-lint-js (2.18.0-1) unstable; urgency=medium + + * New release. + + -- Matthew "strager" Glazar Fri, 03 Nov 2023 17:41:59 -0400 + quick-lint-js (2.17.0-1) unstable; urgency=medium * New release. diff --git a/dist/msix/AppxManifest.xml b/dist/msix/AppxManifest.xml index 43673dc2fe..b9b66f44c6 100644 --- a/dist/msix/AppxManifest.xml +++ b/dist/msix/AppxManifest.xml @@ -10,7 +10,7 @@ + Version="2.18.0.0" /> quick-lint-js diff --git a/dist/npm/BUILDING.md b/dist/npm/BUILDING.md index 969fa8437f..72453cd98d 100644 --- a/dist/npm/BUILDING.md +++ b/dist/npm/BUILDING.md @@ -8,12 +8,12 @@ To build this quick-lint-js npm package: * `dist/npm/linux-x64/bin/quick-lint-js`: Linux x86_64 executable * `dist/npm/darwin-x64/bin/quick-lint-js`: macOS 64-bit Intel executable * `dist/npm/win32-x64/bin/quick-lint-js.exe`: Windows x64 executable -3. Run `npm pack .` to create `quick-lint-js-2.17.0.tgz`. +3. Run `npm pack .` to create `quick-lint-js-2.18.0.tgz`. To install system-wide, run -`npm install --global --unsafe-perm ./quick-lint-js-2.17.0.tgz`. +`npm install --global --unsafe-perm ./quick-lint-js-2.18.0.tgz`. To install within an existing Node.js project, run -`npm install /path/to/quick-lint-js-2.17.0.tgz`. +`npm install /path/to/quick-lint-js-2.18.0.tgz`. -To publish to npm's registry, run `npm publish ./quick-lint-js-2.17.0.tgz`. +To publish to npm's registry, run `npm publish ./quick-lint-js-2.18.0.tgz`. diff --git a/dist/npm/package.json b/dist/npm/package.json index 3f3beaabac..436814c110 100644 --- a/dist/npm/package.json +++ b/dist/npm/package.json @@ -1,7 +1,7 @@ { "name": "quick-lint-js", "description": "Find bugs in your JavaScript code", - "version": "2.17.0", + "version": "2.18.0", "keywords": [ "quick", "lint", diff --git a/dist/scoop/quick-lint-js.template.json b/dist/scoop/quick-lint-js.template.json index 9754210702..23f76ab814 100644 --- a/dist/scoop/quick-lint-js.template.json +++ b/dist/scoop/quick-lint-js.template.json @@ -1,5 +1,5 @@ { - "version": "2.17.0", + "version": "2.18.0", "description": "Find bugs in JavaScript programs.", "homepage": "https://quick-lint-js.com/", "license": "GPL-3.0-or-later,MIT,BSL-1.0,Apache-2.0,ZPL-2.1,Public Domain,Unknown,ISC,BSD-2-Clause,MIT-CMU,LGPL-2.1-or-later,GPL-2.0-or-later,BSD-3-Clause", diff --git a/dist/sign-release.go b/dist/sign-release.go index 974429390a..e12182a82a 100644 --- a/dist/sign-release.go +++ b/dist/sign-release.go @@ -115,7 +115,7 @@ func main() { log.Fatal(err) } - sourceTarballPath := filepath.Join(destinationDir, "source/quick-lint-js-2.17.0.tar.gz") + sourceTarballPath := filepath.Join(destinationDir, "source/quick-lint-js-2.18.0.tar.gz") log.Printf("signing: %s\n", sourceTarballPath) if err := RelicFile(sourceTarballPath, sourceTarballPath+".asc", RelicSignPGP); err != nil { log.Fatal(err) @@ -160,23 +160,23 @@ var filesToTransform map[DeepPath]FileTransformType = map[DeepPath]FileTransform NewDeepPath2("manual/windows-arm.zip", "bin/quick-lint-js.exe"): RelicWindows, NewDeepPath2("manual/windows-x86.zip", "bin/quick-lint-js.exe"): RelicWindows, NewDeepPath2("manual/windows.zip", "bin/quick-lint-js.exe"): RelicWindows, - NewDeepPath2("npm/quick-lint-js-2.17.0.tgz", "package/darwin-arm64/bin/quick-lint-js"): RelicApple, - NewDeepPath2("npm/quick-lint-js-2.17.0.tgz", "package/darwin-x64/bin/quick-lint-js"): RelicApple, - NewDeepPath2("npm/quick-lint-js-2.17.0.tgz", "package/linux-arm/bin/quick-lint-js"): RelicPGP, - NewDeepPath2("npm/quick-lint-js-2.17.0.tgz", "package/linux-arm64/bin/quick-lint-js"): RelicPGP, - NewDeepPath2("npm/quick-lint-js-2.17.0.tgz", "package/linux-x64/bin/quick-lint-js"): RelicPGP, - NewDeepPath2("npm/quick-lint-js-2.17.0.tgz", "package/win32-arm64/bin/quick-lint-js.exe"): RelicWindows, - NewDeepPath2("npm/quick-lint-js-2.17.0.tgz", "package/win32-ia32/bin/quick-lint-js.exe"): RelicWindows, - NewDeepPath2("npm/quick-lint-js-2.17.0.tgz", "package/win32-x64/bin/quick-lint-js.exe"): RelicWindows, - NewDeepPath2("vscode/quick-lint-js-2.17.0.vsix", "extension/dist/quick-lint-js-vscode-node_darwin-arm64.node"): RelicApple, - NewDeepPath2("vscode/quick-lint-js-2.17.0.vsix", "extension/dist/quick-lint-js-vscode-node_darwin-x64.node"): RelicApple, - NewDeepPath2("vscode/quick-lint-js-2.17.0.vsix", "extension/dist/quick-lint-js-vscode-node_linux-arm.node"): RelicPGP, - NewDeepPath2("vscode/quick-lint-js-2.17.0.vsix", "extension/dist/quick-lint-js-vscode-node_linux-arm64.node"): RelicPGP, - NewDeepPath2("vscode/quick-lint-js-2.17.0.vsix", "extension/dist/quick-lint-js-vscode-node_linux-x64.node"): RelicPGP, - NewDeepPath2("vscode/quick-lint-js-2.17.0.vsix", "extension/dist/quick-lint-js-vscode-node_win32-arm.node"): RelicWindows, - NewDeepPath2("vscode/quick-lint-js-2.17.0.vsix", "extension/dist/quick-lint-js-vscode-node_win32-arm64.node"): RelicWindows, - NewDeepPath2("vscode/quick-lint-js-2.17.0.vsix", "extension/dist/quick-lint-js-vscode-node_win32-ia32.node"): RelicWindows, - NewDeepPath2("vscode/quick-lint-js-2.17.0.vsix", "extension/dist/quick-lint-js-vscode-node_win32-x64.node"): RelicWindows, + NewDeepPath2("npm/quick-lint-js-2.18.0.tgz", "package/darwin-arm64/bin/quick-lint-js"): RelicApple, + NewDeepPath2("npm/quick-lint-js-2.18.0.tgz", "package/darwin-x64/bin/quick-lint-js"): RelicApple, + NewDeepPath2("npm/quick-lint-js-2.18.0.tgz", "package/linux-arm/bin/quick-lint-js"): RelicPGP, + NewDeepPath2("npm/quick-lint-js-2.18.0.tgz", "package/linux-arm64/bin/quick-lint-js"): RelicPGP, + NewDeepPath2("npm/quick-lint-js-2.18.0.tgz", "package/linux-x64/bin/quick-lint-js"): RelicPGP, + NewDeepPath2("npm/quick-lint-js-2.18.0.tgz", "package/win32-arm64/bin/quick-lint-js.exe"): RelicWindows, + NewDeepPath2("npm/quick-lint-js-2.18.0.tgz", "package/win32-ia32/bin/quick-lint-js.exe"): RelicWindows, + NewDeepPath2("npm/quick-lint-js-2.18.0.tgz", "package/win32-x64/bin/quick-lint-js.exe"): RelicWindows, + NewDeepPath2("vscode/quick-lint-js-2.18.0.vsix", "extension/dist/quick-lint-js-vscode-node_darwin-arm64.node"): RelicApple, + NewDeepPath2("vscode/quick-lint-js-2.18.0.vsix", "extension/dist/quick-lint-js-vscode-node_darwin-x64.node"): RelicApple, + NewDeepPath2("vscode/quick-lint-js-2.18.0.vsix", "extension/dist/quick-lint-js-vscode-node_linux-arm.node"): RelicPGP, + NewDeepPath2("vscode/quick-lint-js-2.18.0.vsix", "extension/dist/quick-lint-js-vscode-node_linux-arm64.node"): RelicPGP, + NewDeepPath2("vscode/quick-lint-js-2.18.0.vsix", "extension/dist/quick-lint-js-vscode-node_linux-x64.node"): RelicPGP, + NewDeepPath2("vscode/quick-lint-js-2.18.0.vsix", "extension/dist/quick-lint-js-vscode-node_win32-arm.node"): RelicWindows, + NewDeepPath2("vscode/quick-lint-js-2.18.0.vsix", "extension/dist/quick-lint-js-vscode-node_win32-arm64.node"): RelicWindows, + NewDeepPath2("vscode/quick-lint-js-2.18.0.vsix", "extension/dist/quick-lint-js-vscode-node_win32-ia32.node"): RelicWindows, + NewDeepPath2("vscode/quick-lint-js-2.18.0.vsix", "extension/dist/quick-lint-js-vscode-node_win32-x64.node"): RelicWindows, NewDeepPath("windows/quick-lint-js.msix"): RelicWindows, NewDeepPath2("windows/quick-lint-js.msix", "quick-lint-js.exe"): RelicWindows, } diff --git a/dist/winget/quick-lint.quick-lint-js.installer.template.yaml b/dist/winget/quick-lint.quick-lint-js.installer.template.yaml index c16faaed9e..f4f8a95193 100644 --- a/dist/winget/quick-lint.quick-lint-js.installer.template.yaml +++ b/dist/winget/quick-lint.quick-lint-js.installer.template.yaml @@ -5,7 +5,7 @@ # http://creativecommons.org/publicdomain/zero/1.0/ PackageIdentifier: quick-lint.quick-lint-js -PackageVersion: 2.17.0.0 +PackageVersion: 2.18.0.0 Installers: - InstallerUrl: {{ .BaseURI }}windows/quick-lint-js.msix diff --git a/dist/winget/quick-lint.quick-lint-js.locale.en-US.template.yaml b/dist/winget/quick-lint.quick-lint-js.locale.en-US.template.yaml index 8dfdf082c9..086e5a12e3 100644 --- a/dist/winget/quick-lint.quick-lint-js.locale.en-US.template.yaml +++ b/dist/winget/quick-lint.quick-lint-js.locale.en-US.template.yaml @@ -5,7 +5,7 @@ # http://creativecommons.org/publicdomain/zero/1.0/ PackageIdentifier: quick-lint.quick-lint-js -PackageVersion: 2.17.0.0 +PackageVersion: 2.18.0.0 PackageLocale: en-US PackageName: quick-lint-js diff --git a/dist/winget/quick-lint.quick-lint-js.template.yaml b/dist/winget/quick-lint.quick-lint-js.template.yaml index 472b539456..27f15bfd26 100644 --- a/dist/winget/quick-lint.quick-lint-js.template.yaml +++ b/dist/winget/quick-lint.quick-lint-js.template.yaml @@ -5,7 +5,7 @@ # http://creativecommons.org/publicdomain/zero/1.0/ PackageIdentifier: quick-lint.quick-lint-js -PackageVersion: 2.17.0.0 +PackageVersion: 2.18.0.0 DefaultLocale: en-US ManifestType: version diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 13e2b794b7..4795bd5e97 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -6,7 +6,9 @@ based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). quick-lint-js' version numbers are arbitrary. quick-lint-js does *not* adhere to Semantic Versioning. -## Unreleased +## 2.18.0 (2023-11-03) + +[Downloads](https://c.quick-lint-js.com/releases/2.18.0/) ### Added diff --git a/docs/man/quick-lint-js-lsp.8 b/docs/man/quick-lint-js-lsp.8 index 67254da484..cb0ee6738c 100644 --- a/docs/man/quick-lint-js-lsp.8 +++ b/docs/man/quick-lint-js-lsp.8 @@ -12,10 +12,10 @@ .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.17 .\" Manual: \ \& -.\" Source: quick-lint-js version  2.17.0 +.\" Source: quick-lint-js version  2.18.0 .\" Language: English .\" -.TH "QUICK\-LINT\-JS\-LSP" "8" "" "quick\-lint\-js version  2.17.0" "\ \&" +.TH "QUICK\-LINT\-JS\-LSP" "8" "" "quick\-lint\-js version  2.18.0" "\ \&" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/docs/man/quick-lint-js.1 b/docs/man/quick-lint-js.1 index e67fae9840..7dd400bdb1 100644 --- a/docs/man/quick-lint-js.1 +++ b/docs/man/quick-lint-js.1 @@ -12,10 +12,10 @@ .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.17 .\" Manual: \ \& -.\" Source: quick-lint-js version  2.17.0 +.\" Source: quick-lint-js version  2.18.0 .\" Language: English .\" -.TH "QUICK\-LINT\-JS" "1" "" "quick\-lint\-js version  2.17.0" "\ \&" +.TH "QUICK\-LINT\-JS" "1" "" "quick\-lint\-js version  2.18.0" "\ \&" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/docs/man/quick-lint-js.config.5 b/docs/man/quick-lint-js.config.5 index f747923563..75198f04f6 100644 --- a/docs/man/quick-lint-js.config.5 +++ b/docs/man/quick-lint-js.config.5 @@ -12,10 +12,10 @@ .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.17 .\" Manual: \ \& -.\" Source: quick-lint-js version  2.17.0 +.\" Source: quick-lint-js version  2.18.0 .\" Language: English .\" -.TH "QUICK\-LINT\-JS.CONFIG" "5" "" "quick\-lint\-js version  2.17.0" "\ \&" +.TH "QUICK\-LINT\-JS.CONFIG" "5" "" "quick\-lint\-js version  2.18.0" "\ \&" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/plugin/vim/quick-lint-js.vim/doc/quick-lint-js.txt b/plugin/vim/quick-lint-js.vim/doc/quick-lint-js.txt index b8b8d5dccd..7769d436b8 100644 --- a/plugin/vim/quick-lint-js.vim/doc/quick-lint-js.txt +++ b/plugin/vim/quick-lint-js.vim/doc/quick-lint-js.txt @@ -7,7 +7,7 @@ This file contains instructions for installing and using the quick-lint-js plugin. -This plugin version is designed for quick-lint-js version 2.17.0. Older or +This plugin version is designed for quick-lint-js version 2.18.0. Older or newer versions might or might not work. 1. Installing quick-lint-js |quick-lint-js-app-install| diff --git a/plugin/vscode-lsp/README.md b/plugin/vscode-lsp/README.md index 4aa8f7e72a..ed75f577ce 100644 --- a/plugin/vscode-lsp/README.md +++ b/plugin/vscode-lsp/README.md @@ -10,6 +10,6 @@ To build the extension, run the following commands: $ yarn $ ./node_modules/.bin/vsce package -This will create a file called `quick-lint-js-lsp-2.17.0.vsix`. +This will create a file called `quick-lint-js-lsp-2.18.0.vsix`. [VisualStudioCode]: https://code.visualstudio.com/ diff --git a/plugin/vscode-lsp/package.json b/plugin/vscode-lsp/package.json index 85a18f878c..65248805c4 100644 --- a/plugin/vscode-lsp/package.json +++ b/plugin/vscode-lsp/package.json @@ -2,7 +2,7 @@ "name": "quick-lint-js-lsp", "description": "Find JavaScript bugs with quick-lint-js (LSP version, not recommended)", "publisher": "quick-lint", - "version": "2.17.0", + "version": "2.18.0", "engines": { "vscode": "^1.43.0" }, diff --git a/plugin/vscode/BUILDING.md b/plugin/vscode/BUILDING.md index b2bf5b1a74..c3ba2ccf3b 100644 --- a/plugin/vscode/BUILDING.md +++ b/plugin/vscode/BUILDING.md @@ -15,7 +15,7 @@ CMake][build-quick-lint-js] with `-DQUICK_LINT_JS_ENABLE_VSCODE=YES $ # Copy files into the VS Code extension: $ cmake --install build --component vscode-node --prefix plugin/vscode -Finally, run the following commands to create `quick-lint-js-2.17.0.vsix`: +Finally, run the following commands to create `quick-lint-js-2.18.0.vsix`: $ cd plugin/vscode/ # Navigate to this directory. $ yarn diff --git a/plugin/vscode/package.json b/plugin/vscode/package.json index 1a96e84406..a01e210a95 100644 --- a/plugin/vscode/package.json +++ b/plugin/vscode/package.json @@ -2,7 +2,7 @@ "name": "quick-lint-js", "description": "Find JavaScript bugs with quick-lint-js", "publisher": "quick-lint", - "version": "2.17.0", + "version": "2.18.0", "license": "SEE LICENSE IN LICENSE", "categories": [ "Linters" diff --git a/version b/version index 140ee6da8c..bb8c679946 100644 --- a/version +++ b/version @@ -1,2 +1,2 @@ -2.17.0 -2023-10-25 +2.18.0 +2023-11-03 From 2b4ea2dcc9b52984119b2b3b2526e477728d875e Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Fri, 3 Nov 2023 19:25:18 -0400 Subject: [PATCH 076/117] fix(dist): delete redundant prompt We don't need to prompt the user to publish the website because the step automatically publishes. Remove the confusing WaitForDone() call. --- dist/release.go | 1 - 1 file changed, 1 deletion(-) diff --git a/dist/release.go b/dist/release.go index 3a80e09558..058a317e8c 100644 --- a/dist/release.go +++ b/dist/release.go @@ -294,7 +294,6 @@ var Steps []Step = []Step{ Stopf("missing -ReleaseCommitHash\n") } RunCommandOrStop("./website/tools/deploy.sh", ReleaseCommitHash) - WaitForDone() }, }, From 48c2557a76df699a3ad8a61e98d335466eb540ef Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Fri, 3 Nov 2023 19:28:33 -0400 Subject: [PATCH 077/117] fix(dist): fix npm publish 2fac in release script When the relase script runs 'npm publish', publishing fails because the command requires interactive 2-factor auth. Make release.go forward stdin and stdout/stderr so that 'npm publish' can run interactively. This commit affects more commands, such as 'rsync', in case an ssh auth prompt appears, or if the user just wants to see the output of commands. --- dist/release.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dist/release.go b/dist/release.go index 058a317e8c..31b2720ce3 100644 --- a/dist/release.go +++ b/dist/release.go @@ -581,6 +581,9 @@ func UpdateReleaseVersions(options UpdateReleaseVersionsOptions) ([]byte, error) func RunCommandOrStop(name string, arg ...string) { cmd := exec.Command(name, arg...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { commandString := CommandToShell(cmd.Args) Stopf("failed to run command:\n$ %s\n%v", commandString, err) From 7b78dca4722dbdec48fd0a5bc1a07ad30082debc Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Fri, 3 Nov 2023 22:09:03 -0400 Subject: [PATCH 078/117] feat(typescript): parse 'export as namespace' statements --- docs/CHANGELOG.md | 7 + po/messages.pot | 12 ++ .../diag/diagnostic-metadata-generated.cpp | 32 +++++ .../diag/diagnostic-metadata-generated.h | 4 +- src/quick-lint-js/diag/diagnostic-types-2.h | 21 +++ src/quick-lint-js/fe/parse-statement.cpp | 31 +++++ .../i18n/translation-table-generated.cpp | 8 +- .../i18n/translation-table-generated.h | 7 +- .../i18n/translation-table-test-generated.h | 35 ++++- test/CMakeLists.txt | 1 + test/test-parse-typescript-declare-module.cpp | 125 ++++++++++++++++++ 11 files changed, 278 insertions(+), 5 deletions(-) create mode 100644 test/test-parse-typescript-declare-module.cpp diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 4795bd5e97..e6f2c0f69e 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -6,6 +6,13 @@ based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). quick-lint-js' version numbers are arbitrary. quick-lint-js does *not* adhere to Semantic Versioning. +## Unreleased + +### Added + +* TypeScript support (still experimental): + * `export as namespace` statements are now parsed. + ## 2.18.0 (2023-11-03) [Downloads](https://c.quick-lint-js.com/releases/2.18.0/) diff --git a/po/messages.pot b/po/messages.pot index 0d21adfd3b..13d2f7dcc9 100644 --- a/po/messages.pot +++ b/po/messages.pot @@ -1409,6 +1409,18 @@ msgstr "" msgid "{1:headlinese} value must be a compile-time constant" msgstr "" +#: src/quick-lint-js/diag/diagnostic-metadata-generated.cpp +msgid "'export as namespace' is not allowed in a namespace or module" +msgstr "" + +#: src/quick-lint-js/diag/diagnostic-metadata-generated.cpp +msgid "containing namespace or module declared here" +msgstr "" + +#: src/quick-lint-js/diag/diagnostic-metadata-generated.cpp +msgid "'export as namespace' is only allowed in TypeScript .d.ts files" +msgstr "" + #: src/quick-lint-js/diag/diagnostic-metadata-generated.cpp msgid "'export =' is not allowed; write 'export default' or 'module.exports =' (CommonJS) instead" msgstr "" diff --git a/src/quick-lint-js/diag/diagnostic-metadata-generated.cpp b/src/quick-lint-js/diag/diagnostic-metadata-generated.cpp index 1102307596..a5043b249b 100644 --- a/src/quick-lint-js/diag/diagnostic-metadata-generated.cpp +++ b/src/quick-lint-js/diag/diagnostic-metadata-generated.cpp @@ -4189,6 +4189,38 @@ const QLJS_CONSTINIT Diagnostic_Info all_diagnostic_infos[] = { }, }, + // Diag_TypeScript_Export_As_Namespace_Is_Not_Allowed_In_Namespace_Or_Module + { + .code = 424, + .severity = Diagnostic_Severity::error, + .message_formats = { + QLJS_TRANSLATABLE("'export as namespace' is not allowed in a namespace or module"), + QLJS_TRANSLATABLE("containing namespace or module declared here"), + }, + .message_args = { + { + Diagnostic_Message_Arg_Info(offsetof(Diag_TypeScript_Export_As_Namespace_Is_Not_Allowed_In_Namespace_Or_Module, export_keyword), Diagnostic_Arg_Type::source_code_span), + }, + { + Diagnostic_Message_Arg_Info(offsetof(Diag_TypeScript_Export_As_Namespace_Is_Not_Allowed_In_Namespace_Or_Module, namespace_or_module_keyword), Diagnostic_Arg_Type::source_code_span), + }, + }, + }, + + // Diag_TypeScript_Export_As_Namespace_Is_Only_Allowed_In_TypeScript_Definition_File + { + .code = 423, + .severity = Diagnostic_Severity::error, + .message_formats = { + QLJS_TRANSLATABLE("'export as namespace' is only allowed in TypeScript .d.ts files"), + }, + .message_args = { + { + Diagnostic_Message_Arg_Info(offsetof(Diag_TypeScript_Export_As_Namespace_Is_Only_Allowed_In_TypeScript_Definition_File, export_keyword), Diagnostic_Arg_Type::source_code_span), + }, + }, + }, + // Diag_TypeScript_Export_Equal_Not_Allowed_In_JavaScript { .code = 370, diff --git a/src/quick-lint-js/diag/diagnostic-metadata-generated.h b/src/quick-lint-js/diag/diagnostic-metadata-generated.h index dfeb9eb5c9..4057886cc0 100644 --- a/src/quick-lint-js/diag/diagnostic-metadata-generated.h +++ b/src/quick-lint-js/diag/diagnostic-metadata-generated.h @@ -290,6 +290,8 @@ namespace quick_lint_js { QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Enum_Is_Not_Allowed_In_JavaScript) \ QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Enum_Member_Name_Cannot_Be_Number) \ QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Enum_Value_Must_Be_Constant) \ + QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Export_As_Namespace_Is_Not_Allowed_In_Namespace_Or_Module) \ + QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Export_As_Namespace_Is_Only_Allowed_In_TypeScript_Definition_File) \ QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Export_Equal_Not_Allowed_In_JavaScript) \ QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Import_Type_Missing_Export_Name) \ QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Implements_Must_Be_After_Extends) \ @@ -444,7 +446,7 @@ namespace quick_lint_js { /* END */ // clang-format on -inline constexpr int Diag_Type_Count = 430; +inline constexpr int Diag_Type_Count = 432; extern const Diagnostic_Info all_diagnostic_infos[Diag_Type_Count]; } diff --git a/src/quick-lint-js/diag/diagnostic-types-2.h b/src/quick-lint-js/diag/diagnostic-types-2.h index c49dcd7cf4..306439507d 100644 --- a/src/quick-lint-js/diag/diagnostic-types-2.h +++ b/src/quick-lint-js/diag/diagnostic-types-2.h @@ -2155,6 +2155,27 @@ struct Diag_TypeScript_Enum_Value_Must_Be_Constant { Enum_Kind declared_enum_kind; }; +struct + Diag_TypeScript_Export_As_Namespace_Is_Not_Allowed_In_Namespace_Or_Module { + [[qljs::diag("E0424", Diagnostic_Severity::error)]] // + [[qljs::message( + "'export as namespace' is not allowed in a namespace or module", + ARG(export_keyword))]] // + [[qljs::message("containing namespace or module declared here", + ARG(namespace_or_module_keyword))]] // + Source_Code_Span export_keyword; + Source_Code_Span namespace_or_module_keyword; +}; + +struct + Diag_TypeScript_Export_As_Namespace_Is_Only_Allowed_In_TypeScript_Definition_File { + [[qljs::diag("E0423", Diagnostic_Severity::error)]] // + [[qljs::message( + "'export as namespace' is only allowed in TypeScript .d.ts files", + ARG(export_keyword))]] // + Source_Code_Span export_keyword; +}; + struct Diag_TypeScript_Export_Equal_Not_Allowed_In_JavaScript { [[qljs::diag("E0370", Diagnostic_Severity::error)]] // // clang-format off diff --git a/src/quick-lint-js/fe/parse-statement.cpp b/src/quick-lint-js/fe/parse-statement.cpp index a4449fff3e..713b0fef90 100644 --- a/src/quick-lint-js/fe/parse-statement.cpp +++ b/src/quick-lint-js/fe/parse-statement.cpp @@ -1459,6 +1459,37 @@ void Parser::parse_and_visit_export(Parse_Visitor_Base &v, break; } + // export as namespace MyLibrary; // TypeScript definition only. + case Token_Type::kw_as: + // @@@ declare namespace stuff + this->skip(); + QLJS_PARSER_UNIMPLEMENTED_IF_NOT_TOKEN(Token_Type::kw_namespace); + this->skip(); + switch (this->peek().type) { + QLJS_CASE_CONTEXTUAL_KEYWORD: + case Token_Type::identifier: + this->skip(); + break; + default: + QLJS_PARSER_UNIMPLEMENTED(); + break; + } + if (!this->options_.typescript_definition_file) { + this->diag_reporter_->report( + Diag_TypeScript_Export_As_Namespace_Is_Only_Allowed_In_TypeScript_Definition_File{ + .export_keyword = export_token_span, + }); + } else if (this->in_typescript_namespace_or_module_.has_value()) { + this->diag_reporter_->report( + Diag_TypeScript_Export_As_Namespace_Is_Not_Allowed_In_Namespace_Or_Module{ + .export_keyword = export_token_span, + .namespace_or_module_keyword = + *this->in_typescript_namespace_or_module_, + }); + } + this->consume_semicolon_after_statement(); + break; + // export enum E {} // TypeScript only. case Token_Type::kw_enum: // is_current_typescript_namespace_non_empty_ is possibly set by diff --git a/src/quick-lint-js/i18n/translation-table-generated.cpp b/src/quick-lint-js/i18n/translation-table-generated.cpp index f99f767822..18aebffa7f 100644 --- a/src/quick-lint-js/i18n/translation-table-generated.cpp +++ b/src/quick-lint-js/i18n/translation-table-generated.cpp @@ -66,6 +66,8 @@ const Translation_Table translation_data = { {18, 13, 53, 16, 51, 16}, // {0, 0, 0, 0, 0, 33}, // {0, 0, 0, 0, 0, 91}, // + {0, 0, 0, 0, 0, 62}, // + {0, 0, 0, 0, 0, 64}, // {0, 0, 0, 39, 0, 22}, // {30, 39, 0, 46, 0, 38}, // {0, 0, 0, 0, 0, 11}, // @@ -222,7 +224,8 @@ const Translation_Table translation_data = { {58, 31, 67, 69, 0, 43}, // {90, 38, 91, 90, 53, 75}, // {0, 0, 0, 0, 0, 29}, // - {41, 16, 34, 35, 34, 43}, // + {0, 0, 0, 0, 0, 43}, // + {41, 16, 34, 35, 34, 45}, // {0, 0, 0, 0, 0, 43}, // {0, 0, 0, 0, 0, 60}, // {0, 0, 0, 0, 0, 22}, // @@ -1862,6 +1865,8 @@ const Translation_Table translation_data = { u8"'do-while' loop\0" u8"'else' has no corresponding 'if'\0" u8"'export =' is not allowed; write 'export default' or 'module.exports =' (CommonJS) instead\0" + u8"'export as namespace' is not allowed in a namespace or module\0" + u8"'export as namespace' is only allowed in TypeScript .d.ts files\0" u8"'export' keyword here\0" u8"'extends' must be before 'implements'\0" u8"'for' loop\0" @@ -2019,6 +2024,7 @@ const Translation_Table translation_data = { u8"const fields within classes are only allowed in TypeScript, not JavaScript\0" u8"const variable declared here\0" u8"containing 'declare namespace' starts here\0" + u8"containing namespace or module declared here\0" u8"continue can only be used inside of a loop\0" u8"decorator belongs immediately before this overloaded method\0" u8"decorator starts here\0" diff --git a/src/quick-lint-js/i18n/translation-table-generated.h b/src/quick-lint-js/i18n/translation-table-generated.h index 2819960be4..28be58721d 100644 --- a/src/quick-lint-js/i18n/translation-table-generated.h +++ b/src/quick-lint-js/i18n/translation-table-generated.h @@ -18,8 +18,8 @@ namespace quick_lint_js { using namespace std::literals::string_view_literals; constexpr std::uint32_t translation_table_locale_count = 5; -constexpr std::uint16_t translation_table_mapping_table_size = 526; -constexpr std::size_t translation_table_string_table_size = 80133; +constexpr std::uint16_t translation_table_mapping_table_size = 529; +constexpr std::size_t translation_table_string_table_size = 80304; constexpr std::size_t translation_table_locale_table_size = 35; QLJS_CONSTEVAL std::uint16_t translation_table_const_look_up( @@ -80,6 +80,8 @@ QLJS_CONSTEVAL std::uint16_t translation_table_const_look_up( "'do-while' loop"sv, "'else' has no corresponding 'if'"sv, "'export =' is not allowed; write 'export default' or 'module.exports =' (CommonJS) instead"sv, + "'export as namespace' is not allowed in a namespace or module"sv, + "'export as namespace' is only allowed in TypeScript .d.ts files"sv, "'export' keyword here"sv, "'extends' must be before 'implements'"sv, "'for' loop"sv, @@ -237,6 +239,7 @@ QLJS_CONSTEVAL std::uint16_t translation_table_const_look_up( "const fields within classes are only allowed in TypeScript, not JavaScript"sv, "const variable declared here"sv, "containing 'declare namespace' starts here"sv, + "containing namespace or module declared here"sv, "continue can only be used inside of a loop"sv, "decorator belongs immediately before this overloaded method"sv, "decorator starts here"sv, diff --git a/src/quick-lint-js/i18n/translation-table-test-generated.h b/src/quick-lint-js/i18n/translation-table-test-generated.h index c647722028..b283c2ade5 100644 --- a/src/quick-lint-js/i18n/translation-table-test-generated.h +++ b/src/quick-lint-js/i18n/translation-table-test-generated.h @@ -27,7 +27,7 @@ struct Translated_String { }; // clang-format off -inline const Translated_String test_translation_table[525] = { +inline const Translated_String test_translation_table[528] = { { "\"global-groups\" entries must be strings"_translatable, u8"\"global-groups\" entries must be strings", @@ -622,6 +622,28 @@ inline const Translated_String test_translation_table[525] = { u8"'export =' is not allowed; write 'export default' or 'module.exports =' (CommonJS) instead", }, }, + { + "'export as namespace' is not allowed in a namespace or module"_translatable, + u8"'export as namespace' is not allowed in a namespace or module", + { + u8"'export as namespace' is not allowed in a namespace or module", + u8"'export as namespace' is not allowed in a namespace or module", + u8"'export as namespace' is not allowed in a namespace or module", + u8"'export as namespace' is not allowed in a namespace or module", + u8"'export as namespace' is not allowed in a namespace or module", + }, + }, + { + "'export as namespace' is only allowed in TypeScript .d.ts files"_translatable, + u8"'export as namespace' is only allowed in TypeScript .d.ts files", + { + u8"'export as namespace' is only allowed in TypeScript .d.ts files", + u8"'export as namespace' is only allowed in TypeScript .d.ts files", + u8"'export as namespace' is only allowed in TypeScript .d.ts files", + u8"'export as namespace' is only allowed in TypeScript .d.ts files", + u8"'export as namespace' is only allowed in TypeScript .d.ts files", + }, + }, { "'export' keyword here"_translatable, u8"'export' keyword here", @@ -2349,6 +2371,17 @@ inline const Translated_String test_translation_table[525] = { u8"containing 'declare namespace' starts here", }, }, + { + "containing namespace or module declared here"_translatable, + u8"containing namespace or module declared here", + { + u8"containing namespace or module declared here", + u8"containing namespace or module declared here", + u8"containing namespace or module declared here", + u8"containing namespace or module declared here", + u8"containing namespace or module declared here", + }, + }, { "continue can only be used inside of a loop"_translatable, u8"continue can only be used inside of a loop", diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a07387674c..88b3bfff22 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -151,6 +151,7 @@ quick_lint_js_add_executable( test-parse-typescript-declare-function.cpp test-parse-typescript-declare-global.cpp test-parse-typescript-declare-interface.cpp + test-parse-typescript-declare-module.cpp test-parse-typescript-declare-namespace.cpp test-parse-typescript-declare-tsmodule.cpp test-parse-typescript-declare-type-alias.cpp diff --git a/test/test-parse-typescript-declare-module.cpp b/test/test-parse-typescript-declare-module.cpp new file mode 100644 index 0000000000..29605b2525 --- /dev/null +++ b/test/test-parse-typescript-declare-module.cpp @@ -0,0 +1,125 @@ +// Copyright (C) 2020 Matthew "strager" Glazar +// See end of file for extended copyright information. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using ::testing::ElementsAre; + +namespace quick_lint_js { +namespace { +class Test_Parse_TypeScript_Declare_Module : public Test_Parse_Expression {}; + +TEST_F(Test_Parse_TypeScript_Declare_Module, export_as_namespace) { + Spy_Visitor p = + test_parse_and_visit_module(u8"export as namespace mynamespace;"_sv, + no_diags, typescript_definition_options); + EXPECT_THAT(p.visits, ElementsAre("visit_end_of_module")); +} + +TEST_F(Test_Parse_TypeScript_Declare_Module, + export_as_namespace_allows_newlines) { + Spy_Visitor p = + test_parse_and_visit_module(u8"export\nas\nnamespace\nmynamespace\n;"_sv, + no_diags, typescript_definition_options); + EXPECT_THAT(p.visits, ElementsAre("visit_end_of_module")); +} + +TEST_F(Test_Parse_TypeScript_Declare_Module, + export_as_namespace_requires_semicolon_or_asi) { + { + Spy_Visitor p = test_parse_and_visit_module( + u8"export as namespace mynamespace\ndeclare let x;"_sv, no_diags, + typescript_definition_options); + EXPECT_THAT(p.visits, ElementsAre("visit_enter_declare_scope", // + "visit_variable_declaration", // x + "visit_exit_declare_scope", // + "visit_end_of_module")); + } + + { + Spy_Visitor p = test_parse_and_visit_module( + u8"export as namespace mynamespace declare let x;"_sv, // + u8" ` Diag_Missing_Semicolon_After_Statement"_diag, + typescript_definition_options); + EXPECT_THAT(p.visits, ElementsAre("visit_enter_declare_scope", // + "visit_variable_declaration", // x + "visit_exit_declare_scope", // + "visit_end_of_module")); + } +} + +TEST_F(Test_Parse_TypeScript_Declare_Module, + export_as_namespace_allows_contextual_keywords) { + for (String8_View keyword : contextual_keywords) { + test_parse_and_visit_module( + concat(u8"export as namespace "_sv, keyword, u8";"_sv), no_diags, + typescript_definition_options); + } +} + +TEST_F(Test_Parse_TypeScript_Declare_Module, + export_as_namespace_not_allowed_in_javascript) { + test_parse_and_visit_module( + u8"export as namespace mynamespace;"_sv, // + u8"^^^^^^ Diag_TypeScript_Export_As_Namespace_Is_Only_Allowed_In_TypeScript_Definition_File"_diag, + javascript_options); +} + +TEST_F(Test_Parse_TypeScript_Declare_Module, + export_as_namespace_not_allowed_in_typescript_non_definition) { + test_parse_and_visit_module( + u8"export as namespace mynamespace;"_sv, // + u8"^^^^^^ Diag_TypeScript_Export_As_Namespace_Is_Only_Allowed_In_TypeScript_Definition_File"_diag, + typescript_options); +} + +TEST_F(Test_Parse_TypeScript_Declare_Module, + export_as_namespace_not_allowed_in_namespace) { + test_parse_and_visit_module( + u8"declare namespace ns { export as namespace mynamespace; }"_sv, // + u8" ^^^^^^ Diag_TypeScript_Export_As_Namespace_Is_Not_Allowed_In_Namespace_Or_Module.export_keyword\n"_diag + u8" ^^^^^^^^^ .namespace_or_module_keyword", + typescript_definition_options); + + test_parse_and_visit_module( + u8"declare module 'mod' { export as namespace mynamespace; }"_sv, // + u8" ^^^^^^ Diag_TypeScript_Export_As_Namespace_Is_Not_Allowed_In_Namespace_Or_Module.export_keyword\n"_diag + u8" ^^^^^^ .namespace_or_module_keyword", + typescript_definition_options); +} +} +} + +// quick-lint-js finds bugs in JavaScript programs. +// Copyright (C) 2020 Matthew "strager" Glazar +// +// This file is part of quick-lint-js. +// +// quick-lint-js is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// quick-lint-js is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with quick-lint-js. If not, see . From 64ee83d67ec10561803c75b5fe76589f040c7098 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Fri, 3 Nov 2023 22:28:06 -0400 Subject: [PATCH 079/117] fix(typescript): don't treat 'case await a: b;' as arrow function quick-lint-js's error detection for 'async a: b => c' is too optimistic. Disable it when the keyword prior is 'await' instead of 'async', fixing false positives for valid code such as the following: async function f() { switch (x) { case await y: z; break; } } --- docs/CHANGELOG.md | 2 + src/quick-lint-js/fe/parse-expression.cpp | 3 +- test/CMakeLists.txt | 1 + test/test-parse-typescript-statement.cpp | 64 +++++++++++++++++++++++ 4 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 test/test-parse-typescript-statement.cpp diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index e6f2c0f69e..81879ea155 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -12,6 +12,8 @@ Semantic Versioning. * TypeScript support (still experimental): * `export as namespace` statements are now parsed. + * `case await x:` no longer treats `:` as if it was a type annotation colon in + an arrow function parameter list. ## 2.18.0 (2023-11-03) diff --git a/src/quick-lint-js/fe/parse-expression.cpp b/src/quick-lint-js/fe/parse-expression.cpp index a8ff40c322..22799f1280 100644 --- a/src/quick-lint-js/fe/parse-expression.cpp +++ b/src/quick-lint-js/fe/parse-expression.cpp @@ -1105,7 +1105,8 @@ Expression* Parser::parse_async_expression_only( } std::optional type_colon_span; - if (this->peek().type == Token_Type::colon && this->options_.typescript) { + if (is_async && this->peek().type == Token_Type::colon && + this->options_.typescript) { // async param: Type => {} // Invalid. type_colon_span = this->peek().span(); Buffering_Visitor type_visits(&this->type_expression_memory_); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 88b3bfff22..947457ffe3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -167,6 +167,7 @@ quick_lint_js_add_executable( test-parse-typescript-module.cpp test-parse-typescript-namespace.cpp test-parse-typescript-object.cpp + test-parse-typescript-statement.cpp test-parse-typescript-this-parameters.cpp test-parse-typescript-type-alias.cpp test-parse-typescript-type.cpp diff --git a/test/test-parse-typescript-statement.cpp b/test/test-parse-typescript-statement.cpp new file mode 100644 index 0000000000..55c30723d1 --- /dev/null +++ b/test/test-parse-typescript-statement.cpp @@ -0,0 +1,64 @@ +// Copyright (C) 2020 Matthew "strager" Glazar +// See end of file for extended copyright information. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using ::testing::ElementsAreArray; + +namespace quick_lint_js { +namespace { +class Test_Parse_TypeScript_Statement : public ::testing::Test {}; + +TEST_F(Test_Parse_TypeScript_Statement, + await_in_case_is_not_arrow_function_with_missing_parens) { + // This code used to confuse + // Diag_Arrow_Parameter_With_Type_Annotation_Requires_Parentheses detection. + { + Spy_Visitor p = test_parse_and_visit_statement( + u8"switch (x) { case await a: b => c; }"_sv, no_diags, + typescript_options); + EXPECT_THAT(p.variable_uses, + ElementsAreArray({u8"x"_sv, u8"a"_sv, u8"c"_sv})); + EXPECT_THAT(p.variable_declarations, + ElementsAreArray({arrow_param_decl(u8"b"_sv)})); + } +} +} +} + +// quick-lint-js finds bugs in JavaScript programs. +// Copyright (C) 2020 Matthew "strager" Glazar +// +// This file is part of quick-lint-js. +// +// quick-lint-js is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// quick-lint-js is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with quick-lint-js. If not, see . From f50fa8ec2f49fc6de88fbd3233cc8627fd5ca1fa Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Fri, 3 Nov 2023 22:43:44 -0400 Subject: [PATCH 080/117] chore(test-typescript): disable failing test This test is failing but for benign reasons. Disable it. --- tools/test-typescript/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/test-typescript/main.cpp b/tools/test-typescript/main.cpp index d5b81a860a..ac70798a07 100644 --- a/tools/test-typescript/main.cpp +++ b/tools/test-typescript/main.cpp @@ -32,6 +32,10 @@ constexpr String8_View ignored_tests[] = { // directives causes its errors to be ignored by the test runner, but I // can't tell which test directive would do this. u8"/usedImportNotElidedInJs.ts"sv, + + // This test correctly emits E0196 (a warning). + // TODO(strager): Disable E0196 for this test but still check this test. + u8"/initializePropertiesWithRenamedLet.ts"sv, }; struct Test_TypeScript_Options { From 129cc6080cd54bb0a3e035296a6a61c822efd65a Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Fri, 3 Nov 2023 23:28:37 -0400 Subject: [PATCH 081/117] fix(logging): remove duplicate #include --- tools/generate-trace-sources.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/generate-trace-sources.cpp b/tools/generate-trace-sources.cpp index 10f3f5e355..3bdb51bb18 100644 --- a/tools/generate-trace-sources.cpp +++ b/tools/generate-trace-sources.cpp @@ -1409,7 +1409,6 @@ void write_writer_h(CXX_Trace_Types_Parser& types, Output_Stream& out) { #include #include #include -#include #include // clang-format off From 93aece5147969c438501be135e18209d1117c0ed Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Fri, 3 Nov 2023 23:28:37 -0400 Subject: [PATCH 082/117] fix(container): ensure Flexible_Array aligns capacity Flexible_Array assumes that (alignof(T) <= maximum(alignof(Header), std::size_t))). This is a bad assumption. Fix Flexible_Array to align its capacity properly, removing restrictions on T's alignment. --- src/quick-lint-js/container/flexible-array.h | 23 +++- test/CMakeLists.txt | 1 + test/test-flexible-array.cpp | 130 +++++++++++++++++++ 3 files changed, 150 insertions(+), 4 deletions(-) create mode 100644 test/test-flexible-array.cpp diff --git a/src/quick-lint-js/container/flexible-array.h b/src/quick-lint-js/container/flexible-array.h index daf6ce6626..94bb0f1838 100644 --- a/src/quick-lint-js/container/flexible-array.h +++ b/src/quick-lint-js/container/flexible-array.h @@ -5,13 +5,30 @@ #include #include +#include #include #include namespace quick_lint_js { +// Helper for Flexible_Array. Do not use directly. +// +// Flexible_Array_Base exists to have the compiler compute the required +// alignment for Header and the capacity field. +template +class Flexible_Array_Base : public Header { + protected: + template + explicit Flexible_Array_Base(std::size_t capacity, Args&&... args) + : Header(std::forward(args)...), capacity_(capacity) {} + + std::size_t capacity_; +}; + // Like a C99 flexible array member but with its size too. template -class Flexible_Array : public Header { +class alignas(maximum(alignof(T), + alignof(Flexible_Array_Base

    ))) Flexible_Array + : public Flexible_Array_Base
    { public: T* flexible_capacity_begin() { return reinterpret_cast(&this[1]); } @@ -53,9 +70,7 @@ class Flexible_Array : public Header { private: template explicit Flexible_Array(std::size_t capacity, Args&&... args) - : Header(std::forward(args)...), capacity_(capacity) {} - - std::size_t capacity_; + : Flexible_Array_Base
    (capacity, std::forward(args)...) {} }; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 947457ffe3..ae7244351e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -106,6 +106,7 @@ quick_lint_js_add_executable( test-file-path.cpp test-file.cpp test-fixed-vector.cpp + test-flexible-array.cpp test-function-ref.cpp test-instance-tracker.cpp test-integer-decimal.cpp diff --git a/test/test-flexible-array.cpp b/test/test-flexible-array.cpp new file mode 100644 index 0000000000..b5812157d8 --- /dev/null +++ b/test/test-flexible-array.cpp @@ -0,0 +1,130 @@ +// Copyright (C) 2020 Matthew "strager" Glazar +// See end of file for extended copyright information. + +#include +#include +#include +#include +#include +#include +#include + +namespace quick_lint_js { +namespace { +// Wraps any allocator with support for any arbitrary alignment. +// +// Designed for testing only. +// +// Each allocation has the following form: +// +// [padding][header][data] +// ^~~~~~~~~' ^ +// +// * The returned pointer points to the beginning of data. Padding ensures it is +// suitably aligned. +// * The header contains a pointer pointing to the beginning of the underlying +// allocation. This is used to free the memory. +struct Aligning_Memory_Resource : public Memory_Resource { + public: + explicit Aligning_Memory_Resource(Memory_Resource *underlying_memory) + : underlying_memory_(underlying_memory) {} + + void *do_allocate(std::size_t bytes, std::size_t alignment) override { + std::size_t underlying_size = this->underlying_size(bytes, alignment); + void *underlying_allocation = + this->underlying_memory_->allocate(underlying_size, 1); + + void *result = &reinterpret_cast
    (underlying_allocation)[1]; + std::size_t space_after_result = underlying_size; + bool ok = + std::align(alignment, bytes, result, space_after_result) != nullptr; + QLJS_ALWAYS_ASSERT(ok); + + // Write the header. memcpy must be used because the header might not be + // aligned. + Header header = {.underlying_allocation = underlying_allocation}; + std::memcpy(&reinterpret_cast
    (result)[-1], &header, + sizeof(Header)); + + return result; + } + + void do_deallocate(void *p, std::size_t bytes, + std::size_t alignment) override { + // Read the header. memcpy must be used because the header might not be + // aligned. + Header header; + std::memcpy(&header, &reinterpret_cast
    (p)[-1], sizeof(Header)); + this->underlying_memory_->deallocate( + header.underlying_allocation, this->underlying_size(bytes, alignment), + 1); + } + + private: + struct Header { + void *underlying_allocation; + }; + + std::size_t underlying_size(std::size_t bytes, std::size_t alignment) { + return bytes + alignment + sizeof(void *); + } + + Memory_Resource *underlying_memory_; +}; + +Aligning_Memory_Resource memory = + Aligning_Memory_Resource(new_delete_resource()); + +TEST(Test_Flexible_Array, allocating_header_creates_array) { + struct My_Array_Header {}; + using My_Array = Flexible_Array; + My_Array *a = My_Array::allocate_and_construct_header(&memory, 10); + + int *begin = a->flexible_capacity_begin(); + int *end = a->flexible_capacity_end(); + ASSERT_EQ(end - begin, 10); + ASSERT_EQ(a->flexible_capacity(), 10); + + // Ensure the array elements are writable. This is intended to cause an ASAN + // or UBSAN report if Flexible_Array is buggy. + for (int i = 0; i < 10; ++i) { + begin[i] = i * 11111111; + } + for (int i = 0; i < 10; ++i) { + ASSERT_EQ(begin[i], i * 11111111) << i; + } + + My_Array::destroy_header_and_deallocate(&memory, a); +} + +TEST(Test_Flexible_Array, allocating_header_over_aligned_by_type) { + struct alignas(128) My_Type {}; + struct My_Array_Header {}; + using My_Array = Flexible_Array; + My_Array *a = My_Array::allocate_and_construct_header(&memory, 10); + + My_Type *begin = a->flexible_capacity_begin(); + ASSERT_TRUE(is_aligned(begin, 128)) << begin; + + My_Array::destroy_header_and_deallocate(&memory, a); +} +} +} + +// quick-lint-js finds bugs in JavaScript programs. +// Copyright (C) 2020 Matthew "strager" Glazar +// +// This file is part of quick-lint-js. +// +// quick-lint-js is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// quick-lint-js is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with quick-lint-js. If not, see . From 9e8ee47297299aa044ad0d35976f0a4a4b394495 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Fri, 3 Nov 2023 23:28:37 -0400 Subject: [PATCH 083/117] refactor(container): make Linked_Bump_Allocator use run-time alignment Linked_Bump_Allocator is coded to align all allocations to 'alignment' (typically 8). This is problematic for a few reasons: 1. 'alignment' is specified as a compile-time template parameter, forcing Linked_Bump_Allocator to be a template. This probably slows down compilation and clutters the header file. (This is the main problem motivating this patch.) 2. Allocations perform run-time alignment anyways, but on the size rather than on the pointer. 3. The forced alignment wastes some space. 4. Linked_Bump_Allocator cannot support overaligned data. (This isn't a problem yet, and I don't forsee this being a real problem. I mention this for completeness.) Teach Linked_Bump_Allocator to align everything according to a run-time alignment. This will let us fix issue #1 later, directly fixes issue #3, and (with some work included in this patch) fixes #4. This patch might have negative performance costs. I did not measure. --- src/quick-lint-js/container/flexible-array.h | 6 ++ .../container/linked-bump-allocator.h | 89 ++++++++++++------- src/quick-lint-js/util/pointer.h | 4 +- test/test-linked-bump-allocator.cpp | 22 ++++- 4 files changed, 85 insertions(+), 36 deletions(-) diff --git a/src/quick-lint-js/container/flexible-array.h b/src/quick-lint-js/container/flexible-array.h index 94bb0f1838..9f650c526a 100644 --- a/src/quick-lint-js/container/flexible-array.h +++ b/src/quick-lint-js/container/flexible-array.h @@ -30,6 +30,12 @@ class alignas(maximum(alignof(T), alignof(Flexible_Array_Base
    ))) Flexible_Array : public Flexible_Array_Base
    { public: + // The guaranteed alignment for the capacity. + // + // Invariant: capacity_alignment >= alignof(T) + static inline constexpr std::size_t capacity_alignment = + maximum(alignof(T), alignof(Flexible_Array_Base
    )); + T* flexible_capacity_begin() { return reinterpret_cast(&this[1]); } T* flexible_capacity_end() { diff --git a/src/quick-lint-js/container/linked-bump-allocator.h b/src/quick-lint-js/container/linked-bump-allocator.h index c649c95e38..e5fc831fc7 100644 --- a/src/quick-lint-js/container/linked-bump-allocator.h +++ b/src/quick-lint-js/container/linked-bump-allocator.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -32,9 +33,10 @@ namespace quick_lint_js { // * no per-object free()/delete // * bulk free() via rewind() (doesn't call destructors) // * in-place growing of allocations -// * all allocations have the same alignment // // Internally, Linked_Bump_Allocator maintains a linked list of chunks. +// +// TODO(strager): Remove alignment parameter. template class Linked_Bump_Allocator final : public Memory_Resource { private: @@ -133,11 +135,8 @@ class Linked_Bump_Allocator final : public Memory_Resource { template T* new_object(Args&&... args) { - static_assert(alignof(T) <= alignment, - "T is not allowed by this allocator; this allocator's " - "alignment is insufficient for T"); - constexpr std::size_t byte_size = align_up(sizeof(T)); - return new (this->allocate_bytes(byte_size)) T(std::forward(args)...); + return new (this->allocate_bytes(sizeof(T), alignof(T))) + T(std::forward(args)...); } template @@ -156,11 +155,9 @@ class Linked_Bump_Allocator final : public Memory_Resource { template [[nodiscard]] Span allocate_uninitialized_span(std::size_t size) { - static_assert(alignof(T) <= alignment, - "T is not allowed by this allocator; this allocator's " - "alignment is insufficient for T"); - std::size_t byte_size = this->align_up(size * sizeof(T)); - T* items = reinterpret_cast(this->allocate_bytes(byte_size)); + std::size_t byte_size = size * sizeof(T); + T* items = + reinterpret_cast(this->allocate_bytes(byte_size, alignof(T))); return Span(items, narrow_cast(size)); } @@ -185,7 +182,7 @@ class Linked_Bump_Allocator final : public Memory_Resource { std::size_t new_size) { this->assert_not_disabled(); QLJS_ASSERT(new_size > old_size); - std::size_t old_byte_size = this->align_up(old_size * sizeof(T)); + std::size_t old_byte_size = old_size * sizeof(T); bool array_is_last_allocation = reinterpret_cast(array) + old_byte_size == this->next_allocation_; @@ -194,7 +191,7 @@ class Linked_Bump_Allocator final : public Memory_Resource { return false; } - std::size_t extra_bytes = this->align_up((new_size - old_size) * sizeof(T)); + std::size_t extra_bytes = (new_size - old_size) * sizeof(T); if (extra_bytes > this->remaining_bytes_in_current_chunk()) { return false; } @@ -235,17 +232,16 @@ class Linked_Bump_Allocator final : public Memory_Resource { protected: void* do_allocate(std::size_t bytes, std::size_t align) override { - QLJS_ASSERT(align <= alignment); - return this->allocate_bytes(this->align_up(bytes)); + return this->allocate_bytes(bytes, align); } - void do_deallocate(void* p, std::size_t bytes, std::size_t align) override { - QLJS_ASSERT(align <= alignment); + void do_deallocate(void* p, std::size_t bytes, + [[maybe_unused]] std::size_t align) override { this->deallocate_bytes(p, bytes); } private: - struct alignas(maximum(alignment, alignof(void*))) Chunk_Header { + struct alignas(alignof(void*)) Chunk_Header { explicit Chunk_Header(Chunk* previous) : previous(previous) {} Chunk* previous; // Linked list. @@ -253,19 +249,30 @@ class Linked_Bump_Allocator final : public Memory_Resource { static inline constexpr std::size_t default_chunk_size = 4096 - sizeof(Chunk); - static constexpr std::size_t align_up(std::size_t size) { - return (size + alignment - 1) & ~(alignment - 1); - } - - [[nodiscard]] void* allocate_bytes(std::size_t size) { + [[nodiscard]] void* allocate_bytes(std::size_t size, std::size_t align) { this->assert_not_disabled(); - QLJS_SLOW_ASSERT(size % alignment == 0); - if (this->remaining_bytes_in_current_chunk() < size) { - this->append_chunk(maximum(size, this->default_chunk_size)); - QLJS_ASSERT(this->remaining_bytes_in_current_chunk() >= size); - } - void* result = this->next_allocation_; - this->next_allocation_ += size; + QLJS_SLOW_ASSERT(size % align == 0); + + std::uintptr_t next_allocation_int = + reinterpret_cast(this->next_allocation_); + // NOTE(strager): align_up might overflow. If it does, the allocation + // couldn't fit due to alignment alone + // (alignment_padding > this->remaining_bytes_in_current_chunk()). + std::uintptr_t result_int = align_up(next_allocation_int, align); + char* result = reinterpret_cast(result_int); + + // alignment_padding is how much the pointer moved due to alignment, i.e. + // how much padding is necessary due to alignment. + std::uintptr_t alignment_padding = result_int - next_allocation_int; + bool have_enough_space = + (alignment_padding + size) <= this->remaining_bytes_in_current_chunk(); + if (!have_enough_space) [[unlikely]] { + this->append_chunk(maximum(size, this->default_chunk_size), align); + result = this->next_allocation_; + QLJS_ASSERT(is_aligned(result, align)); + } + + this->next_allocation_ = result + size; this->did_allocate_bytes(result, size); return result; } @@ -291,11 +298,25 @@ class Linked_Bump_Allocator final : public Memory_Resource { // TODO(strager): Mark memory as unusable for Valgrind. } - void append_chunk(std::size_t size) { - this->chunk_ = Chunk::allocate_and_construct_header(new_delete_resource(), - size, this->chunk_); - this->next_allocation_ = this->chunk_->flexible_capacity_begin(); + void append_chunk(std::size_t size, std::size_t align) { + // Over-alignment is tested by + // NOTE[Linked_Bump_Allocator-append_chunk-alignment]. + bool is_over_aligned = align > Chunk::capacity_alignment; + std::size_t allocated_size = size; + if (is_over_aligned) { + allocated_size += align; + } + this->chunk_ = Chunk::allocate_and_construct_header( + new_delete_resource(), allocated_size, this->chunk_); + std::uintptr_t next_allocation_int = reinterpret_cast( + this->chunk_->flexible_capacity_begin()); + if (is_over_aligned) { + next_allocation_int = align_up(next_allocation_int, align); + } + this->next_allocation_ = reinterpret_cast(next_allocation_int); this->chunk_end_ = this->chunk_->flexible_capacity_end(); + QLJS_ASSERT(is_aligned(this->next_allocation_, align)); + QLJS_ASSERT(this->remaining_bytes_in_current_chunk() >= size); } void assert_not_disabled() const { diff --git a/src/quick-lint-js/util/pointer.h b/src/quick-lint-js/util/pointer.h index 127981995b..824faab783 100644 --- a/src/quick-lint-js/util/pointer.h +++ b/src/quick-lint-js/util/pointer.h @@ -12,8 +12,10 @@ inline bool is_aligned(void* p, std::size_t alignment) { return (reinterpret_cast(p) & alignment_mask) == 0; } +// Does not check for pointer overflow. template -Integer_Pointer align_up(Integer_Pointer p, std::size_t alignment) { +[[nodiscard]] Integer_Pointer align_up(Integer_Pointer p, + std::size_t alignment) { Integer_Pointer alignment_mask = static_cast(alignment - 1); // TODO(strager): What about integer overflow? return ((p - 1) | alignment_mask) + 1; diff --git a/test/test-linked-bump-allocator.cpp b/test/test-linked-bump-allocator.cpp index f08c7ec5ff..c2003808b3 100644 --- a/test/test-linked-bump-allocator.cpp +++ b/test/test-linked-bump-allocator.cpp @@ -81,7 +81,7 @@ TEST(Test_Linked_Bump_Allocator, TEST(Test_Linked_Bump_Allocator, less_aligned_pre_grown_and_grown_array_keeps_next_allocation_aligned) { - Linked_Bump_Allocator<4> alloc("test"); + Linked_Bump_Allocator<1> alloc("test"); Span chars = alloc.allocate_uninitialized_span(3); bool grew = alloc.try_grow_array_in_place(chars.data(), 3, 6); @@ -136,6 +136,26 @@ TEST(Test_Linked_Bump_Allocator, filling_first_chunk_allocates_second_chunk) { assert_valid_memory(new_chunk_object); } +TEST(Test_Linked_Bump_Allocator, + allocate_new_chunk_with_over_alignment_aligns) { + constexpr std::size_t chunk_size = + 4096 - sizeof(void*) * 2; // Implementation detail. + + Linked_Bump_Allocator alloc("test"); + [[maybe_unused]] Span padding = alloc.allocate_span(chunk_size); + ASSERT_EQ(alloc.remaining_bytes_in_current_chunk(), 0) + << "First chunk should be consumed entirely"; + + // NOTE[Linked_Bump_Allocator-append_chunk-alignment]: This should allocate a + // brand new chunk, thus exercising the alignment code in + // Linked_Bump_Allocator::append_chunk. + struct alignas(128) Over_Aligned_Struct { + char data[chunk_size]; + }; + Over_Aligned_Struct* s = alloc.new_object(); + assert_valid_memory(s); +} + TEST(Test_Linked_Bump_Allocator, rewinding_within_chunk_reuses_memory) { Linked_Bump_Allocator<1> alloc("test"); From bfebe9f641772b0a1156ee17ea27fd4f2024b15f Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Fri, 3 Nov 2023 23:28:37 -0400 Subject: [PATCH 084/117] refactor(container): make Linked_Bump_Allocator a non-template Linked_Bump_Allocator does not use its 'alignment' template parameter. Remove the template parameter then convert it into a non-template class. --- .../container/linked-bump-allocator.h | 3 -- .../container/monotonic-allocator.h | 5 +-- src/quick-lint-js/fe/jsx.cpp | 2 +- src/quick-lint-js/fe/lex.h | 5 +-- test/test-buffering-diag-reporter.cpp | 4 +- test/test-linked-bump-allocator.cpp | 38 +++++++++---------- test/test-vector.cpp | 28 +++++++------- 7 files changed, 39 insertions(+), 46 deletions(-) diff --git a/src/quick-lint-js/container/linked-bump-allocator.h b/src/quick-lint-js/container/linked-bump-allocator.h index e5fc831fc7..8d720c6a7e 100644 --- a/src/quick-lint-js/container/linked-bump-allocator.h +++ b/src/quick-lint-js/container/linked-bump-allocator.h @@ -35,9 +35,6 @@ namespace quick_lint_js { // * in-place growing of allocations // // Internally, Linked_Bump_Allocator maintains a linked list of chunks. -// -// TODO(strager): Remove alignment parameter. -template class Linked_Bump_Allocator final : public Memory_Resource { private: struct Chunk_Header; diff --git a/src/quick-lint-js/container/monotonic-allocator.h b/src/quick-lint-js/container/monotonic-allocator.h index b445ba6281..ef2b9874f3 100644 --- a/src/quick-lint-js/container/monotonic-allocator.h +++ b/src/quick-lint-js/container/monotonic-allocator.h @@ -3,13 +3,10 @@ #pragma once -#include #include -#include namespace quick_lint_js { -using Monotonic_Allocator = - Linked_Bump_Allocator; +using Monotonic_Allocator = Linked_Bump_Allocator; } // quick-lint-js finds bugs in JavaScript programs. diff --git a/src/quick-lint-js/fe/jsx.cpp b/src/quick-lint-js/fe/jsx.cpp index a29f932f1c..ef93078363 100644 --- a/src/quick-lint-js/fe/jsx.cpp +++ b/src/quick-lint-js/fe/jsx.cpp @@ -15,7 +15,7 @@ using namespace std::literals::string_view_literals; namespace quick_lint_js { const Hash_Map& jsx_attribute_aliases() { - static Linked_Bump_Allocator<1> string_allocator("jsx_attribute_aliases"); + static Linked_Bump_Allocator string_allocator("jsx_attribute_aliases"); static const Hash_Map cache = [] { // FIXME(strager): This is very inefficient. Hash_Map aliases{ diff --git a/src/quick-lint-js/fe/lex.h b/src/quick-lint-js/fe/lex.h index d641ae8b9d..f8aee077a9 100644 --- a/src/quick-lint-js/fe/lex.h +++ b/src/quick-lint-js/fe/lex.h @@ -333,8 +333,7 @@ class Lexer { Padded_String_View original_input_; Monotonic_Allocator allocator_{"lexer::allocator_"}; - Linked_Bump_Allocator transaction_allocator_{ - "lexer::transaction_allocator_"}; + Linked_Bump_Allocator transaction_allocator_{"lexer::transaction_allocator_"}; friend struct Lex_Tables; }; @@ -342,7 +341,7 @@ class Lexer { struct Lexer_Transaction { // Private to lexer. Do not construct, read, or modify. - using Allocator_Type = Linked_Bump_Allocator; + using Allocator_Type = Linked_Bump_Allocator; explicit Lexer_Transaction(Token old_last_token, const Char8* old_last_last_token_end, diff --git a/test/test-buffering-diag-reporter.cpp b/test/test-buffering-diag-reporter.cpp index 2104bd715e..2c1eb4fdc4 100644 --- a/test/test-buffering-diag-reporter.cpp +++ b/test/test-buffering-diag-reporter.cpp @@ -18,7 +18,7 @@ TEST(Test_Buffering_Diag_Reporter, buffers_all_visits) { static Padded_String let_code(u8"let"_sv); static Padded_String expression_code(u8"2+2==5"_sv); - Linked_Bump_Allocator memory("test"); + Linked_Bump_Allocator memory("test"); Buffering_Diag_Reporter diag_reporter(&memory); diag_reporter.report(Diag_Let_With_No_Bindings{.where = span_of(let_code)}); diag_reporter.report(Diag_Expected_Parenthesis_Around_If_Condition{ @@ -62,7 +62,7 @@ TEST(Test_Buffering_Diag_Reporter, not_destructing_does_not_leak) { // This test relies on a leak checker such as Valgrind's memtest or // Clang's LeakSanitizer. - Linked_Bump_Allocator memory("test"); + Linked_Bump_Allocator memory("test"); alignas(Buffering_Diag_Reporter) std::byte diag_reporter_storage[sizeof(Buffering_Diag_Reporter)]; Buffering_Diag_Reporter* diag_reporter = diff --git a/test/test-linked-bump-allocator.cpp b/test/test-linked-bump-allocator.cpp index c2003808b3..a0460aac62 100644 --- a/test/test-linked-bump-allocator.cpp +++ b/test/test-linked-bump-allocator.cpp @@ -31,7 +31,7 @@ TYPED_TEST_SUITE(Test_Linked_Bump_Allocator_With_Type, TYPED_TEST(Test_Linked_Bump_Allocator_With_Type, separate_allocations_are_contiguous_without_padding) { using T = TypeParam; - Linked_Bump_Allocator alloc("test"); + Linked_Bump_Allocator alloc("test"); std::intptr_t a = reinterpret_cast(alloc.template new_object()); std::intptr_t b = @@ -50,7 +50,7 @@ TYPED_TEST(Test_Linked_Bump_Allocator_With_Type, TEST(Test_Linked_Bump_Allocator, less_aligned_object_keeps_next_allocation_aligned) { - Linked_Bump_Allocator<4> alloc("test"); + Linked_Bump_Allocator alloc("test"); [[maybe_unused]] char* small = alloc.new_object(); std::uint32_t* after = alloc.new_object(); assert_valid_memory(after); @@ -58,21 +58,21 @@ TEST(Test_Linked_Bump_Allocator, TEST(Test_Linked_Bump_Allocator, less_aligned_bytes_keeps_next_allocation_aligned) { - Linked_Bump_Allocator<4> alloc("test"); + Linked_Bump_Allocator alloc("test"); [[maybe_unused]] void* small = alloc.allocate(1, /*align=*/1); std::uint32_t* after = alloc.new_object(); assert_valid_memory(after); } TEST(Test_Linked_Bump_Allocator, array_allocation_is_contiguous) { - Linked_Bump_Allocator<1> alloc("test"); + Linked_Bump_Allocator alloc("test"); Span chars = alloc.allocate_uninitialized_span(42); assert_valid_memory(chars.data(), chars.data() + 42, alignof(char)); } TEST(Test_Linked_Bump_Allocator, less_aligned_array_keeps_next_allocation_aligned) { - Linked_Bump_Allocator<4> alloc("test"); + Linked_Bump_Allocator alloc("test"); [[maybe_unused]] Span chars = alloc.allocate_uninitialized_span(3); std::uint32_t* after = alloc.new_object(); @@ -81,7 +81,7 @@ TEST(Test_Linked_Bump_Allocator, TEST(Test_Linked_Bump_Allocator, less_aligned_pre_grown_and_grown_array_keeps_next_allocation_aligned) { - Linked_Bump_Allocator<1> alloc("test"); + Linked_Bump_Allocator alloc("test"); Span chars = alloc.allocate_uninitialized_span(3); bool grew = alloc.try_grow_array_in_place(chars.data(), 3, 6); @@ -93,7 +93,7 @@ TEST(Test_Linked_Bump_Allocator, TEST(Test_Linked_Bump_Allocator, less_aligned_grown_array_keeps_next_allocation_aligned) { - Linked_Bump_Allocator<4> alloc("test"); + Linked_Bump_Allocator alloc("test"); Span chars = alloc.allocate_uninitialized_span(4); bool grew = alloc.try_grow_array_in_place(chars.data(), 4, 7); @@ -111,7 +111,7 @@ TEST(Test_Linked_Bump_Allocator, char c[chunk_size - 2]; }; - Linked_Bump_Allocator alloc("test"); + Linked_Bump_Allocator alloc("test"); ASSERT_GE(chunk_size, sizeof(Big_Object)) << "A big_object should fit in the chunk before allocating padding"; [[maybe_unused]] void* padding = alloc.new_object(); @@ -124,7 +124,7 @@ TEST(Test_Linked_Bump_Allocator, } TEST(Test_Linked_Bump_Allocator, filling_first_chunk_allocates_second_chunk) { - Linked_Bump_Allocator<1> alloc("test"); + Linked_Bump_Allocator alloc("test"); std::size_t first_chunk_size = alloc.remaining_bytes_in_current_chunk(); for (std::size_t i = 0; i < first_chunk_size; ++i) { @@ -141,7 +141,7 @@ TEST(Test_Linked_Bump_Allocator, constexpr std::size_t chunk_size = 4096 - sizeof(void*) * 2; // Implementation detail. - Linked_Bump_Allocator alloc("test"); + Linked_Bump_Allocator alloc("test"); [[maybe_unused]] Span padding = alloc.allocate_span(chunk_size); ASSERT_EQ(alloc.remaining_bytes_in_current_chunk(), 0) << "First chunk should be consumed entirely"; @@ -157,12 +157,12 @@ TEST(Test_Linked_Bump_Allocator, } TEST(Test_Linked_Bump_Allocator, rewinding_within_chunk_reuses_memory) { - Linked_Bump_Allocator<1> alloc("test"); + Linked_Bump_Allocator alloc("test"); [[maybe_unused]] char* byte_0 = alloc.new_object(); [[maybe_unused]] char* byte_1 = alloc.new_object(); - typename Linked_Bump_Allocator<1>::Rewind_State rewind = + typename Linked_Bump_Allocator::Rewind_State rewind = alloc.prepare_for_rewind(); char* byte_2a = alloc.new_object(); char* byte_3a = alloc.new_object(); @@ -178,14 +178,14 @@ TEST(Test_Linked_Bump_Allocator, rewinding_within_chunk_reuses_memory) { TEST(Test_Linked_Bump_Allocator, rewinding_across_chunk_reuses_memory_of_first_chunk) { - Linked_Bump_Allocator<1> alloc("test"); + Linked_Bump_Allocator alloc("test"); // First chunk: std::size_t first_chunk_size = alloc.remaining_bytes_in_current_chunk(); for (std::size_t i = 0; i < first_chunk_size / 2; ++i) { [[maybe_unused]] char* byte = alloc.new_object(); } - typename Linked_Bump_Allocator<1>::Rewind_State rewind = + typename Linked_Bump_Allocator::Rewind_State rewind = alloc.prepare_for_rewind(); std::vector reusable_allocations; for (std::size_t i = first_chunk_size / 2; i < first_chunk_size; ++i) { @@ -213,14 +213,14 @@ TEST(Test_Linked_Bump_Allocator, TEST(Test_Linked_Bump_Allocator, rewinding_across_chunk_uses_unallocated_memory_of_first_chunk) { - Linked_Bump_Allocator<1> alloc("test"); + Linked_Bump_Allocator alloc("test"); // First chunk: std::size_t first_chunk_size = alloc.remaining_bytes_in_current_chunk(); for (std::size_t i = 0; i < first_chunk_size / 2; ++i) { [[maybe_unused]] char* byte = alloc.new_object(); } - typename Linked_Bump_Allocator<1>::Rewind_State rewind = + typename Linked_Bump_Allocator::Rewind_State rewind = alloc.prepare_for_rewind(); // Second chunk: @@ -242,7 +242,7 @@ TEST(Test_Linked_Bump_Allocator, } TEST(Test_Linked_Bump_Allocator, last_allocation_can_grow_in_place) { - Linked_Bump_Allocator<1> alloc("test"); + Linked_Bump_Allocator alloc("test"); Span array = alloc.allocate_uninitialized_span(10); bool ok = alloc.try_grow_array_in_place(array.data(), 10, 20); EXPECT_TRUE(ok); @@ -257,7 +257,7 @@ TEST(Test_Linked_Bump_Allocator, last_allocation_can_grow_in_place) { TEST(Test_Linked_Bump_Allocator, last_allocation_cannot_grow_beyond_current_chunk) { - Linked_Bump_Allocator<1> alloc("test"); + Linked_Bump_Allocator alloc("test"); [[maybe_unused]] char* first_byte = alloc.new_object(); // Allocate the first chunk. @@ -280,7 +280,7 @@ TEST(Test_Linked_Bump_Allocator, } TEST(Test_Linked_Bump_Allocator, non_last_allocation_cannot_grow) { - Linked_Bump_Allocator<1> alloc("test"); + Linked_Bump_Allocator alloc("test"); Span array = alloc.allocate_uninitialized_span(10); [[maybe_unused]] char* last = alloc.new_object(); bool ok = alloc.try_grow_array_in_place(array.data(), 10, 20); diff --git a/test/test-vector.cpp b/test/test-vector.cpp index fd5181cf4f..1f928fb643 100644 --- a/test/test-vector.cpp +++ b/test/test-vector.cpp @@ -15,7 +15,7 @@ using ::testing::IsEmpty; namespace quick_lint_js { namespace { TEST(Test_Bump_Vector, empty) { - Linked_Bump_Allocator alloc("test"); + Linked_Bump_Allocator alloc("test"); Bump_Vector v("test", &alloc); EXPECT_TRUE(v.empty()); EXPECT_EQ(v.size(), 0); @@ -23,7 +23,7 @@ TEST(Test_Bump_Vector, empty) { } TEST(Test_Bump_Vector, append_into_reserved_memory) { - Linked_Bump_Allocator alloc("test"); + Linked_Bump_Allocator alloc("test"); Bump_Vector v("test", &alloc); v.reserve(2); EXPECT_EQ(v.capacity(), 2); @@ -41,7 +41,7 @@ TEST(Test_Bump_Vector, append_into_reserved_memory) { } TEST(Test_Bump_Vector, reserve_0_does_nothing) { - Linked_Bump_Allocator alloc("test"); + Linked_Bump_Allocator alloc("test"); Bump_Vector v("test", &alloc); v.reserve(0); @@ -58,7 +58,7 @@ TEST(Test_Bump_Vector, reserve_0_does_nothing) { } TEST(Test_Bump_Vector, append_into_new_memory) { - Linked_Bump_Allocator alloc("test"); + Linked_Bump_Allocator alloc("test"); Bump_Vector v("test", &alloc); EXPECT_EQ(v.capacity(), 0); EXPECT_EQ(v.size(), 0); @@ -75,7 +75,7 @@ TEST(Test_Bump_Vector, append_into_new_memory) { } TEST(Test_Bump_Vector, growing_allocation_in_place) { - Linked_Bump_Allocator alloc("test"); + Linked_Bump_Allocator alloc("test"); Bump_Vector v("test", &alloc); v.reserve(2); @@ -91,7 +91,7 @@ TEST(Test_Bump_Vector, growing_allocation_in_place) { } TEST(Test_Bump_Vector, growing_allocation_by_copy) { - Linked_Bump_Allocator alloc("test"); + Linked_Bump_Allocator alloc("test"); Bump_Vector v("test", &alloc); v.reserve(2); @@ -117,7 +117,7 @@ TEST(Test_Bump_Vector, growing_allocation_by_copy) { } TEST(Test_Bump_Vector, resize_allows_same_size) { - Linked_Bump_Allocator alloc("test"); + Linked_Bump_Allocator alloc("test"); Bump_Vector v("test", &alloc); v.emplace_back(100); v.emplace_back(200); @@ -136,7 +136,7 @@ TEST(Test_Bump_Vector, resize_allows_same_size) { } TEST(Test_Bump_Vector, resize_allows_shrinking) { - Linked_Bump_Allocator alloc("test"); + Linked_Bump_Allocator alloc("test"); Bump_Vector v("test", &alloc); v.emplace_back(100); v.emplace_back(200); @@ -157,7 +157,7 @@ TEST(Test_Bump_Vector, resize_allows_shrinking) { } TEST(Test_Bump_Vector, resize_allows_growing_within_capacity) { - Linked_Bump_Allocator alloc("test"); + Linked_Bump_Allocator alloc("test"); Bump_Vector v("test", &alloc); v.emplace_back(100); v.emplace_back(200); @@ -178,7 +178,7 @@ TEST(Test_Bump_Vector, resize_allows_growing_within_capacity) { } TEST(Test_Bump_Vector, resize_allows_growing_outside_capacity) { - Linked_Bump_Allocator alloc("test"); + Linked_Bump_Allocator alloc("test"); Bump_Vector v("test", &alloc); v.emplace_back(100); v.emplace_back(200); @@ -194,7 +194,7 @@ TEST(Test_Bump_Vector, resize_allows_growing_outside_capacity) { } TEST(Test_Bump_Vector, pop_back_shrinks_vector) { - Linked_Bump_Allocator alloc("test"); + Linked_Bump_Allocator alloc("test"); Bump_Vector v("test", &alloc); v.push_back(100); v.push_back(200); @@ -206,7 +206,7 @@ TEST(Test_Bump_Vector, pop_back_shrinks_vector) { } TEST(Test_Bump_Vector, pop_back_then_push_back_reuses_memory) { - Linked_Bump_Allocator alloc("test"); + Linked_Bump_Allocator alloc("test"); Bump_Vector v("test", &alloc); v.push_back(100); v.push_back(200); @@ -223,7 +223,7 @@ TEST(Test_Bump_Vector, pop_back_then_push_back_reuses_memory) { } TEST(Test_Bump_Vector, move_constructing_clears_old_vector) { - Linked_Bump_Allocator alloc("test"); + Linked_Bump_Allocator alloc("test"); Bump_Vector v("test", &alloc); v.emplace_back(100); v.emplace_back(200); @@ -233,7 +233,7 @@ TEST(Test_Bump_Vector, move_constructing_clears_old_vector) { } TEST(Test_Bump_Vector, move_constructor_preserves_pointers) { - Linked_Bump_Allocator alloc("test"); + Linked_Bump_Allocator alloc("test"); Bump_Vector v("test", &alloc); v.emplace_back(100); v.emplace_back(200); From 67da3d41c764a1fc1e7d6f36bda3e79e55488461 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Fri, 3 Nov 2023 23:28:37 -0400 Subject: [PATCH 085/117] fix(container): fix compilation with QLJS_DEBUG=1 When compiled with QLJS_DEBUG=1, Linked_Bump_Allocator enables extra checking. This checking code does not compile. Fix these build errors. --- src/quick-lint-js/container/linked-bump-allocator.h | 4 ++-- test/test-linked-bump-allocator.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/quick-lint-js/container/linked-bump-allocator.h b/src/quick-lint-js/container/linked-bump-allocator.h index 8d720c6a7e..f8d2b0ccf1 100644 --- a/src/quick-lint-js/container/linked-bump-allocator.h +++ b/src/quick-lint-js/container/linked-bump-allocator.h @@ -211,7 +211,7 @@ class Linked_Bump_Allocator final : public Memory_Resource { private: #if QLJS_DEBUG_BUMP_ALLOCATOR - explicit disable_guard(linked_bump_allocator* alloc) : alloc_(alloc) { + explicit Disable_Guard(Linked_Bump_Allocator* alloc) : alloc_(alloc) { this->alloc_->disabled_count_ += 1; } #else @@ -219,7 +219,7 @@ class Linked_Bump_Allocator final : public Memory_Resource { #endif #if QLJS_DEBUG_BUMP_ALLOCATOR - linked_bump_allocator* alloc_; + Linked_Bump_Allocator* alloc_; #endif friend class Linked_Bump_Allocator; diff --git a/test/test-linked-bump-allocator.cpp b/test/test-linked-bump-allocator.cpp index a0460aac62..e82279ffa7 100644 --- a/test/test-linked-bump-allocator.cpp +++ b/test/test-linked-bump-allocator.cpp @@ -296,7 +296,7 @@ TEST(Test_Linked_Bump_Allocator, non_last_allocation_cannot_grow) { (defined(GTEST_HAS_DEATH_TEST) && GTEST_HAS_DEATH_TEST) TEST(Test_Linked_Bump_Allocator, cannot_allocate_when_disabled) { auto check = [] { - linked_bump_allocator<1> alloc("test"); + Linked_Bump_Allocator alloc("test"); auto disable_guard = alloc.disable(); // The following line should crash: [[maybe_unused]] char* c = alloc.new_object(); @@ -308,7 +308,7 @@ TEST(Test_Linked_Bump_Allocator, cannot_allocate_when_disabled) { #if QLJS_DEBUG_BUMP_ALLOCATOR TEST(Test_Linked_Bump_Allocator, can_allocate_after_disabling_then_reenabling) { - linked_bump_allocator<1> alloc("test"); + Linked_Bump_Allocator alloc("test"); { auto disable_guard = alloc.disable(); // Destruct disable_guard, re-enabling allocation. From b0b20071a88dc98e28c4d1369c0e266e00bdece1 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Fri, 3 Nov 2023 23:28:37 -0400 Subject: [PATCH 086/117] feat(build): add QUICK_LINT_JS_FEATURE_EXTRA_DEBUG The QLJS_DEBUG macro is used in a few places but is not set by a build system knob. Add QUICK_LINT_JS_FEATURE_EXTRA_DEBUG which, when enabled, causes QLJS_SLOW_ASSERT and other things to activate. --- .github/workflows/build-and-test.yml | 2 +- CMakeLists.txt | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 6babaadcbe..dc40e35c26 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -23,7 +23,7 @@ jobs: - {runs_on: ubuntu-latest, name: "GCC 10 ASAN+UBSAN", container: "ghcr.io/quick-lint/quick-lint-js-github-gcc:v1", CC: gcc-10, CXX: g++-10, CFLAGS: "-fsanitize=address,undefined -fsanitize-address-use-after-scope -fno-sanitize-recover=address,undefined -fuse-ld=gold", CMAKE_BUILD_TYPE: "Debug", WARNINGS: "-Werror;{0}", CMAKE_FLAGS: "-G Ninja", ASAN_OPTIONS: "strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1"} - {runs_on: ubuntu-latest, name: "GCC 10 Release", container: "ghcr.io/quick-lint/quick-lint-js-github-gcc:v1", CC: gcc-10, CXX: g++-10, CFLAGS: "", CMAKE_BUILD_TYPE: "Release", WARNINGS: "-Werror;{0}"} # TODO(strager): Enable Ninja for this job. - - {runs_on: ubuntu-latest, name: "GCC 10 dev", container: "ghcr.io/quick-lint/quick-lint-js-github-gcc:v1", CC: gcc-10, CXX: g++-10, CFLAGS: "", CMAKE_BUILD_TYPE: "Debug", WARNINGS: "-Werror;{0}", CMAKE_FLAGS: "-DQUICK_LINT_JS_FEATURE_DEBUG_SERVER=ON -DQUICK_LINT_JS_FEATURE_VECTOR_PROFILING=ON"} + - {runs_on: ubuntu-latest, name: "GCC 10 dev", container: "ghcr.io/quick-lint/quick-lint-js-github-gcc:v1", CC: gcc-10, CXX: g++-10, CFLAGS: "", CMAKE_BUILD_TYPE: "Debug", WARNINGS: "-Werror;{0}", CMAKE_FLAGS: "-DQUICK_LINT_JS_FEATURE_DEBUG_SERVER=ON -DQUICK_LINT_JS_FEATURE_EXTRA_DEBUG=ON -DQUICK_LINT_JS_FEATURE_VECTOR_PROFILING=ON"} # TODO(strager): Also test MinGW-based builds. - {runs_on: windows-latest, name: "MSVC", CFLAGS: "", CMAKE_BUILD_TYPE: "Debug", WARNINGS: ""} - {runs_on: windows-latest, name: "MSVC Release", CFLAGS: "", CMAKE_BUILD_TYPE: "Release", WARNINGS: ""} diff --git a/CMakeLists.txt b/CMakeLists.txt index 711a69c949..c2053cf093 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,6 +125,11 @@ option( "Enable the HTTP monitoring server at run-time" FALSE ) +option( + QUICK_LINT_JS_FEATURE_EXTRA_DEBUG + "Enable extra slow debug checking at run-time" + FALSE +) option( QUICK_LINT_JS_FEATURE_VECTOR_PROFILING "Enable the QLJS_DUMP_VECTORS option at run-time" @@ -147,6 +152,9 @@ quick_lint_js_disable_unwanted_warnings() if (WIN32) add_definitions(-D_WIN32_WINNT=0x0602) endif () +if (QUICK_LINT_JS_FEATURE_EXTRA_DEBUG) + add_compile_definitions(QLJS_DEBUG) +endif () # HACK(strager): Work around issues with CI. We should consider using # find_package(Python3) instead. From 406402492e2aa0caab94fa36e31a0c13a67cc623 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 4 Nov 2023 20:16:10 -0400 Subject: [PATCH 087/117] refactor(container): split linked-bump-allocator.h into .h/.cpp Kick code out of the linked-bump-allocator.h header to make it easier to read. This might also slightly improve compile times. --- src/CMakeLists.txt | 3 +- src/quick-lint-js/container/allocator.h | 9 +- .../container/linked-bump-allocator.cpp | 195 ++++++++++++++++++ .../container/linked-bump-allocator.h | 155 ++------------ 4 files changed, 219 insertions(+), 143 deletions(-) create mode 100644 src/quick-lint-js/container/linked-bump-allocator.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3f7c793819..a37f78e4fd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -199,6 +199,8 @@ quick_lint_js_add_library( quick-lint-js/cli/cli-location.cpp quick-lint-js/cli/cli-location.h quick-lint-js/container/flexible-array.h + quick-lint-js/container/linked-bump-allocator.cpp + quick-lint-js/container/linked-bump-allocator.h quick-lint-js/container/padded-string.cpp quick-lint-js/container/padded-string.h quick-lint-js/container/string-view.h @@ -295,7 +297,6 @@ quick_lint_js_add_library( quick-lint-js/container/hash-map.h quick-lint-js/container/hash-set.h quick-lint-js/container/hash.h - quick-lint-js/container/linked-bump-allocator.h quick-lint-js/container/linked-vector.h quick-lint-js/container/optional.h quick-lint-js/container/result.h diff --git a/src/quick-lint-js/container/allocator.h b/src/quick-lint-js/container/allocator.h index f24af7fab0..2c1f3fb0ea 100644 --- a/src/quick-lint-js/container/allocator.h +++ b/src/quick-lint-js/container/allocator.h @@ -3,20 +3,23 @@ #pragma once +#include #include +#include #include #include namespace quick_lint_js { -QLJS_WARNING_PUSH -QLJS_WARNING_IGNORE_GCC("-Wnull-dereference") template T* new_object(Memory_Resource* memory, Args&&... args) { T* result = reinterpret_cast(memory->allocate(sizeof(T), alignof(T))); + if (result == nullptr) { + QLJS_SLOW_ASSERT(result != nullptr); + QLJS_UNREACHABLE(); // Silence GCC warnings. + } result = new (result) T(std::forward(args)...); return result; } -QLJS_WARNING_POP template void delete_object(Memory_Resource* memory, T* object) { diff --git a/src/quick-lint-js/container/linked-bump-allocator.cpp b/src/quick-lint-js/container/linked-bump-allocator.cpp new file mode 100644 index 0000000000..44d7026303 --- /dev/null +++ b/src/quick-lint-js/container/linked-bump-allocator.cpp @@ -0,0 +1,195 @@ +// Copyright (C) 2020 Matthew "strager" Glazar +// See end of file for extended copyright information. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if QLJS_HAVE_SANITIZER_ASAN_INTERFACE_H +#include +#endif + +namespace quick_lint_js { +Linked_Bump_Allocator::Linked_Bump_Allocator(const char* debug_owner) { + static_cast(debug_owner); +} + +Linked_Bump_Allocator::~Linked_Bump_Allocator() { this->release(); } + +void Linked_Bump_Allocator::release() { + Chunk* c = this->chunk_; + while (c) { + Chunk* previous = c->previous; + Chunk::destroy_header_and_deallocate(new_delete_resource(), c); + c = previous; + } + this->chunk_ = nullptr; + this->next_allocation_ = nullptr; + this->chunk_end_ = nullptr; +} + +void Linked_Bump_Allocator::rewind(Rewind_State&& r) { + bool allocated_new_chunk = this->chunk_ != r.chunk_; + if (allocated_new_chunk) { + // If we rewound to exactly where we were before, we might rewind near the + // end of a chunk. Allocations would soon need a new chunk. + // + // Avoid straddling near the end of a chunk by using a new chunk (which + // was already allocated). + // + // TODO(strager): Should we use the *oldest* chunk or the *newest* chunk? + // Here we pick the *oldest* chunk. + Chunk* c = this->chunk_; + QLJS_ASSERT(c); + while (c->previous != r.chunk_) { + Chunk* previous = c->previous; + Chunk::destroy_header_and_deallocate(new_delete_resource(), c); + c = previous; + QLJS_ASSERT(c); + } + this->chunk_ = c; + this->next_allocation_ = c->flexible_capacity_begin(); + this->chunk_end_ = c->flexible_capacity_end(); + } else { + this->chunk_ = r.chunk_; + this->next_allocation_ = r.next_allocation_; + this->chunk_end_ = r.chunk_end_; + } + this->did_deallocate_bytes( + this->next_allocation_, + narrow_cast(this->chunk_end_ - this->next_allocation_)); +} + +Linked_Bump_Allocator::Disable_Guard::~Disable_Guard() { +#if QLJS_DEBUG_BUMP_ALLOCATOR + this->alloc_->disabled_count_ -= 1; +#endif +} + +Linked_Bump_Allocator::Disable_Guard::Disable_Guard([ + [maybe_unused]] Linked_Bump_Allocator* alloc) +#if QLJS_DEBUG_BUMP_ALLOCATOR + : alloc_(alloc) +#endif +{ +#if QLJS_DEBUG_BUMP_ALLOCATOR + this->alloc_->disabled_count_ += 1; +#endif +} + +void* Linked_Bump_Allocator::do_allocate(std::size_t bytes, std::size_t align) { + return this->allocate_bytes(bytes, align); +} + +void Linked_Bump_Allocator::do_deallocate(void* p, std::size_t bytes, + [[maybe_unused]] std::size_t align) { + this->deallocate_bytes(p, bytes); +} + +[[nodiscard]] void* Linked_Bump_Allocator::allocate_bytes(std::size_t size, + std::size_t align) { + this->assert_not_disabled(); + QLJS_SLOW_ASSERT(size % align == 0); + + std::uintptr_t next_allocation_int = + reinterpret_cast(this->next_allocation_); + // NOTE(strager): align_up might overflow. If it does, the allocation + // couldn't fit due to alignment alone + // (alignment_padding > this->remaining_bytes_in_current_chunk()). + std::uintptr_t result_int = align_up(next_allocation_int, align); + char* result = reinterpret_cast(result_int); + + // alignment_padding is how much the pointer moved due to alignment, i.e. + // how much padding is necessary due to alignment. + std::uintptr_t alignment_padding = result_int - next_allocation_int; + bool have_enough_space = + (alignment_padding + size) <= this->remaining_bytes_in_current_chunk(); + if (!have_enough_space) [[unlikely]] { + this->append_chunk(maximum(size, this->default_chunk_size), align); + result = this->next_allocation_; + QLJS_ASSERT(is_aligned(result, align)); + } + + this->next_allocation_ = result + size; + this->did_allocate_bytes(result, size); + return result; +} + +void Linked_Bump_Allocator::did_allocate_bytes( + [[maybe_unused]] void* p, [[maybe_unused]] std::size_t size) { +#if QLJS_HAVE_SANITIZER_ASAN_INTERFACE_H + ASAN_UNPOISON_MEMORY_REGION(p, size); +#endif + // TODO(strager): Mark memory as usable for Valgrind. +} + +void Linked_Bump_Allocator::did_deallocate_bytes( + [[maybe_unused]] void* p, [[maybe_unused]] std::size_t size) { +#if QLJS_HAVE_SANITIZER_ASAN_INTERFACE_H + ASAN_POISON_MEMORY_REGION(p, size); +#endif + // TODO(strager): Mark memory as unusable for Valgrind. +} + +void Linked_Bump_Allocator::append_chunk(std::size_t size, std::size_t align) { + // Over-alignment is tested by + // NOTE[Linked_Bump_Allocator-append_chunk-alignment]. + bool is_over_aligned = align > Chunk::capacity_alignment; + std::size_t allocated_size = size; + if (is_over_aligned) { + allocated_size += align; + } + this->chunk_ = Chunk::allocate_and_construct_header( + new_delete_resource(), allocated_size, this->chunk_); + std::uintptr_t next_allocation_int = + reinterpret_cast(this->chunk_->flexible_capacity_begin()); + if (is_over_aligned) { + next_allocation_int = align_up(next_allocation_int, align); + } + this->next_allocation_ = reinterpret_cast(next_allocation_int); + this->chunk_end_ = this->chunk_->flexible_capacity_end(); + QLJS_ASSERT(is_aligned(this->next_allocation_, align)); + QLJS_ASSERT(this->remaining_bytes_in_current_chunk() >= size); +} + +void Linked_Bump_Allocator::assert_not_disabled() const { +#if QLJS_DEBUG_BUMP_ALLOCATOR + QLJS_ALWAYS_ASSERT(!this->is_disabled()); +#endif +} + +#if QLJS_DEBUG_BUMP_ALLOCATOR +bool Linked_Bump_Allocator::is_disabled() const { + return this->disabled_count_ > 0; +} +#endif +} + +// quick-lint-js finds bugs in JavaScript programs. +// Copyright (C) 2020 Matthew "strager" Glazar +// +// This file is part of quick-lint-js. +// +// quick-lint-js is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// quick-lint-js is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with quick-lint-js. If not, see . diff --git a/src/quick-lint-js/container/linked-bump-allocator.h b/src/quick-lint-js/container/linked-bump-allocator.h index f8d2b0ccf1..b66a8b2771 100644 --- a/src/quick-lint-js/container/linked-bump-allocator.h +++ b/src/quick-lint-js/container/linked-bump-allocator.h @@ -4,23 +4,15 @@ #pragma once #include -#include +#include #include #include #include -#include -#include #include #include #include -#include -#include #include -#if QLJS_HAVE_SANITIZER_ASAN_INTERFACE_H -#include -#endif - #if defined(QLJS_DEBUG) && QLJS_DEBUG #define QLJS_DEBUG_BUMP_ALLOCATOR 1 #else @@ -41,26 +33,14 @@ class Linked_Bump_Allocator final : public Memory_Resource { using Chunk = Flexible_Array; public: - explicit Linked_Bump_Allocator(const char* debug_owner) { - static_cast(debug_owner); - } + explicit Linked_Bump_Allocator(const char* debug_owner); Linked_Bump_Allocator(const Linked_Bump_Allocator&) = delete; Linked_Bump_Allocator& operator=(const Linked_Bump_Allocator&) = delete; - ~Linked_Bump_Allocator() override { this->release(); } + ~Linked_Bump_Allocator() override; - void release() { - Chunk* c = this->chunk_; - while (c) { - Chunk* previous = c->previous; - Chunk::destroy_header_and_deallocate(new_delete_resource(), c); - c = previous; - } - this->chunk_ = nullptr; - this->next_allocation_ = nullptr; - this->chunk_end_ = nullptr; - } + void release(); struct Rewind_State { // Private to linked_bump_allocator. Do not use. @@ -96,37 +76,7 @@ class Linked_Bump_Allocator final : public Memory_Resource { }; } - void rewind(Rewind_State&& r) { - bool allocated_new_chunk = this->chunk_ != r.chunk_; - if (allocated_new_chunk) { - // If we rewound to exactly where we were before, we might rewind near the - // end of a chunk. Allocations would soon need a new chunk. - // - // Avoid straddling near the end of a chunk by using a new chunk (which - // was already allocated). - // - // TODO(strager): Should we use the *oldest* chunk or the *newest* chunk? - // Here we pick the *oldest* chunk. - Chunk* c = this->chunk_; - QLJS_ASSERT(c); - while (c->previous != r.chunk_) { - Chunk* previous = c->previous; - Chunk::destroy_header_and_deallocate(new_delete_resource(), c); - c = previous; - QLJS_ASSERT(c); - } - this->chunk_ = c; - this->next_allocation_ = c->flexible_capacity_begin(); - this->chunk_end_ = c->flexible_capacity_end(); - } else { - this->chunk_ = r.chunk_; - this->next_allocation_ = r.next_allocation_; - this->chunk_end_ = r.chunk_end_; - } - this->did_deallocate_bytes( - this->next_allocation_, - narrow_cast(this->chunk_end_ - this->next_allocation_)); - } + void rewind(Rewind_State&& r); [[nodiscard]] Rewind_Guard make_rewind_guard() { return Rewind_Guard(this); } @@ -203,20 +153,10 @@ class Linked_Bump_Allocator final : public Memory_Resource { class Disable_Guard { public: - ~Disable_Guard() { -#if QLJS_DEBUG_BUMP_ALLOCATOR - this->alloc_->disabled_count_ -= 1; -#endif - } + ~Disable_Guard(); private: -#if QLJS_DEBUG_BUMP_ALLOCATOR - explicit Disable_Guard(Linked_Bump_Allocator* alloc) : alloc_(alloc) { - this->alloc_->disabled_count_ += 1; - } -#else - explicit Disable_Guard(Linked_Bump_Allocator*) {} -#endif + explicit Disable_Guard(Linked_Bump_Allocator*); #if QLJS_DEBUG_BUMP_ALLOCATOR Linked_Bump_Allocator* alloc_; @@ -228,14 +168,9 @@ class Linked_Bump_Allocator final : public Memory_Resource { [[nodiscard]] Disable_Guard disable() { return Disable_Guard(this); } protected: - void* do_allocate(std::size_t bytes, std::size_t align) override { - return this->allocate_bytes(bytes, align); - } - + void* do_allocate(std::size_t bytes, std::size_t align) override; void do_deallocate(void* p, std::size_t bytes, - [[maybe_unused]] std::size_t align) override { - this->deallocate_bytes(p, bytes); - } + [[maybe_unused]] std::size_t align) override; private: struct alignas(alignof(void*)) Chunk_Header { @@ -246,33 +181,7 @@ class Linked_Bump_Allocator final : public Memory_Resource { static inline constexpr std::size_t default_chunk_size = 4096 - sizeof(Chunk); - [[nodiscard]] void* allocate_bytes(std::size_t size, std::size_t align) { - this->assert_not_disabled(); - QLJS_SLOW_ASSERT(size % align == 0); - - std::uintptr_t next_allocation_int = - reinterpret_cast(this->next_allocation_); - // NOTE(strager): align_up might overflow. If it does, the allocation - // couldn't fit due to alignment alone - // (alignment_padding > this->remaining_bytes_in_current_chunk()). - std::uintptr_t result_int = align_up(next_allocation_int, align); - char* result = reinterpret_cast(result_int); - - // alignment_padding is how much the pointer moved due to alignment, i.e. - // how much padding is necessary due to alignment. - std::uintptr_t alignment_padding = result_int - next_allocation_int; - bool have_enough_space = - (alignment_padding + size) <= this->remaining_bytes_in_current_chunk(); - if (!have_enough_space) [[unlikely]] { - this->append_chunk(maximum(size, this->default_chunk_size), align); - result = this->next_allocation_; - QLJS_ASSERT(is_aligned(result, align)); - } - - this->next_allocation_ = result + size; - this->did_allocate_bytes(result, size); - return result; - } + [[nodiscard]] void* allocate_bytes(std::size_t size, std::size_t align); void deallocate_bytes([[maybe_unused]] void* p, [[maybe_unused]] std::size_t size) { @@ -280,50 +189,17 @@ class Linked_Bump_Allocator final : public Memory_Resource { } void did_allocate_bytes([[maybe_unused]] void* p, - [[maybe_unused]] std::size_t size) { -#if QLJS_HAVE_SANITIZER_ASAN_INTERFACE_H - ASAN_UNPOISON_MEMORY_REGION(p, size); -#endif - // TODO(strager): Mark memory as usable for Valgrind. - } + [[maybe_unused]] std::size_t size); void did_deallocate_bytes([[maybe_unused]] void* p, - [[maybe_unused]] std::size_t size) { -#if QLJS_HAVE_SANITIZER_ASAN_INTERFACE_H - ASAN_POISON_MEMORY_REGION(p, size); -#endif - // TODO(strager): Mark memory as unusable for Valgrind. - } + [[maybe_unused]] std::size_t size); - void append_chunk(std::size_t size, std::size_t align) { - // Over-alignment is tested by - // NOTE[Linked_Bump_Allocator-append_chunk-alignment]. - bool is_over_aligned = align > Chunk::capacity_alignment; - std::size_t allocated_size = size; - if (is_over_aligned) { - allocated_size += align; - } - this->chunk_ = Chunk::allocate_and_construct_header( - new_delete_resource(), allocated_size, this->chunk_); - std::uintptr_t next_allocation_int = reinterpret_cast( - this->chunk_->flexible_capacity_begin()); - if (is_over_aligned) { - next_allocation_int = align_up(next_allocation_int, align); - } - this->next_allocation_ = reinterpret_cast(next_allocation_int); - this->chunk_end_ = this->chunk_->flexible_capacity_end(); - QLJS_ASSERT(is_aligned(this->next_allocation_, align)); - QLJS_ASSERT(this->remaining_bytes_in_current_chunk() >= size); - } + void append_chunk(std::size_t size, std::size_t align); - void assert_not_disabled() const { -#if QLJS_DEBUG_BUMP_ALLOCATOR - QLJS_ALWAYS_ASSERT(!this->is_disabled()); -#endif - } + void assert_not_disabled() const; #if QLJS_DEBUG_BUMP_ALLOCATOR - bool is_disabled() const { return this->disabled_count_ > 0; } + bool is_disabled() const; #endif Chunk* chunk_ = nullptr; @@ -331,6 +207,7 @@ class Linked_Bump_Allocator final : public Memory_Resource { char* chunk_end_ = nullptr; #if QLJS_DEBUG_BUMP_ALLOCATOR + // Used only if QLJS_DEBUG_BUMP_ALLOCATOR. int disabled_count_ = 0; #endif }; From 0a705e764502d86ac3eb86a1833b420a01e1f691 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 4 Nov 2023 20:16:10 -0400 Subject: [PATCH 088/117] refactor(container): reduce template code bloat Only a tiny piece of try_grow_array_in_place depends on the template parameter. Refactor this function template such that most of it is in a non-template function. This should reduce binary size slightly. --- .../container/linked-bump-allocator.cpp | 20 +++++++++++++++ .../container/linked-bump-allocator.h | 25 +++++-------------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/quick-lint-js/container/linked-bump-allocator.cpp b/src/quick-lint-js/container/linked-bump-allocator.cpp index 44d7026303..adeaea3d40 100644 --- a/src/quick-lint-js/container/linked-bump-allocator.cpp +++ b/src/quick-lint-js/container/linked-bump-allocator.cpp @@ -97,6 +97,26 @@ void Linked_Bump_Allocator::do_deallocate(void* p, std::size_t bytes, this->deallocate_bytes(p, bytes); } +bool Linked_Bump_Allocator::try_grow_array_in_place_impl( + char* array, std::size_t old_byte_size, std::size_t new_byte_size) { + this->assert_not_disabled(); + QLJS_ASSERT(new_byte_size > old_byte_size); + bool array_is_last_allocation = + array + old_byte_size == this->next_allocation_; + if (!array_is_last_allocation) { + // We can't grow because something else was already allocated. + return false; + } + + std::size_t extra_bytes = new_byte_size - old_byte_size; + if (extra_bytes > this->remaining_bytes_in_current_chunk()) { + return false; + } + this->did_allocate_bytes(this->next_allocation_, extra_bytes); + this->next_allocation_ += extra_bytes; + return true; +} + [[nodiscard]] void* Linked_Bump_Allocator::allocate_bytes(std::size_t size, std::size_t align) { this->assert_not_disabled(); diff --git a/src/quick-lint-js/container/linked-bump-allocator.h b/src/quick-lint-js/container/linked-bump-allocator.h index b66a8b2771..5995e737bb 100644 --- a/src/quick-lint-js/container/linked-bump-allocator.h +++ b/src/quick-lint-js/container/linked-bump-allocator.h @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -127,24 +126,9 @@ class Linked_Bump_Allocator final : public Memory_Resource { template bool try_grow_array_in_place(T* array, std::size_t old_size, std::size_t new_size) { - this->assert_not_disabled(); - QLJS_ASSERT(new_size > old_size); - std::size_t old_byte_size = old_size * sizeof(T); - bool array_is_last_allocation = - reinterpret_cast(array) + old_byte_size == - this->next_allocation_; - if (!array_is_last_allocation) { - // We can't grow because something else was already allocated. - return false; - } - - std::size_t extra_bytes = (new_size - old_size) * sizeof(T); - if (extra_bytes > this->remaining_bytes_in_current_chunk()) { - return false; - } - this->did_allocate_bytes(this->next_allocation_, extra_bytes); - this->next_allocation_ += extra_bytes; - return true; + return this->try_grow_array_in_place_impl(reinterpret_cast(array), + old_size * sizeof(T), + new_size * sizeof(T)); } std::size_t remaining_bytes_in_current_chunk() const { @@ -181,6 +165,9 @@ class Linked_Bump_Allocator final : public Memory_Resource { static inline constexpr std::size_t default_chunk_size = 4096 - sizeof(Chunk); + bool try_grow_array_in_place_impl(char* array, std::size_t old_byte_size, + std::size_t new_byte_size); + [[nodiscard]] void* allocate_bytes(std::size_t size, std::size_t align); void deallocate_bytes([[maybe_unused]] void* p, From e0c6e195f077da1858a3ac7559b31f08aa3b2d19 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 4 Nov 2023 20:16:10 -0400 Subject: [PATCH 089/117] refactor(container): remove allocator template param from Bump_Vector Bump_Vector is only instantiated with Linked_Bump_Allocator for Bump_Allocator. Inline Bump_Allocator, making some code less verbose. --- src/quick-lint-js/c-api-diag-reporter.h | 9 +++--- src/quick-lint-js/cli/options.cpp | 9 +++--- .../container/vector-profiler.cpp | 6 ++-- src/quick-lint-js/container/vector.h | 20 ++++++------ src/quick-lint-js/debug/find-debug-server.cpp | 18 ++++------- src/quick-lint-js/diag/diag-code-list.cpp | 29 +++++++---------- src/quick-lint-js/diag/diag-code-list.h | 8 ++--- src/quick-lint-js/fe/expression.h | 6 ++-- src/quick-lint-js/fe/lex.cpp | 4 +-- src/quick-lint-js/fe/parse-class.cpp | 13 ++++---- src/quick-lint-js/fe/parse-expression.cpp | 4 +-- src/quick-lint-js/fe/parse-statement.cpp | 8 ++--- src/quick-lint-js/fe/parse.cpp | 4 +-- src/quick-lint-js/fe/parse.h | 2 +- src/quick-lint-js/fe/token.h | 2 +- src/quick-lint-js/i18n/po-parser.cpp | 6 ++-- .../i18n/translation-table-compiler.cpp | 6 ++-- src/quick-lint-js/i18n/translation.cpp | 6 ++-- src/quick-lint-js/io/event-loop-poll.cpp | 6 ++-- .../lsp/lsp-workspace-configuration.h | 2 +- src/quick-lint-js/port/child-process.cpp | 5 ++- src/quick-lint-js/reflection/cxx-parser.cpp | 4 +-- src/quick-lint-js/reflection/cxx-parser.h | 8 ++--- test/quick-lint-js/tjson.cpp | 4 +-- test/test-vector.cpp | 32 +++++++++---------- tools/compile-translations.cpp | 6 ++-- tools/generate-trace-sources.cpp | 13 +++----- 27 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/quick-lint-js/c-api-diag-reporter.h b/src/quick-lint-js/c-api-diag-reporter.h index 3e1cfe6f5f..4338b64b99 100644 --- a/src/quick-lint-js/c-api-diag-reporter.h +++ b/src/quick-lint-js/c-api-diag-reporter.h @@ -42,8 +42,8 @@ class C_API_Diag_Reporter final : public Diag_Reporter { Translator translator_; Monotonic_Allocator allocator_{"C_API_Diag_Reporter::allocator_"}; - Bump_Vector diagnostics_{ - "C_API_Diag_Reporter::diagnostics_", &this->allocator_}; + Bump_Vector diagnostics_{"C_API_Diag_Reporter::diagnostics_", + &this->allocator_}; const Char8 *input_; std::optional locator_; Monotonic_Allocator string_allocator_{ @@ -68,9 +68,8 @@ class C_API_Diag_Formatter private: C_API_Diag_Reporter *reporter_; - Bump_Vector current_message_{ - "C_API_Diag_Reporter::current_message_", - &this->reporter_->string_allocator_}; + Bump_Vector current_message_{"C_API_Diag_Reporter::current_message_", + &this->reporter_->string_allocator_}; }; QLJS_WARNING_PUSH diff --git a/src/quick-lint-js/cli/options.cpp b/src/quick-lint-js/cli/options.cpp index 605f0dbc04..943cdeffbc 100644 --- a/src/quick-lint-js/cli/options.cpp +++ b/src/quick-lint-js/cli/options.cpp @@ -35,13 +35,12 @@ Options parse_options(int argc, char** argv, Monotonic_Allocator* allocator) { const char* arg_var; } next_vim_file_bufnr; - Bump_Vector files_to_lint("files_to_lint", - allocator); - Bump_Vector error_unrecognized_options( + Bump_Vector files_to_lint("files_to_lint", allocator); + Bump_Vector error_unrecognized_options( "error_unrecognized_options", allocator); - Bump_Vector warning_vim_bufnr_without_file( + Bump_Vector warning_vim_bufnr_without_file( "warning_vim_bufnr_without_file", allocator); - Bump_Vector warning_language_without_file( + Bump_Vector warning_language_without_file( "warning_language_without_file", allocator); const char* next_path_for_config_search = nullptr; diff --git a/src/quick-lint-js/container/vector-profiler.cpp b/src/quick-lint-js/container/vector-profiler.cpp index 72bfff3c4f..1a75c1a9a7 100644 --- a/src/quick-lint-js/container/vector-profiler.cpp +++ b/src/quick-lint-js/container/vector-profiler.cpp @@ -146,14 +146,12 @@ Vector_Max_Size_Histogram_By_Owner::histogram( // NOTE(strager): We use Raw_Bump_Vector to prevent vector profiling code from // emitting events itself. - Raw_Bump_Vector + Raw_Bump_Vector out_entries_by_owner(memory); out_entries_by_owner.reserve( narrow_cast(stable_histogram.size())); for (auto &[owner, counts] : stable_histogram) { - Raw_Bump_Vector - out_entries(memory); + Raw_Bump_Vector out_entries(memory); out_entries.reserve(narrow_cast(counts.size())); for (auto &[size, count] : counts) { out_entries.push_back(Trace_Vector_Max_Size_Histogram_Entry{ diff --git a/src/quick-lint-js/container/vector.h b/src/quick-lint-js/container/vector.h index dfa0a301f1..34506ddf1c 100644 --- a/src/quick-lint-js/container/vector.h +++ b/src/quick-lint-js/container/vector.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -91,11 +92,11 @@ class Uninstrumented_Vector : private Vector { using Bump_Vector_Size = std::ptrdiff_t; -template +template class Raw_Bump_Vector { public: using value_type = T; - using allocator_type = Bump_Allocator *; + using allocator_type = Linked_Bump_Allocator *; using size_type = Bump_Vector_Size; using difference_type = Bump_Vector_Size; using reference = T &; @@ -107,7 +108,8 @@ class Raw_Bump_Vector { static_assert(is_winkable_v); - explicit Raw_Bump_Vector(Bump_Allocator *allocator) : allocator_(allocator) {} + explicit Raw_Bump_Vector(Linked_Bump_Allocator *allocator) + : allocator_(allocator) {} Raw_Bump_Vector(const Raw_Bump_Vector &) = delete; Raw_Bump_Vector &operator=(const Raw_Bump_Vector &) = delete; @@ -124,7 +126,7 @@ class Raw_Bump_Vector { ~Raw_Bump_Vector() { this->clear(); } - Bump_Allocator *get_allocator() const { return this->allocator_; } + Linked_Bump_Allocator *get_allocator() const { return this->allocator_; } bool empty() const { return this->data_ == this->data_end_; } size_type size() const { @@ -338,15 +340,15 @@ class Raw_Bump_Vector { T *data_end_ = nullptr; T *capacity_end_ = nullptr; - Bump_Allocator *allocator_; + Linked_Bump_Allocator *allocator_; }; #if QLJS_FEATURE_VECTOR_PROFILING -template -using Bump_Vector = Instrumented_Vector>; +template +using Bump_Vector = Instrumented_Vector>; #else -template -using Bump_Vector = Uninstrumented_Vector>; +template +using Bump_Vector = Uninstrumented_Vector>; #endif } diff --git a/src/quick-lint-js/debug/find-debug-server.cpp b/src/quick-lint-js/debug/find-debug-server.cpp index 3384906c36..6d27eff43b 100644 --- a/src/quick-lint-js/debug/find-debug-server.cpp +++ b/src/quick-lint-js/debug/find-debug-server.cpp @@ -258,8 +258,7 @@ void enumerate_all_process_thread_names(Callback&& callback) { #if defined(__linux__) Span find_debug_servers(Monotonic_Allocator* allocator) { - Bump_Vector debug_servers( - "debug_servers", allocator); + Bump_Vector debug_servers("debug_servers", allocator); enumerate_all_process_thread_names([&](std::string_view process_id_string, std::string_view thread_name) { @@ -302,8 +301,7 @@ void enumerate_all_process_threads(Monotonic_Allocator& allocator, QLJS_ASSERT( narrow_cast(process_id_buffer_size) % sizeof(::pid_t) == 0); - Bump_Vector<::pid_t, Monotonic_Allocator> process_ids("process_ids", - &allocator); + Bump_Vector<::pid_t> process_ids("process_ids", &allocator); // NOTE(strager): It's okay if our buffer is to small. We miss out on some // processes, but they were just created anyway. Harmless race condition. process_ids.resize(narrow_cast(process_id_buffer_size) / @@ -320,8 +318,7 @@ void enumerate_all_process_threads(Monotonic_Allocator& allocator, process_ids.resize(narrow_cast(process_id_buffer_size) / sizeof(int)); - Bump_Vector thread_ids("thread_ids", - &allocator); + Bump_Vector thread_ids("thread_ids", &allocator); constexpr std::size_t initial_thread_ids_buffer_count = 128; // Arbitrary. for (::pid_t process_id : process_ids) { thread_ids.resize(initial_thread_ids_buffer_count); @@ -362,8 +359,7 @@ void enumerate_all_process_threads(Monotonic_Allocator& allocator, Span find_debug_servers(Monotonic_Allocator* allocator) { static constexpr char func[] = "find_debug_servers"; - Bump_Vector debug_servers( - "debug_servers", allocator); + Bump_Vector debug_servers("debug_servers", allocator); enumerate_all_process_threads( *allocator, [&](::pid_t process_id, std::uint64_t thread_id) -> void { ::proc_threadinfo thread_info; @@ -419,8 +415,7 @@ Span find_debug_servers(Monotonic_Allocator* allocator) { size_t own_jid_size; ::kinfo_proc* p; ::kvm_t* kd; - Bump_Vector debug_servers( - "debug_servers", allocator); + Bump_Vector debug_servers("debug_servers", allocator); // Query our own jail id own_jid_size = sizeof own_jid; @@ -519,8 +514,7 @@ void enumerate_all_process_threads(Callback&& callback) { Span find_debug_servers(Monotonic_Allocator* allocator) { static constexpr char func[] = "find_debug_servers"; - Bump_Vector debug_servers( - "debug_servers", allocator); + Bump_Vector debug_servers("debug_servers", allocator); enumerate_all_process_threads([&](::DWORD process_id, ::DWORD thread_id) -> void { Windows_Handle_File thread_handle( diff --git a/src/quick-lint-js/diag/diag-code-list.cpp b/src/quick-lint-js/diag/diag-code-list.cpp index a0bc6b58af..7f44f3499d 100644 --- a/src/quick-lint-js/diag/diag-code-list.cpp +++ b/src/quick-lint-js/diag/diag-code-list.cpp @@ -30,16 +30,13 @@ Parsed_Diag_Code_List parse_diag_code_list(const char* const raw_diag_code_list, return '0' <= c && c <= '9'; }; - Bump_Vector included_codes( - "included_codes", allocator); - Bump_Vector excluded_codes( - "excluded_codes", allocator); - Bump_Vector included_categories( - "included_categories", allocator); - Bump_Vector excluded_categories( - "excluded_categories", allocator); - Bump_Vector unexpected("unexpected", - allocator); + Bump_Vector included_codes("included_codes", allocator); + Bump_Vector excluded_codes("excluded_codes", allocator); + Bump_Vector included_categories("included_categories", + allocator); + Bump_Vector excluded_categories("excluded_categories", + allocator); + Bump_Vector unexpected("unexpected", allocator); bool override_defaults = false; std::size_t i = 0; @@ -143,11 +140,10 @@ void Compiled_Diag_Code_List::add(const Parsed_Diag_Code_List& diag_code_list) { Span Compiled_Diag_Code_List::parse_errors( std::string_view cli_option_name, Monotonic_Allocator* allocator) const { - Bump_Vector errors("errors", - allocator); + Bump_Vector errors("errors", allocator); if (this->has_missing_predicate_error_) { // TODO(#1102): Make this code pretty. - Bump_Vector error("error", allocator); + Bump_Vector error("error", allocator); error += cli_option_name; error += " must be given at least one category or code"sv; errors.emplace_back(error.release_to_string_view()); @@ -157,12 +153,11 @@ Span Compiled_Diag_Code_List::parse_errors( Span Compiled_Diag_Code_List::parse_warnings( Monotonic_Allocator* allocator) const { - Bump_Vector warnings("warnings", - allocator); + Bump_Vector warnings("warnings", allocator); auto check_category = [&](std::string_view category) { if (category != "all") { // TODO(#1102): Make this code pretty. - Bump_Vector warning("warning", allocator); + Bump_Vector warning("warning", allocator); warning += "unknown error category: "sv; warning += category; warnings.emplace_back(warning.release_to_string_view()); @@ -180,7 +175,7 @@ Span Compiled_Diag_Code_List::parse_warnings( for (std::string_view code : this->unknown_codes_) { // TODO(#1102): Make this code pretty. - Bump_Vector warning("warning", allocator); + Bump_Vector warning("warning", allocator); warning += "unknown error code: "sv; warning += code; warnings.emplace_back(warning.release_to_string_view()); diff --git a/src/quick-lint-js/diag/diag-code-list.h b/src/quick-lint-js/diag/diag-code-list.h index 75b10fc81f..0f24005454 100644 --- a/src/quick-lint-js/diag/diag-code-list.h +++ b/src/quick-lint-js/diag/diag-code-list.h @@ -62,12 +62,12 @@ class Compiled_Diag_Code_List { // movable. std::unique_ptr allocator_; - Bump_Vector parsed_diag_code_lists_{ - "parsed_diag_code_lists_", this->allocator_.get()}; + Bump_Vector parsed_diag_code_lists_{"parsed_diag_code_lists_", + this->allocator_.get()}; // Collected errors and warnings: - Bump_Vector unknown_codes_{ - "unknown_codes_", this->allocator_.get()}; + Bump_Vector unknown_codes_{"unknown_codes_", + this->allocator_.get()}; bool has_missing_predicate_error_ = false; }; } diff --git a/src/quick-lint-js/fe/expression.h b/src/quick-lint-js/fe/expression.h index 1e0b852b96..8fe82a5b60 100644 --- a/src/quick-lint-js/fe/expression.h +++ b/src/quick-lint-js/fe/expression.h @@ -162,7 +162,7 @@ class Expression_Arena { using Buffering_Visitor_Ptr = Buffering_Visitor *; template - using Vector = Bump_Vector; + using Vector = Bump_Vector; template static inline constexpr bool is_allocatable = @@ -172,7 +172,7 @@ class Expression_Arena { Expression *make_expression(Args &&... args); template - Array_Ptr make_array(Bump_Vector &&); + Array_Ptr make_array(Bump_Vector &&); template Array_Ptr make_array(T *begin, T *end); @@ -337,7 +337,7 @@ Expression *Expression_Arena::make_expression(Args &&... args) { template inline Expression_Arena::Array_Ptr Expression_Arena::make_array( - Bump_Vector &&elements) { + Bump_Vector &&elements) { QLJS_ASSERT(elements.get_allocator() == &this->allocator_); // NOTE(strager): Adopt the pointer instead of copying. Array_Ptr result(elements.data(), elements.size()); diff --git a/src/quick-lint-js/fe/lex.cpp b/src/quick-lint-js/fe/lex.cpp index 1973613490..661d08e575 100644 --- a/src/quick-lint-js/fe/lex.cpp +++ b/src/quick-lint-js/fe/lex.cpp @@ -1698,8 +1698,8 @@ Lexer::Parsed_Identifier Lexer::parse_identifier_slow( const Char8* private_identifier_begin = is_private_identifier ? &identifier_begin[-1] : identifier_begin; - Bump_Vector normalized( - "parse_identifier_slow normalized", &this->allocator_); + Bump_Vector normalized("parse_identifier_slow normalized", + &this->allocator_); normalized.append(private_identifier_begin, input); Escape_Sequence_List* escape_sequences = diff --git a/src/quick-lint-js/fe/parse-class.cpp b/src/quick-lint-js/fe/parse-class.cpp index 559746aec7..2a35eb9d04 100644 --- a/src/quick-lint-js/fe/parse-class.cpp +++ b/src/quick-lint-js/fe/parse-class.cpp @@ -294,9 +294,8 @@ void Parser::parse_and_visit_class_or_interface_member( this->type == Token_Type::kw_public; } }; - Bump_Vector modifiers = - Bump_Vector("class member modifiers", - &p->temporary_memory_); + Bump_Vector modifiers = + Bump_Vector("class member modifiers", &p->temporary_memory_); // Example: // @@ -323,8 +322,8 @@ void Parser::parse_and_visit_class_or_interface_member( Source_Code_Span name_span; }; - Bump_Vector - overload_signatures{"class overload signatures", &p->temporary_memory_}; + Bump_Vector overload_signatures{ + "class overload signatures", &p->temporary_memory_}; void reset_state_except_overload_signatures() { this->current_member_begin = p->peek().begin; @@ -897,8 +896,8 @@ void Parser::parse_and_visit_class_or_interface_member( // this->overload_signatures then parse the next member. is_possibly_typescript_overload = true; const Char8 *expected_body = p->lexer_.end_of_previous_token(); - Bump_Vector semicolons( - "semicolons", &p->temporary_memory_); + Bump_Vector semicolons("semicolons", + &p->temporary_memory_); while (p->peek().type == Token_Type::semicolon) { semicolons.push_back(p->peek().span()); p->skip(); diff --git a/src/quick-lint-js/fe/parse-expression.cpp b/src/quick-lint-js/fe/parse-expression.cpp index 22799f1280..821bdd1a6b 100644 --- a/src/quick-lint-js/fe/parse-expression.cpp +++ b/src/quick-lint-js/fe/parse-expression.cpp @@ -3763,8 +3763,8 @@ Expression* Parser::parse_jsx_element_or_fragment(Parse_Visitor_Base& v, mismatch = true; } if (mismatch) { - Bump_Vector opening_tag_name_pretty( - "opening_tag_name_pretty", &this->diagnostic_memory_); + Bump_Vector opening_tag_name_pretty("opening_tag_name_pretty", + &this->diagnostic_memory_); if (tag_namespace) { opening_tag_name_pretty += tag_namespace->span().string_view(); opening_tag_name_pretty += u8':'; diff --git a/src/quick-lint-js/fe/parse-statement.cpp b/src/quick-lint-js/fe/parse-statement.cpp index 713b0fef90..a41a1b2d6f 100644 --- a/src/quick-lint-js/fe/parse-statement.cpp +++ b/src/quick-lint-js/fe/parse-statement.cpp @@ -1232,7 +1232,7 @@ void Parser::parse_and_visit_export(Parse_Visitor_Base &v, // NOTE[ambiguous-ambient-statement-in-namespace]. Stacked_Buffering_Visitor exports_visitor = this->buffering_visitor_stack_.push(); - Bump_Vector exported_bad_tokens( + Bump_Vector exported_bad_tokens( "parse_and_visit_export exported_bad_tokens", &this->temporary_memory_); this->parse_and_visit_named_exports( exports_visitor.visitor(), @@ -1595,7 +1595,7 @@ void Parser::parse_and_visit_typescript_generic_parameters( const Char8 *less_end = this->peek().end; this->skip(); - Bump_Vector leading_commas( + Bump_Vector leading_commas( "parse_and_visit_typescript_generic_parameters leading_commas", &this->temporary_memory_); while (this->peek().type == Token_Type::comma) { @@ -1942,7 +1942,7 @@ void Parser::parse_and_visit_function_declaration( Identifier function_name = this->peek().identifier_name(); this->skip(); - Bump_Vector overload_names( + Bump_Vector overload_names( "parse_and_visit_function_declaration overload_names", &this->temporary_memory_); @@ -4626,7 +4626,7 @@ void Parser::parse_and_visit_named_exports_for_typescript_type_only_import( void Parser::parse_and_visit_named_exports( Parse_Visitor_Base &v, std::optional typescript_type_only_keyword, - Bump_Vector *out_exported_bad_tokens) { + Bump_Vector *out_exported_bad_tokens) { QLJS_ASSERT(this->peek().type == Token_Type::left_curly); this->skip(); diff --git a/src/quick-lint-js/fe/parse.cpp b/src/quick-lint-js/fe/parse.cpp index fb7417949b..d3e15b6eb1 100644 --- a/src/quick-lint-js/fe/parse.cpp +++ b/src/quick-lint-js/fe/parse.cpp @@ -192,8 +192,8 @@ void Parser::check_jsx_attribute(const Identifier& attribute_name) { bool name_has_upper = any_of(name, isupper); if (!name_has_upper && is_event_attribute) { - Bump_Vector fixed_name( - "check_jsx_attribute fixed_name", &this->diagnostic_memory_); + Bump_Vector fixed_name("check_jsx_attribute fixed_name", + &this->diagnostic_memory_); fixed_name += name; fixed_name[2] = toupper(fixed_name[2]); this->diag_reporter_->report(Diag_JSX_Event_Attribute_Should_Be_Camel_Case{ diff --git a/src/quick-lint-js/fe/parse.h b/src/quick-lint-js/fe/parse.h index 214d93dbbc..0e028d7bd8 100644 --- a/src/quick-lint-js/fe/parse.h +++ b/src/quick-lint-js/fe/parse.h @@ -566,7 +566,7 @@ class Parser { void parse_and_visit_named_exports( Parse_Visitor_Base &v, std::optional typescript_type_only_keyword, - Bump_Vector *out_exported_bad_tokens); + Bump_Vector *out_exported_bad_tokens); void parse_and_visit_variable_declaration_statement( Parse_Visitor_Base &v, diff --git a/src/quick-lint-js/fe/token.h b/src/quick-lint-js/fe/token.h index 7c1a61fe8a..6f61d76284 100644 --- a/src/quick-lint-js/fe/token.h +++ b/src/quick-lint-js/fe/token.h @@ -289,7 +289,7 @@ enum class Token_Type { const char* to_string(Token_Type); std::ostream& operator<<(std::ostream&, Token_Type); -using Escape_Sequence_List = Bump_Vector; +using Escape_Sequence_List = Bump_Vector; struct Token { Identifier identifier_name() const; diff --git a/src/quick-lint-js/i18n/po-parser.cpp b/src/quick-lint-js/i18n/po-parser.cpp index ab209a0dfe..c809b24bbc 100644 --- a/src/quick-lint-js/i18n/po-parser.cpp +++ b/src/quick-lint-js/i18n/po-parser.cpp @@ -131,8 +131,7 @@ class PO_Parser { this->fatal(); } this->input_ += 1; - Bump_Vector decoded("parse_string", - this->allocator_); + Bump_Vector decoded("parse_string", this->allocator_); for (;;) { switch (*this->input_) { case u8'"': { @@ -219,8 +218,7 @@ class PO_Parser { const CLI_Locator* locator_; Monotonic_Allocator* allocator_; - Bump_Vector entries_{"PO_Parser::entries", - this->allocator_}; + Bump_Vector entries_{"PO_Parser::entries", this->allocator_}; bool is_next_entry_fuzzy_ = false; }; diff --git a/src/quick-lint-js/i18n/translation-table-compiler.cpp b/src/quick-lint-js/i18n/translation-table-compiler.cpp index 4966f9cbce..e4a843267d 100644 --- a/src/quick-lint-js/i18n/translation-table-compiler.cpp +++ b/src/quick-lint-js/i18n/translation-table-compiler.cpp @@ -36,7 +36,7 @@ struct String_Table { } private: - Bump_Vector strings_; + Bump_Vector strings_; }; } @@ -78,7 +78,7 @@ Compiled_Translation_Table compile_translation_table( Span keys = untranslated_strings; { - Bump_Vector locale_names( + Bump_Vector locale_names( "compile_translation_table locale_names", allocator); for (const PO_File& file : files) { locale_names.push_back(file.locale); @@ -182,7 +182,7 @@ Compiled_Translation_Table compile_translation_table( Span get_all_untranslated(Span files, Monotonic_Allocator* allocator) { - Bump_Vector all_untranslated( + Bump_Vector all_untranslated( "get_all_untranslated all_untranslated", allocator); auto add_untranslated = [&](String8_View untranslated) -> void { bool is_duplicate = contains(all_untranslated, untranslated); diff --git a/src/quick-lint-js/i18n/translation.cpp b/src/quick-lint-js/i18n/translation.cpp index 8f984a64a9..673a494fb3 100644 --- a/src/quick-lint-js/i18n/translation.cpp +++ b/src/quick-lint-js/i18n/translation.cpp @@ -26,8 +26,7 @@ Translator qljs_messages; namespace { Span split_on(const char* s, char separator, Monotonic_Allocator* allocator) { - Bump_Vector locales("locales", - allocator); + Bump_Vector locales("locales", allocator); for (;;) { const char* sep = std::strchr(s, separator); if (sep) { @@ -65,8 +64,7 @@ Span get_user_locale_preferences( // TODO(strager): Determine the language using macOS' and Windows' native // APIs. See GNU gettext's _nl_language_preferences_default. - Bump_Vector locales("locales", - allocator); + Bump_Vector locales("locales", allocator); locales.push_back(locale); return locales.release_to_span(); } diff --git a/src/quick-lint-js/io/event-loop-poll.cpp b/src/quick-lint-js/io/event-loop-poll.cpp index 8910816313..6f1c7988b9 100644 --- a/src/quick-lint-js/io/event-loop-poll.cpp +++ b/src/quick-lint-js/io/event-loop-poll.cpp @@ -74,9 +74,9 @@ Event_Loop_Poll::~Event_Loop_Poll() { delete this->impl_; } void Event_Loop_Poll::run() { Monotonic_Allocator allocator("Event_Loop_Poll"); // events[i] corresponds to event_registered_events[i]. - Bump_Vector<::pollfd, Monotonic_Allocator> events("events", &allocator); - Bump_Vector - event_registered_events("event_registered_events", &allocator); + Bump_Vector<::pollfd> events("events", &allocator); + Bump_Vector event_registered_events( + "event_registered_events", &allocator); while (!this->is_stop_requested()) { events.clear(); diff --git a/src/quick-lint-js/lsp/lsp-workspace-configuration.h b/src/quick-lint-js/lsp/lsp-workspace-configuration.h index 023d9a9c96..e203717a11 100644 --- a/src/quick-lint-js/lsp/lsp-workspace-configuration.h +++ b/src/quick-lint-js/lsp/lsp-workspace-configuration.h @@ -61,7 +61,7 @@ class LSP_Workspace_Configuration { Item* find_item(String8_View name); bool set_item(Item&, ::simdjson::ondemand::value); - Bump_Vector items_; + Bump_Vector items_; }; } diff --git a/src/quick-lint-js/port/child-process.cpp b/src/quick-lint-js/port/child-process.cpp index dbb97d9218..5510387e18 100644 --- a/src/quick-lint-js/port/child-process.cpp +++ b/src/quick-lint-js/port/child-process.cpp @@ -86,8 +86,7 @@ Run_Program_Result run_program(Span command) { Run_Program_Result run_program(Span command, Run_Program_Options options) { Monotonic_Allocator allocator("run_program"); - Bump_Vector command_raw("command_raw", - &allocator); + Bump_Vector command_raw("command_raw", &allocator); for (const std::string& arg : command) { command_raw.push_back(arg.c_str()); } @@ -123,7 +122,7 @@ Run_Program_Result run_program(Span command, } Monotonic_Allocator allocator("run_program"); - Bump_Vector argv("argv", &allocator); + Bump_Vector argv("argv", &allocator); for (const char* arg : command) { argv.push_back(const_cast(arg)); } diff --git a/src/quick-lint-js/reflection/cxx-parser.cpp b/src/quick-lint-js/reflection/cxx-parser.cpp index da63ad5a14..b1ea8980cd 100644 --- a/src/quick-lint-js/reflection/cxx-parser.cpp +++ b/src/quick-lint-js/reflection/cxx-parser.cpp @@ -233,8 +233,8 @@ String8_View CXX_Lexer::lex_string_literal() { QLJS_ASSERT(*this->input_ == u8'"'); this->input_ += 1; - Bump_Vector decoded( - "CXX_Lexer::lex_string_literal", &this->decoded_string_allocator_); + Bump_Vector decoded("CXX_Lexer::lex_string_literal", + &this->decoded_string_allocator_); for (;;) { switch (*this->input_) { case u8'"': { diff --git a/src/quick-lint-js/reflection/cxx-parser.h b/src/quick-lint-js/reflection/cxx-parser.h index 6b92d99b2d..9ccd4005f0 100644 --- a/src/quick-lint-js/reflection/cxx-parser.h +++ b/src/quick-lint-js/reflection/cxx-parser.h @@ -198,10 +198,10 @@ class CXX_Diagnostic_Types_Parser : private CXX_Parser_Base { using Base::fatal_at; Monotonic_Allocator allocator_{"CXX_Diagnostic_Types_Parser"}; - Bump_Vector parsed_types{ - "parsed_types", &this->allocator_}; - Bump_Vector reserved_codes{ - "reserved_codes", &this->allocator_}; + Bump_Vector parsed_types{"parsed_types", + &this->allocator_}; + Bump_Vector reserved_codes{"reserved_codes", + &this->allocator_}; }; // Precondition: variables.size() <= 4 diff --git a/test/quick-lint-js/tjson.cpp b/test/quick-lint-js/tjson.cpp index 6dceefbc81..f2b078accb 100644 --- a/test/quick-lint-js/tjson.cpp +++ b/test/quick-lint-js/tjson.cpp @@ -98,8 +98,8 @@ TJSON_Value TJSON_Value::operator[](std::size_t index) const { std::optional> TJSON_Value::try_get_array() const { TJSON::Impl* tjson_impl = this->impl_->tjson_impl; - Bump_Vector items( - "TJSON_Value::try_get_array items", &tjson_impl->allocator); + Bump_Vector items("TJSON_Value::try_get_array items", + &tjson_impl->allocator); ::simdjson::dom::array array; if (this->impl_->value.get(array) != ::simdjson::SUCCESS) { return std::nullopt; diff --git a/test/test-vector.cpp b/test/test-vector.cpp index 1f928fb643..0d40c099d8 100644 --- a/test/test-vector.cpp +++ b/test/test-vector.cpp @@ -16,7 +16,7 @@ namespace quick_lint_js { namespace { TEST(Test_Bump_Vector, empty) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Bump_Vector v("test", &alloc); EXPECT_TRUE(v.empty()); EXPECT_EQ(v.size(), 0); EXPECT_EQ(v.capacity(), 0); @@ -24,7 +24,7 @@ TEST(Test_Bump_Vector, empty) { TEST(Test_Bump_Vector, append_into_reserved_memory) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Bump_Vector v("test", &alloc); v.reserve(2); EXPECT_EQ(v.capacity(), 2); EXPECT_EQ(v.size(), 0); @@ -43,7 +43,7 @@ TEST(Test_Bump_Vector, append_into_reserved_memory) { TEST(Test_Bump_Vector, reserve_0_does_nothing) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Bump_Vector v("test", &alloc); v.reserve(0); EXPECT_EQ(v.capacity(), 0); EXPECT_EQ(v.size(), 0); @@ -59,7 +59,7 @@ TEST(Test_Bump_Vector, reserve_0_does_nothing) { TEST(Test_Bump_Vector, append_into_new_memory) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Bump_Vector v("test", &alloc); EXPECT_EQ(v.capacity(), 0); EXPECT_EQ(v.size(), 0); @@ -76,7 +76,7 @@ TEST(Test_Bump_Vector, append_into_new_memory) { TEST(Test_Bump_Vector, growing_allocation_in_place) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Bump_Vector v("test", &alloc); v.reserve(2); v.emplace_back(100); @@ -92,7 +92,7 @@ TEST(Test_Bump_Vector, growing_allocation_in_place) { TEST(Test_Bump_Vector, growing_allocation_by_copy) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Bump_Vector v("test", &alloc); v.reserve(2); v.emplace_back(100); @@ -118,7 +118,7 @@ TEST(Test_Bump_Vector, growing_allocation_by_copy) { TEST(Test_Bump_Vector, resize_allows_same_size) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Bump_Vector v("test", &alloc); v.emplace_back(100); v.emplace_back(200); std::uintptr_t old_v_data_pointer = @@ -137,7 +137,7 @@ TEST(Test_Bump_Vector, resize_allows_same_size) { TEST(Test_Bump_Vector, resize_allows_shrinking) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Bump_Vector v("test", &alloc); v.emplace_back(100); v.emplace_back(200); v.emplace_back(300); @@ -158,7 +158,7 @@ TEST(Test_Bump_Vector, resize_allows_shrinking) { TEST(Test_Bump_Vector, resize_allows_growing_within_capacity) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Bump_Vector v("test", &alloc); v.emplace_back(100); v.emplace_back(200); std::uintptr_t old_v_data_pointer = @@ -179,7 +179,7 @@ TEST(Test_Bump_Vector, resize_allows_growing_within_capacity) { TEST(Test_Bump_Vector, resize_allows_growing_outside_capacity) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Bump_Vector v("test", &alloc); v.emplace_back(100); v.emplace_back(200); @@ -195,7 +195,7 @@ TEST(Test_Bump_Vector, resize_allows_growing_outside_capacity) { TEST(Test_Bump_Vector, pop_back_shrinks_vector) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Bump_Vector v("test", &alloc); v.push_back(100); v.push_back(200); v.push_back(300); @@ -207,7 +207,7 @@ TEST(Test_Bump_Vector, pop_back_shrinks_vector) { TEST(Test_Bump_Vector, pop_back_then_push_back_reuses_memory) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Bump_Vector v("test", &alloc); v.push_back(100); v.push_back(200); v.push_back(300); @@ -224,17 +224,17 @@ TEST(Test_Bump_Vector, pop_back_then_push_back_reuses_memory) { TEST(Test_Bump_Vector, move_constructing_clears_old_vector) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Bump_Vector v("test", &alloc); v.emplace_back(100); v.emplace_back(200); - Bump_Vector v2(std::move(v)); + Bump_Vector v2(std::move(v)); EXPECT_THAT(v, IsEmpty()); } TEST(Test_Bump_Vector, move_constructor_preserves_pointers) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Bump_Vector v("test", &alloc); v.emplace_back(100); v.emplace_back(200); @@ -243,7 +243,7 @@ TEST(Test_Bump_Vector, move_constructor_preserves_pointers) { Bump_Vector_Size old_v_capacity = v.capacity(); Bump_Vector_Size old_v_size = v.size(); - Bump_Vector v2(std::move(v)); + Bump_Vector v2(std::move(v)); EXPECT_EQ(reinterpret_cast(v2.data()), old_v_data_pointer); EXPECT_EQ(v2.capacity(), old_v_capacity); diff --git a/tools/compile-translations.cpp b/tools/compile-translations.cpp index e34ec6d8b9..54d654b3a6 100644 --- a/tools/compile-translations.cpp +++ b/tools/compile-translations.cpp @@ -39,7 +39,7 @@ struct String_Table { // Copies the string. explicit Entry(String8_View string, Monotonic_Allocator* allocator); - Bump_Vector origin_file_paths; + Bump_Vector origin_file_paths; String8_View string; }; @@ -125,7 +125,7 @@ int main(int argc, char** argv) { write_messages_po_template(string_table, output_messages_pot_path); Monotonic_Allocator allocator("main"); - Bump_Vector po_files("PO files", &allocator); + Bump_Vector po_files("PO files", &allocator); for (const char* po_file_path : po_file_paths) { po_files.push_back(PO_File{ .locale = po_path_to_locale_name(po_file_path), @@ -484,7 +484,7 @@ void write_translation_test_header( Output_Stream& out) { Monotonic_Allocator allocator("write_translation_test_header"); - Bump_Vector locale_names( + Bump_Vector locale_names( "compile_translation_table locale_names", &allocator); for (const PO_File& file : po_files) { locale_names.push_back(file.locale); diff --git a/tools/generate-trace-sources.cpp b/tools/generate-trace-sources.cpp index 3bdb51bb18..cce75c810f 100644 --- a/tools/generate-trace-sources.cpp +++ b/tools/generate-trace-sources.cpp @@ -141,8 +141,8 @@ class CXX_Trace_Types_Parser : public CXX_Parser_Base { this->skip(); this->expect_skip(CXX_Token_Type::less); this->expect_skip(u8"class"_sv); - Bump_Vector template_parameters( - "template_parameters", &this->memory_); + Bump_Vector template_parameters("template_parameters", + &this->memory_); template_parameters.emplace_back(this->expect_skip_identifier()); this->expect_skip(CXX_Token_Type::greater); s.template_parameters = template_parameters.release_to_span(); @@ -154,8 +154,7 @@ class CXX_Trace_Types_Parser : public CXX_Parser_Base { s.ctf_name = this->cxx_name_to_ctf_name(s.cxx_name); this->expect_skip(CXX_Token_Type::left_curly); - Bump_Vector members( - "members", &this->memory_); + Bump_Vector members("members", &this->memory_); while (!this->peek_is(CXX_Token_Type::right_curly)) { if (this->peek_is(u8"static"_sv)) { // static constexpr std::uint8_t id = 0x03; @@ -292,8 +291,7 @@ class CXX_Trace_Types_Parser : public CXX_Parser_Base { e.underlying_cxx_type = this->expect_skip_identifier(); this->expect_skip(CXX_Token_Type::left_curly); - Bump_Vector members( - "members", &this->memory_); + Bump_Vector members("members", &this->memory_); while (!this->peek_is(CXX_Token_Type::right_curly)) { // name = 42, Parsed_Enum_Member& member = members.emplace_back(); @@ -394,8 +392,7 @@ class CXX_Trace_Types_Parser : public CXX_Parser_Base { } Monotonic_Allocator memory_{"CXX_Trace_Types_Parser"}; - Bump_Vector declarations{ - "declarations", &this->memory_}; + Bump_Vector declarations{"declarations", &this->memory_}; }; void write_010_editor_template(CXX_Trace_Types_Parser& types, From 580f51de8f0c0da6394658a37ceb64ab4f607060 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 4 Nov 2023 20:56:26 -0400 Subject: [PATCH 090/117] refactor(container): document Linked_Bump_Allocator and Raw_Bump_Vector --- .../container/linked-bump-allocator.h | 31 +++++++++++++++++++ src/quick-lint-js/container/vector.h | 31 +++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/src/quick-lint-js/container/linked-bump-allocator.h b/src/quick-lint-js/container/linked-bump-allocator.h index 5995e737bb..4bb1a79296 100644 --- a/src/quick-lint-js/container/linked-bump-allocator.h +++ b/src/quick-lint-js/container/linked-bump-allocator.h @@ -39,6 +39,7 @@ class Linked_Bump_Allocator final : public Memory_Resource { ~Linked_Bump_Allocator() override; + // Deallocate previously-allocated memory. void release(); struct Rewind_State { @@ -67,6 +68,7 @@ class Linked_Bump_Allocator final : public Memory_Resource { Rewind_State rewind_; }; + // See rewind(). Rewind_State prepare_for_rewind() { return Rewind_State{ .chunk_ = this->chunk_, @@ -75,21 +77,31 @@ class Linked_Bump_Allocator final : public Memory_Resource { }; } + // Deallocate all allocations made since the creation of the Rewind_State + // (returned by this->prepare_for_rewind()). void rewind(Rewind_State&& r); + // Calls this->prepare_for_rewind() immediately then this->rewind() on + // destruction. [[nodiscard]] Rewind_Guard make_rewind_guard() { return Rewind_Guard(this); } + // Allocate space for an instance of T, then construct T. template T* new_object(Args&&... args) { return new (this->allocate_bytes(sizeof(T), alignof(T))) T(std::forward(args)...); } + // Allocate space for an instance of T, then construct T via copy or move + // construction. template T* new_object_copy(T&& value) { return this->new_object(std::forward(value)); } + // Allocate space for objects.size() instances of T, then construct result[i] + // via copy or move construction from objects[i] for i from 0 to + // objects.size()-1. template Span new_objects_copy(Span objects) { Span new_objects = this->allocate_uninitialized_span( @@ -99,6 +111,8 @@ class Linked_Bump_Allocator final : public Memory_Resource { return new_objects; } + // Allocate space for object.size() instances of T. Does not construct any + // T-s. template [[nodiscard]] Span allocate_uninitialized_span(std::size_t size) { std::size_t byte_size = size * sizeof(T); @@ -107,11 +121,15 @@ class Linked_Bump_Allocator final : public Memory_Resource { return Span(items, narrow_cast(size)); } + // Allocate space for object.size() instances of T, then default-construct + // object.size() instances. template [[nodiscard]] Span allocate_span(Span_Size size) { return this->allocate_span(narrow_cast(size)); } + // Allocate space for object.size() instances of T, then default-construct + // object.size() instances. template [[nodiscard]] Span allocate_span(std::size_t size) { Span items = this->allocate_uninitialized_span(size); @@ -123,6 +141,11 @@ class Linked_Bump_Allocator final : public Memory_Resource { return items; } + // Given previously-allocated space for old_size instances of T, allocate + // adjacent space for (new_size-old_size) instances of T after the old + // allocation and return true. + // + // If adjacent space is not available, do nothing and return false. template bool try_grow_array_in_place(T* array, std::size_t old_size, std::size_t new_size) { @@ -131,6 +154,7 @@ class Linked_Bump_Allocator final : public Memory_Resource { new_size * sizeof(T)); } + // For testing only. std::size_t remaining_bytes_in_current_chunk() const { return narrow_cast(this->chunk_end_ - this->next_allocation_); } @@ -149,6 +173,8 @@ class Linked_Bump_Allocator final : public Memory_Resource { friend class Linked_Bump_Allocator; }; + // In debug modes, cause all allocations to fail with a precondition failure + // until the Disable_Guard is destructed. [[nodiscard]] Disable_Guard disable() { return Disable_Guard(this); } protected: @@ -165,6 +191,11 @@ class Linked_Bump_Allocator final : public Memory_Resource { static inline constexpr std::size_t default_chunk_size = 4096 - sizeof(Chunk); + // Given previously-allocated space of old_byte_size bytes, allocate adjacent + // space for (new_byte_size-old_byte_size) bytes after the old allocation and + // return true. + // + // If adjacent space is not available, do nothing and return false. bool try_grow_array_in_place_impl(char* array, std::size_t old_byte_size, std::size_t new_byte_size); diff --git a/src/quick-lint-js/container/vector.h b/src/quick-lint-js/container/vector.h index 34506ddf1c..a2b1701b58 100644 --- a/src/quick-lint-js/container/vector.h +++ b/src/quick-lint-js/container/vector.h @@ -92,6 +92,10 @@ class Uninstrumented_Vector : private Vector { using Bump_Vector_Size = std::ptrdiff_t; +// Like std::pmr::vector. Some differences: +// +// * No exception safety. +// * Extended interface for convenience. template class Raw_Bump_Vector { public: @@ -108,12 +112,18 @@ class Raw_Bump_Vector { static_assert(is_winkable_v); + // Create an empty vector. explicit Raw_Bump_Vector(Linked_Bump_Allocator *allocator) : allocator_(allocator) {} Raw_Bump_Vector(const Raw_Bump_Vector &) = delete; Raw_Bump_Vector &operator=(const Raw_Bump_Vector &) = delete; + // Move items from another Raw_Bump_Vector by taking its allocation. + // + // This function does not move individual items. + // + // Postcondition: other.empty() Raw_Bump_Vector(Raw_Bump_Vector &&other) : data_(other.data_), data_end_(other.data_end_), @@ -124,8 +134,15 @@ class Raw_Bump_Vector { other.capacity_end_ = nullptr; } + // Destruct items in the container, as in this->clear(), then release the + // memory. + // + // If the allocator is a Linked_Bump_Allocator, then memory is only released + // if this Raw_Bump_Vector's capacity is the last thing allocated with that + // allocator. ~Raw_Bump_Vector() { this->clear(); } + // Return the pointer given in Raw_Bump_Vector's constructor. Linked_Bump_Allocator *get_allocator() const { return this->allocator_; } bool empty() const { return this->data_ == this->data_end_; } @@ -163,11 +180,15 @@ class Raw_Bump_Vector { return this->data_end_[-1]; } + // Precondition: index is in bounds. This means that '&(*this)[this->size()]' + // (indexing one past the end) is invalid. To get one past the end, call + // this->end() instead or write '&this->data()[this->size()]'. T &operator[](size_type index) { QLJS_ASSERT(index < this->size()); return this->data_[index]; } + // Precondition: (none) void reserve(size_type new_capacity) { QLJS_ASSERT(new_capacity >= 0); if (this->capacity() < new_capacity) { @@ -175,6 +196,7 @@ class Raw_Bump_Vector { } } + // Precondition: new_capacity > this->capacity() void reserve_grow(size_type new_capacity) { QLJS_ASSERT(new_capacity > this->capacity()); if (this->data_) { @@ -266,6 +288,10 @@ class Raw_Bump_Vector { return span; } + // Call the destructor of each item, then deallocate memory used for the + // items. + // + // Postcondition: this->empty() void clear() { if (this->data_) { std::destroy(this->data_, this->data_end_); @@ -278,6 +304,10 @@ class Raw_Bump_Vector { } } + // If new_size > this->size(): default-construct new items at the end. + // If new_size < this->size(): destruct items at the end. + // + // Postcondition: this->size() == new_size void resize(size_type new_size) { size_type old_size = this->size(); if (new_size == old_size) { @@ -327,6 +357,7 @@ class Raw_Bump_Vector { } private: + // Growth strategy. void reserve_grow_by_at_least(size_type minimum_new_entries) { size_type old_capacity = this->capacity(); constexpr size_type minimum_capacity = 4; From 8fe55673f2c145477bbc5e9cb07e7ec292146025 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sat, 4 Nov 2023 21:45:05 -0400 Subject: [PATCH 091/117] refactor(container): move helper methods up class hierarchy quick-lint-js-benchmark-parse with jQuery on my Linux 5950X with GCC: Benchmark Time CPU Time Old Time New CPU Old CPU New -------------------------------------------------------------------------------------------------------------------------- benchmark_parse_file_pvalue 0.0002 0.0002 U Test, Repetitions: 10 vs 10 benchmark_parse_file_mean -0.0059 -0.0059 1699545 1689510 1699517 1689477 benchmark_parse_file_median -0.0055 -0.0055 1698614 1689311 1698597 1689281 benchmark_parse_file_stddev -0.3142 -0.3126 2678 1837 2668 1834 benchmark_parse_file_cv -0.3101 -0.3085 0 0 0 0 --- .../container/linked-bump-allocator.h | 58 --------------- src/quick-lint-js/port/memory-resource.h | 70 ++++++++++++++++++- 2 files changed, 68 insertions(+), 60 deletions(-) diff --git a/src/quick-lint-js/container/linked-bump-allocator.h b/src/quick-lint-js/container/linked-bump-allocator.h index 4bb1a79296..54c66a0df1 100644 --- a/src/quick-lint-js/container/linked-bump-allocator.h +++ b/src/quick-lint-js/container/linked-bump-allocator.h @@ -8,9 +8,7 @@ #include #include #include -#include #include -#include #if defined(QLJS_DEBUG) && QLJS_DEBUG #define QLJS_DEBUG_BUMP_ALLOCATOR 1 @@ -85,62 +83,6 @@ class Linked_Bump_Allocator final : public Memory_Resource { // destruction. [[nodiscard]] Rewind_Guard make_rewind_guard() { return Rewind_Guard(this); } - // Allocate space for an instance of T, then construct T. - template - T* new_object(Args&&... args) { - return new (this->allocate_bytes(sizeof(T), alignof(T))) - T(std::forward(args)...); - } - - // Allocate space for an instance of T, then construct T via copy or move - // construction. - template - T* new_object_copy(T&& value) { - return this->new_object(std::forward(value)); - } - - // Allocate space for objects.size() instances of T, then construct result[i] - // via copy or move construction from objects[i] for i from 0 to - // objects.size()-1. - template - Span new_objects_copy(Span objects) { - Span new_objects = this->allocate_uninitialized_span( - narrow_cast(objects.size())); - std::uninitialized_copy(objects.begin(), objects.end(), - new_objects.begin()); - return new_objects; - } - - // Allocate space for object.size() instances of T. Does not construct any - // T-s. - template - [[nodiscard]] Span allocate_uninitialized_span(std::size_t size) { - std::size_t byte_size = size * sizeof(T); - T* items = - reinterpret_cast(this->allocate_bytes(byte_size, alignof(T))); - return Span(items, narrow_cast(size)); - } - - // Allocate space for object.size() instances of T, then default-construct - // object.size() instances. - template - [[nodiscard]] Span allocate_span(Span_Size size) { - return this->allocate_span(narrow_cast(size)); - } - - // Allocate space for object.size() instances of T, then default-construct - // object.size() instances. - template - [[nodiscard]] Span allocate_span(std::size_t size) { - Span items = this->allocate_uninitialized_span(size); - for (T& item : items) { - // FIXME(strager): I think we technically need to std::launder after - // placement new. - new (&item) T(); - } - return items; - } - // Given previously-allocated space for old_size instances of T, allocate // adjacent space for (new_size-old_size) instances of T after the old // allocation and return true. diff --git a/src/quick-lint-js/port/memory-resource.h b/src/quick-lint-js/port/memory-resource.h index 5d0e28cbdf..d9ef0e35a1 100644 --- a/src/quick-lint-js/port/memory-resource.h +++ b/src/quick-lint-js/port/memory-resource.h @@ -4,21 +4,87 @@ #pragma once #include +#include +#include +#include +#include +#include +#include namespace quick_lint_js { // Like std::pmr::memory_resource. +// +// Helper functions are forcefully inlined with QLJS_FORCE_INLINE to increase +// the chance that devirtualization occurs. class Memory_Resource { public: virtual ~Memory_Resource() = default; - void* allocate(std::size_t bytes, std::size_t alignment) { + QLJS_FORCE_INLINE void* allocate(std::size_t bytes, std::size_t alignment) { return this->do_allocate(bytes, alignment); } - void deallocate(void* p, std::size_t bytes, std::size_t alignment) { + QLJS_FORCE_INLINE void deallocate(void* p, std::size_t bytes, + std::size_t alignment) { return this->do_deallocate(p, bytes, alignment); } + // Allocate space for an instance of T, then construct T. + template + QLJS_FORCE_INLINE T* new_object(Args&&... args) { + return new (this->do_allocate(sizeof(T), alignof(T))) + T(std::forward(args)...); + } + + // Allocate space for an instance of T, then construct T via copy or move + // construction. + template + QLJS_FORCE_INLINE T* new_object_copy(T&& value) { + return this->new_object(std::forward(value)); + } + + // Allocate space for objects.size() instances of T, then construct result[i] + // via copy or move construction from objects[i] for i from 0 to + // objects.size()-1. + template + QLJS_FORCE_INLINE Span new_objects_copy(Span objects) { + Span new_objects = this->allocate_uninitialized_span( + narrow_cast(objects.size())); + std::uninitialized_copy(objects.begin(), objects.end(), + new_objects.begin()); + return new_objects; + } + + // Allocate space for object.size() instances of T. Does not construct any + // T-s. + template + QLJS_FORCE_INLINE [[nodiscard]] Span allocate_uninitialized_span( + std::size_t size) { + std::size_t byte_size = size * sizeof(T); + T* items = reinterpret_cast(this->do_allocate(byte_size, alignof(T))); + return Span(items, narrow_cast(size)); + } + + // Allocate space for object.size() instances of T, then default-construct + // object.size() instances. + template + QLJS_FORCE_INLINE [[nodiscard]] Span allocate_span(Span_Size size) { + return this->allocate_span(narrow_cast(size)); + } + + // Allocate space for object.size() instances of T, then default-construct + // object.size() instances. + template + QLJS_FORCE_INLINE [[nodiscard]] Span allocate_span(std::size_t size) { + Span items = this->allocate_uninitialized_span(size); + for (T& item : items) { + // FIXME(strager): I think we technically need to std::launder after + // placement new. + new (&item) T(); + } + return items; + } + protected: virtual void* do_allocate(std::size_t bytes, std::size_t alignment) = 0; virtual void do_deallocate(void* p, std::size_t bytes, From 1933fe4df74880a2808eaa2ab6f7f6221e43f97c Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sun, 5 Nov 2023 01:53:41 -0400 Subject: [PATCH 092/117] perf(container): optimize Bump_Vector Avoid inlining a somewhat-cold function into push_back, improving parse+lint perf slightly (GCC): Benchmark Time CPU Time Old Time New CPU Old CPU New ------------------------------------------------------------------------------------------------------------------------------ benchmark_parse_and_lint_pvalue 0.0890 0.0890 U Test, Repetitions: 10 vs 10 benchmark_parse_and_lint_mean -0.0372 -0.0372 2381522 2292841 2381434 2292757 benchmark_parse_and_lint_median -0.0104 -0.0104 2331848 2307682 2331767 2307573 benchmark_parse_and_lint_stddev -0.5834 -0.5835 115285 48026 115284 48020 benchmark_parse_and_lint_cv -0.5673 -0.5674 0 0 0 0 OVERALL_GEOMEAN -0.0364 -0.0364 0 0 0 0 --- src/quick-lint-js/container/vector.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/quick-lint-js/container/vector.h b/src/quick-lint-js/container/vector.h index a2b1701b58..062cd689fd 100644 --- a/src/quick-lint-js/container/vector.h +++ b/src/quick-lint-js/container/vector.h @@ -358,7 +358,8 @@ class Raw_Bump_Vector { private: // Growth strategy. - void reserve_grow_by_at_least(size_type minimum_new_entries) { + [[gnu::noinline]] void reserve_grow_by_at_least( + size_type minimum_new_entries) { size_type old_capacity = this->capacity(); constexpr size_type minimum_capacity = 4; size_type new_size = (std::max)( From f8fab2ac3f602904b02c0ee3a607780b8d1ce14a Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sun, 5 Nov 2023 01:54:35 -0400 Subject: [PATCH 093/117] refactor(container): push try_grow_array_in_place up class hierarchy Allow other Memory_Resource-s to implement in-place allocation growth. --- .../container/linked-bump-allocator.cpp | 7 ++--- .../container/linked-bump-allocator.h | 23 ++-------------- src/quick-lint-js/port/memory-resource.h | 27 +++++++++++++++++++ 3 files changed, 33 insertions(+), 24 deletions(-) diff --git a/src/quick-lint-js/container/linked-bump-allocator.cpp b/src/quick-lint-js/container/linked-bump-allocator.cpp index adeaea3d40..eb1589cb7c 100644 --- a/src/quick-lint-js/container/linked-bump-allocator.cpp +++ b/src/quick-lint-js/container/linked-bump-allocator.cpp @@ -97,12 +97,13 @@ void Linked_Bump_Allocator::do_deallocate(void* p, std::size_t bytes, this->deallocate_bytes(p, bytes); } -bool Linked_Bump_Allocator::try_grow_array_in_place_impl( - char* array, std::size_t old_byte_size, std::size_t new_byte_size) { +bool Linked_Bump_Allocator::do_try_grow_in_place(void* array, + std::size_t old_byte_size, + std::size_t new_byte_size) { this->assert_not_disabled(); QLJS_ASSERT(new_byte_size > old_byte_size); bool array_is_last_allocation = - array + old_byte_size == this->next_allocation_; + reinterpret_cast(array) + old_byte_size == this->next_allocation_; if (!array_is_last_allocation) { // We can't grow because something else was already allocated. return false; diff --git a/src/quick-lint-js/container/linked-bump-allocator.h b/src/quick-lint-js/container/linked-bump-allocator.h index 54c66a0df1..9988c0475e 100644 --- a/src/quick-lint-js/container/linked-bump-allocator.h +++ b/src/quick-lint-js/container/linked-bump-allocator.h @@ -83,19 +83,6 @@ class Linked_Bump_Allocator final : public Memory_Resource { // destruction. [[nodiscard]] Rewind_Guard make_rewind_guard() { return Rewind_Guard(this); } - // Given previously-allocated space for old_size instances of T, allocate - // adjacent space for (new_size-old_size) instances of T after the old - // allocation and return true. - // - // If adjacent space is not available, do nothing and return false. - template - bool try_grow_array_in_place(T* array, std::size_t old_size, - std::size_t new_size) { - return this->try_grow_array_in_place_impl(reinterpret_cast(array), - old_size * sizeof(T), - new_size * sizeof(T)); - } - // For testing only. std::size_t remaining_bytes_in_current_chunk() const { return narrow_cast(this->chunk_end_ - this->next_allocation_); @@ -123,6 +110,8 @@ class Linked_Bump_Allocator final : public Memory_Resource { void* do_allocate(std::size_t bytes, std::size_t align) override; void do_deallocate(void* p, std::size_t bytes, [[maybe_unused]] std::size_t align) override; + bool do_try_grow_in_place(void* p, std::size_t old_byte_size, + std::size_t new_byte_size) override; private: struct alignas(alignof(void*)) Chunk_Header { @@ -133,14 +122,6 @@ class Linked_Bump_Allocator final : public Memory_Resource { static inline constexpr std::size_t default_chunk_size = 4096 - sizeof(Chunk); - // Given previously-allocated space of old_byte_size bytes, allocate adjacent - // space for (new_byte_size-old_byte_size) bytes after the old allocation and - // return true. - // - // If adjacent space is not available, do nothing and return false. - bool try_grow_array_in_place_impl(char* array, std::size_t old_byte_size, - std::size_t new_byte_size); - [[nodiscard]] void* allocate_bytes(std::size_t size, std::size_t align); void deallocate_bytes([[maybe_unused]] void* p, diff --git a/src/quick-lint-js/port/memory-resource.h b/src/quick-lint-js/port/memory-resource.h index d9ef0e35a1..05c0b6f186 100644 --- a/src/quick-lint-js/port/memory-resource.h +++ b/src/quick-lint-js/port/memory-resource.h @@ -85,10 +85,37 @@ class Memory_Resource { return items; } + // Given previously-allocated space for old_size instances of T, allocate + // adjacent space for (new_size-old_size) instances of T after the old + // allocation and return true. + // + // If adjacent space is not available, do nothing and return false. + template + QLJS_FORCE_INLINE bool try_grow_array_in_place(T* array, std::size_t old_size, + std::size_t new_size) { + return this->try_grow_in_place(array, old_size * sizeof(T), + new_size * sizeof(T)); + } + + // Given previously-allocated space of old_byte_size bytes, allocate adjacent + // space for (new_byte_size-old_byte_size) bytes after the old allocation and + // return true. + // + // If adjacent space is not available, do nothing and return false. + QLJS_FORCE_INLINE bool try_grow_in_place(void* p, std::size_t old_byte_size, + std::size_t new_byte_size) { + return this->do_try_grow_in_place(p, old_byte_size, new_byte_size); + } + protected: virtual void* do_allocate(std::size_t bytes, std::size_t alignment) = 0; virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) = 0; + virtual bool do_try_grow_in_place( + [[maybe_unused]] void* p, [[maybe_unused]] std::size_t old_byte_size, + [[maybe_unused]] std::size_t new_byte_size) { + return false; + } }; // Like std::pmr::new_delete_resource. From 0f73dff17d8c13efd4679c349d4c26782a59ed98 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sun, 5 Nov 2023 02:11:01 -0500 Subject: [PATCH 094/117] refactor(cli): work around GCC false positive warning GCC complains that arg_var might not be initialized: vector.h:238:23: error: '*((void*)& next_vim_file_bufnr +8)' may be used uninitialized in this function [-Werror=maybe-uninitialized] 238 | this->data_end_ = new (this->data_end_) T(std::forward(args)...); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ options.cpp:36:5: note: '*((void*)& next_vim_file_bufnr +8)' was declared here 36 | } next_vim_file_bufnr; | ^~~~~~~~~~~~~~~~~~~ This is a false positive in GCC. Whenever arg_var is pushed onto a Vector, we check if number is non-null. Whenever number is non-null, arg_var is initialized. Work around the false positive by refactoring the code such that arg_var and number are initialized together. --- src/quick-lint-js/cli/options.cpp | 39 ++++++++++++++++++------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/quick-lint-js/cli/options.cpp b/src/quick-lint-js/cli/options.cpp index 943cdeffbc..d5235f1537 100644 --- a/src/quick-lint-js/cli/options.cpp +++ b/src/quick-lint-js/cli/options.cpp @@ -30,10 +30,11 @@ Options parse_options(int argc, char** argv, Monotonic_Allocator* allocator) { Monotonic_Allocator temporary_allocator("parse_options"); - struct { - std::optional number; + struct Next_Vim_File_Bufnr { + int number; const char* arg_var; - } next_vim_file_bufnr; + }; + std::optional next_vim_file_bufnr; Bump_Vector files_to_lint("files_to_lint", allocator); Bump_Vector error_unrecognized_options( @@ -53,12 +54,16 @@ Options parse_options(int argc, char** argv, Monotonic_Allocator* allocator) { if (is_stdin && has_stdin) { o.has_multiple_stdin = true; } else { - File_To_Lint file{.path = path, - .config_file = active_config_file, - .path_for_config_search = next_path_for_config_search, - .language = language, - .is_stdin = is_stdin, - .vim_bufnr = next_vim_file_bufnr.number}; + File_To_Lint file{ + .path = path, + .config_file = active_config_file, + .path_for_config_search = next_path_for_config_search, + .language = language, + .is_stdin = is_stdin, + .vim_bufnr = next_vim_file_bufnr.has_value() + ? std::optional(next_vim_file_bufnr->number) + : std::nullopt, + }; files_to_lint.emplace_back(file); } if (is_stdin) { @@ -67,7 +72,7 @@ Options parse_options(int argc, char** argv, Monotonic_Allocator* allocator) { unused_language_option = nullptr; next_path_for_config_search = nullptr; - next_vim_file_bufnr.number = std::nullopt; + next_vim_file_bufnr = std::nullopt; }; auto add_stdin_file = [&]() { add_file("", /*is_stdin=*/true); }; @@ -160,12 +165,14 @@ Options parse_options(int argc, char** argv, Monotonic_Allocator* allocator) { error_unrecognized_options.emplace_back(arg_value); continue; } - if (next_vim_file_bufnr.number != std::nullopt) { + if (next_vim_file_bufnr.has_value()) { warning_vim_bufnr_without_file.emplace_back( - next_vim_file_bufnr.arg_var); + next_vim_file_bufnr->arg_var); } - next_vim_file_bufnr.number = bufnr; - next_vim_file_bufnr.arg_var = arg_value; + next_vim_file_bufnr = Next_Vim_File_Bufnr{ + .number = bufnr, + .arg_var = arg_value, + }; } QLJS_OPTION(const char* arg_value, "--exit-fail-on"sv) { @@ -189,8 +196,8 @@ Options parse_options(int argc, char** argv, Monotonic_Allocator* allocator) { if (unused_language_option) { warning_language_without_file.emplace_back(unused_language_option); } - if (next_vim_file_bufnr.number != std::nullopt) { - warning_vim_bufnr_without_file.emplace_back(next_vim_file_bufnr.arg_var); + if (next_vim_file_bufnr.has_value()) { + warning_vim_bufnr_without_file.emplace_back(next_vim_file_bufnr->arg_var); } if (o.path_for_stdin != nullptr) { for (File_To_Lint& file : files_to_lint) { From 2314119978e7c9311b6939173c05d9c422a22221 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sun, 5 Nov 2023 02:11:35 -0500 Subject: [PATCH 095/117] refactor(container): allow any allocator for Bump_Vector Raw_Bump_Vector is restricted to Linked_Bump_Allocator, but this restriction is not necessary. Refactor Raw_Bump_Vector to accept any Memory_Resource, including New_Delete_Resource_Impl. This will allow us to use Raw_Bump_Vector in more places. --- src/quick-lint-js/container/vector.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/quick-lint-js/container/vector.h b/src/quick-lint-js/container/vector.h index 062cd689fd..d73e2d07e6 100644 --- a/src/quick-lint-js/container/vector.h +++ b/src/quick-lint-js/container/vector.h @@ -100,7 +100,7 @@ template class Raw_Bump_Vector { public: using value_type = T; - using allocator_type = Linked_Bump_Allocator *; + using allocator_type = Memory_Resource *; using size_type = Bump_Vector_Size; using difference_type = Bump_Vector_Size; using reference = T &; @@ -110,10 +110,8 @@ class Raw_Bump_Vector { using iterator = T *; using const_iterator = const T *; - static_assert(is_winkable_v); - // Create an empty vector. - explicit Raw_Bump_Vector(Linked_Bump_Allocator *allocator) + explicit Raw_Bump_Vector(Memory_Resource *allocator) : allocator_(allocator) {} Raw_Bump_Vector(const Raw_Bump_Vector &) = delete; @@ -143,7 +141,7 @@ class Raw_Bump_Vector { ~Raw_Bump_Vector() { this->clear(); } // Return the pointer given in Raw_Bump_Vector's constructor. - Linked_Bump_Allocator *get_allocator() const { return this->allocator_; } + Memory_Resource *get_allocator() const { return this->allocator_; } bool empty() const { return this->data_ == this->data_end_; } size_type size() const { @@ -372,7 +370,7 @@ class Raw_Bump_Vector { T *data_end_ = nullptr; T *capacity_end_ = nullptr; - Linked_Bump_Allocator *allocator_; + Memory_Resource *allocator_; }; #if QLJS_FEATURE_VECTOR_PROFILING From 011df71f8ebf8a54a5402f8f431a7a3c7933d4d0 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sun, 5 Nov 2023 02:11:35 -0500 Subject: [PATCH 096/117] refactor(container): rename Bump_Vector -> Vector Bump_Vector works with non-bump allocators. Rename it to make this more clear. --- src/quick-lint-js/c-api-diag-reporter.h | 8 +-- src/quick-lint-js/cli/options.cpp | 10 +-- .../container/vector-profiler.cpp | 10 +-- src/quick-lint-js/container/vector.h | 35 +++++---- src/quick-lint-js/debug/find-debug-server.cpp | 24 +++---- src/quick-lint-js/diag/diag-code-list.cpp | 24 +++---- src/quick-lint-js/diag/diag-code-list.h | 8 +-- src/quick-lint-js/fe/expression.h | 6 +- src/quick-lint-js/fe/lex.cpp | 7 +- src/quick-lint-js/fe/parse-class.cpp | 10 +-- src/quick-lint-js/fe/parse-expression.cpp | 6 +- src/quick-lint-js/fe/parse-statement.cpp | 12 ++-- src/quick-lint-js/fe/parse.cpp | 4 +- src/quick-lint-js/fe/parse.h | 2 +- src/quick-lint-js/fe/token.h | 2 +- src/quick-lint-js/i18n/po-parser.cpp | 4 +- .../i18n/translation-table-compiler.cpp | 10 +-- src/quick-lint-js/i18n/translation.cpp | 4 +- src/quick-lint-js/io/event-loop-poll.cpp | 6 +- .../lsp/lsp-workspace-configuration.h | 2 +- src/quick-lint-js/port/child-process.cpp | 4 +- src/quick-lint-js/reflection/cxx-parser.cpp | 4 +- src/quick-lint-js/reflection/cxx-parser.h | 7 +- test/quick-lint-js/tjson.cpp | 4 +- test/test-vector.cpp | 72 +++++++++---------- tools/compile-translations.cpp | 8 +-- tools/generate-trace-sources.cpp | 10 +-- 27 files changed, 150 insertions(+), 153 deletions(-) diff --git a/src/quick-lint-js/c-api-diag-reporter.h b/src/quick-lint-js/c-api-diag-reporter.h index 4338b64b99..c97e535102 100644 --- a/src/quick-lint-js/c-api-diag-reporter.h +++ b/src/quick-lint-js/c-api-diag-reporter.h @@ -42,8 +42,8 @@ class C_API_Diag_Reporter final : public Diag_Reporter { Translator translator_; Monotonic_Allocator allocator_{"C_API_Diag_Reporter::allocator_"}; - Bump_Vector diagnostics_{"C_API_Diag_Reporter::diagnostics_", - &this->allocator_}; + Vector diagnostics_{"C_API_Diag_Reporter::diagnostics_", + &this->allocator_}; const Char8 *input_; std::optional locator_; Monotonic_Allocator string_allocator_{ @@ -68,8 +68,8 @@ class C_API_Diag_Formatter private: C_API_Diag_Reporter *reporter_; - Bump_Vector current_message_{"C_API_Diag_Reporter::current_message_", - &this->reporter_->string_allocator_}; + Vector current_message_{"C_API_Diag_Reporter::current_message_", + &this->reporter_->string_allocator_}; }; QLJS_WARNING_PUSH diff --git a/src/quick-lint-js/cli/options.cpp b/src/quick-lint-js/cli/options.cpp index d5235f1537..eedb366649 100644 --- a/src/quick-lint-js/cli/options.cpp +++ b/src/quick-lint-js/cli/options.cpp @@ -36,12 +36,12 @@ Options parse_options(int argc, char** argv, Monotonic_Allocator* allocator) { }; std::optional next_vim_file_bufnr; - Bump_Vector files_to_lint("files_to_lint", allocator); - Bump_Vector error_unrecognized_options( - "error_unrecognized_options", allocator); - Bump_Vector warning_vim_bufnr_without_file( + Vector files_to_lint("files_to_lint", allocator); + Vector error_unrecognized_options("error_unrecognized_options", + allocator); + Vector warning_vim_bufnr_without_file( "warning_vim_bufnr_without_file", allocator); - Bump_Vector warning_language_without_file( + Vector warning_language_without_file( "warning_language_without_file", allocator); const char* next_path_for_config_search = nullptr; diff --git a/src/quick-lint-js/container/vector-profiler.cpp b/src/quick-lint-js/container/vector-profiler.cpp index 1a75c1a9a7..fcd319a586 100644 --- a/src/quick-lint-js/container/vector-profiler.cpp +++ b/src/quick-lint-js/container/vector-profiler.cpp @@ -144,15 +144,15 @@ Vector_Max_Size_Histogram_By_Owner::histogram( } } - // NOTE(strager): We use Raw_Bump_Vector to prevent vector profiling code from + // NOTE(strager): We use Raw_Vector to prevent vector profiling code from // emitting events itself. - Raw_Bump_Vector + Raw_Vector out_entries_by_owner(memory); out_entries_by_owner.reserve( - narrow_cast(stable_histogram.size())); + narrow_cast(stable_histogram.size())); for (auto &[owner, counts] : stable_histogram) { - Raw_Bump_Vector out_entries(memory); - out_entries.reserve(narrow_cast(counts.size())); + Raw_Vector out_entries(memory); + out_entries.reserve(narrow_cast(counts.size())); for (auto &[size, count] : counts) { out_entries.push_back(Trace_Vector_Max_Size_Histogram_Entry{ .max_size = narrow_cast(size), diff --git a/src/quick-lint-js/container/vector.h b/src/quick-lint-js/container/vector.h index d73e2d07e6..111b30321f 100644 --- a/src/quick-lint-js/container/vector.h +++ b/src/quick-lint-js/container/vector.h @@ -90,19 +90,19 @@ class Uninstrumented_Vector : private Vector { using Vector::to_string_view; }; -using Bump_Vector_Size = std::ptrdiff_t; +using Vector_Size = std::ptrdiff_t; // Like std::pmr::vector. Some differences: // // * No exception safety. // * Extended interface for convenience. template -class Raw_Bump_Vector { +class Raw_Vector { public: using value_type = T; using allocator_type = Memory_Resource *; - using size_type = Bump_Vector_Size; - using difference_type = Bump_Vector_Size; + using size_type = Vector_Size; + using difference_type = Vector_Size; using reference = T &; using const_reference = const T &; using pointer = T *; @@ -111,18 +111,17 @@ class Raw_Bump_Vector { using const_iterator = const T *; // Create an empty vector. - explicit Raw_Bump_Vector(Memory_Resource *allocator) - : allocator_(allocator) {} + explicit Raw_Vector(Memory_Resource *allocator) : allocator_(allocator) {} - Raw_Bump_Vector(const Raw_Bump_Vector &) = delete; - Raw_Bump_Vector &operator=(const Raw_Bump_Vector &) = delete; + Raw_Vector(const Raw_Vector &) = delete; + Raw_Vector &operator=(const Raw_Vector &) = delete; - // Move items from another Raw_Bump_Vector by taking its allocation. + // Move items from another Raw_Vector by taking its allocation. // // This function does not move individual items. // // Postcondition: other.empty() - Raw_Bump_Vector(Raw_Bump_Vector &&other) + Raw_Vector(Raw_Vector &&other) : data_(other.data_), data_end_(other.data_end_), capacity_end_(other.capacity_end_), @@ -136,11 +135,11 @@ class Raw_Bump_Vector { // memory. // // If the allocator is a Linked_Bump_Allocator, then memory is only released - // if this Raw_Bump_Vector's capacity is the last thing allocated with that + // if this Raw_Vector's capacity is the last thing allocated with that // allocator. - ~Raw_Bump_Vector() { this->clear(); } + ~Raw_Vector() { this->clear(); } - // Return the pointer given in Raw_Bump_Vector's constructor. + // Return the pointer given in Raw_Vector's constructor. Memory_Resource *get_allocator() const { return this->allocator_; } bool empty() const { return this->data_ == this->data_end_; } @@ -255,13 +254,13 @@ class Raw_Bump_Vector { } // Similar to std::basic_string::operator+=. - Raw_Bump_Vector &operator+=(std::basic_string_view values) { + Raw_Vector &operator+=(std::basic_string_view values) { this->append(values.data(), values.data() + values.size()); return *this; } // Similar to std::basic_string::operator+=. - Raw_Bump_Vector &operator+=(T value) { + Raw_Vector &operator+=(T value) { this->emplace_back(value); return *this; } @@ -296,7 +295,7 @@ class Raw_Bump_Vector { this->allocator_->deallocate( this->data_, narrow_cast(this->size() * - static_cast(sizeof(T))), + static_cast(sizeof(T))), alignof(T)); this->release(); } @@ -375,10 +374,10 @@ class Raw_Bump_Vector { #if QLJS_FEATURE_VECTOR_PROFILING template -using Bump_Vector = Instrumented_Vector>; +using Vector = Instrumented_Vector>; #else template -using Bump_Vector = Uninstrumented_Vector>; +using Vector = Uninstrumented_Vector>; #endif } diff --git a/src/quick-lint-js/debug/find-debug-server.cpp b/src/quick-lint-js/debug/find-debug-server.cpp index 6d27eff43b..3fc7d97903 100644 --- a/src/quick-lint-js/debug/find-debug-server.cpp +++ b/src/quick-lint-js/debug/find-debug-server.cpp @@ -258,7 +258,7 @@ void enumerate_all_process_thread_names(Callback&& callback) { #if defined(__linux__) Span find_debug_servers(Monotonic_Allocator* allocator) { - Bump_Vector debug_servers("debug_servers", allocator); + Vector debug_servers("debug_servers", allocator); enumerate_all_process_thread_names([&](std::string_view process_id_string, std::string_view thread_name) { @@ -301,7 +301,7 @@ void enumerate_all_process_threads(Monotonic_Allocator& allocator, QLJS_ASSERT( narrow_cast(process_id_buffer_size) % sizeof(::pid_t) == 0); - Bump_Vector<::pid_t> process_ids("process_ids", &allocator); + Vector<::pid_t> process_ids("process_ids", &allocator); // NOTE(strager): It's okay if our buffer is to small. We miss out on some // processes, but they were just created anyway. Harmless race condition. process_ids.resize(narrow_cast(process_id_buffer_size) / @@ -309,7 +309,7 @@ void enumerate_all_process_threads(Monotonic_Allocator& allocator, process_id_buffer_size = ::proc_listpids( PROC_ALL_PIDS, 0, process_ids.data(), narrow_cast(process_ids.size() * - narrow_cast(sizeof(::pid_t)))); + narrow_cast(sizeof(::pid_t)))); if (process_id_buffer_size == -1) { QLJS_DEBUG_LOG("%s: ignoring failure to get process IDs: %s\n", __func__, std::strerror(errno)); @@ -318,7 +318,7 @@ void enumerate_all_process_threads(Monotonic_Allocator& allocator, process_ids.resize(narrow_cast(process_id_buffer_size) / sizeof(int)); - Bump_Vector thread_ids("thread_ids", &allocator); + Vector thread_ids("thread_ids", &allocator); constexpr std::size_t initial_thread_ids_buffer_count = 128; // Arbitrary. for (::pid_t process_id : process_ids) { thread_ids.resize(initial_thread_ids_buffer_count); @@ -327,7 +327,7 @@ void enumerate_all_process_threads(Monotonic_Allocator& allocator, process_id, PROC_PIDLISTTHREADIDS, /*arg=*/0, thread_ids.data(), narrow_cast(thread_ids.size() * - narrow_cast(sizeof(std::uint64_t)))); + narrow_cast(sizeof(std::uint64_t)))); if (thread_ids_buffer_size == -1) { QLJS_DEBUG_LOG( "%s: ignoring failure to get thread IDs for process %d: %s\n", @@ -337,10 +337,10 @@ void enumerate_all_process_threads(Monotonic_Allocator& allocator, QLJS_ASSERT(narrow_cast(thread_ids_buffer_size) % sizeof(std::uint64_t) == 0); - Bump_Vector_Size thread_count = - narrow_cast(thread_ids_buffer_size) / - narrow_cast(sizeof(std::uint64_t)); - if (narrow_cast(thread_count) == thread_ids.size()) { + Vector_Size thread_count = + narrow_cast(thread_ids_buffer_size) / + narrow_cast(sizeof(std::uint64_t)); + if (narrow_cast(thread_count) == thread_ids.size()) { // We can't tell if we read exactly all the threads or if there are more // threads. Assume there are more threads. thread_ids.resize(thread_ids.size() * 2); @@ -359,7 +359,7 @@ void enumerate_all_process_threads(Monotonic_Allocator& allocator, Span find_debug_servers(Monotonic_Allocator* allocator) { static constexpr char func[] = "find_debug_servers"; - Bump_Vector debug_servers("debug_servers", allocator); + Vector debug_servers("debug_servers", allocator); enumerate_all_process_threads( *allocator, [&](::pid_t process_id, std::uint64_t thread_id) -> void { ::proc_threadinfo thread_info; @@ -415,7 +415,7 @@ Span find_debug_servers(Monotonic_Allocator* allocator) { size_t own_jid_size; ::kinfo_proc* p; ::kvm_t* kd; - Bump_Vector debug_servers("debug_servers", allocator); + Vector debug_servers("debug_servers", allocator); // Query our own jail id own_jid_size = sizeof own_jid; @@ -514,7 +514,7 @@ void enumerate_all_process_threads(Callback&& callback) { Span find_debug_servers(Monotonic_Allocator* allocator) { static constexpr char func[] = "find_debug_servers"; - Bump_Vector debug_servers("debug_servers", allocator); + Vector debug_servers("debug_servers", allocator); enumerate_all_process_threads([&](::DWORD process_id, ::DWORD thread_id) -> void { Windows_Handle_File thread_handle( diff --git a/src/quick-lint-js/diag/diag-code-list.cpp b/src/quick-lint-js/diag/diag-code-list.cpp index 7f44f3499d..30080ff2b1 100644 --- a/src/quick-lint-js/diag/diag-code-list.cpp +++ b/src/quick-lint-js/diag/diag-code-list.cpp @@ -30,13 +30,13 @@ Parsed_Diag_Code_List parse_diag_code_list(const char* const raw_diag_code_list, return '0' <= c && c <= '9'; }; - Bump_Vector included_codes("included_codes", allocator); - Bump_Vector excluded_codes("excluded_codes", allocator); - Bump_Vector included_categories("included_categories", - allocator); - Bump_Vector excluded_categories("excluded_categories", - allocator); - Bump_Vector unexpected("unexpected", allocator); + Vector included_codes("included_codes", allocator); + Vector excluded_codes("excluded_codes", allocator); + Vector included_categories("included_categories", + allocator); + Vector excluded_categories("excluded_categories", + allocator); + Vector unexpected("unexpected", allocator); bool override_defaults = false; std::size_t i = 0; @@ -140,10 +140,10 @@ void Compiled_Diag_Code_List::add(const Parsed_Diag_Code_List& diag_code_list) { Span Compiled_Diag_Code_List::parse_errors( std::string_view cli_option_name, Monotonic_Allocator* allocator) const { - Bump_Vector errors("errors", allocator); + Vector errors("errors", allocator); if (this->has_missing_predicate_error_) { // TODO(#1102): Make this code pretty. - Bump_Vector error("error", allocator); + Vector error("error", allocator); error += cli_option_name; error += " must be given at least one category or code"sv; errors.emplace_back(error.release_to_string_view()); @@ -153,11 +153,11 @@ Span Compiled_Diag_Code_List::parse_errors( Span Compiled_Diag_Code_List::parse_warnings( Monotonic_Allocator* allocator) const { - Bump_Vector warnings("warnings", allocator); + Vector warnings("warnings", allocator); auto check_category = [&](std::string_view category) { if (category != "all") { // TODO(#1102): Make this code pretty. - Bump_Vector warning("warning", allocator); + Vector warning("warning", allocator); warning += "unknown error category: "sv; warning += category; warnings.emplace_back(warning.release_to_string_view()); @@ -175,7 +175,7 @@ Span Compiled_Diag_Code_List::parse_warnings( for (std::string_view code : this->unknown_codes_) { // TODO(#1102): Make this code pretty. - Bump_Vector warning("warning", allocator); + Vector warning("warning", allocator); warning += "unknown error code: "sv; warning += code; warnings.emplace_back(warning.release_to_string_view()); diff --git a/src/quick-lint-js/diag/diag-code-list.h b/src/quick-lint-js/diag/diag-code-list.h index 0f24005454..cf14a3417c 100644 --- a/src/quick-lint-js/diag/diag-code-list.h +++ b/src/quick-lint-js/diag/diag-code-list.h @@ -62,12 +62,12 @@ class Compiled_Diag_Code_List { // movable. std::unique_ptr allocator_; - Bump_Vector parsed_diag_code_lists_{"parsed_diag_code_lists_", - this->allocator_.get()}; + Vector parsed_diag_code_lists_{"parsed_diag_code_lists_", + this->allocator_.get()}; // Collected errors and warnings: - Bump_Vector unknown_codes_{"unknown_codes_", - this->allocator_.get()}; + Vector unknown_codes_{"unknown_codes_", + this->allocator_.get()}; bool has_missing_predicate_error_ = false; }; } diff --git a/src/quick-lint-js/fe/expression.h b/src/quick-lint-js/fe/expression.h index 8fe82a5b60..cefb018e09 100644 --- a/src/quick-lint-js/fe/expression.h +++ b/src/quick-lint-js/fe/expression.h @@ -162,7 +162,7 @@ class Expression_Arena { using Buffering_Visitor_Ptr = Buffering_Visitor *; template - using Vector = Bump_Vector; + using Vector = Vector; template static inline constexpr bool is_allocatable = @@ -172,7 +172,7 @@ class Expression_Arena { Expression *make_expression(Args &&... args); template - Array_Ptr make_array(Bump_Vector &&); + Array_Ptr make_array(Vector &&); template Array_Ptr make_array(T *begin, T *end); @@ -337,7 +337,7 @@ Expression *Expression_Arena::make_expression(Args &&... args) { template inline Expression_Arena::Array_Ptr Expression_Arena::make_array( - Bump_Vector &&elements) { + Vector &&elements) { QLJS_ASSERT(elements.get_allocator() == &this->allocator_); // NOTE(strager): Adopt the pointer instead of copying. Array_Ptr result(elements.data(), elements.size()); diff --git a/src/quick-lint-js/fe/lex.cpp b/src/quick-lint-js/fe/lex.cpp index 661d08e575..7828695c0e 100644 --- a/src/quick-lint-js/fe/lex.cpp +++ b/src/quick-lint-js/fe/lex.cpp @@ -1698,8 +1698,8 @@ Lexer::Parsed_Identifier Lexer::parse_identifier_slow( const Char8* private_identifier_begin = is_private_identifier ? &identifier_begin[-1] : identifier_begin; - Bump_Vector normalized("parse_identifier_slow normalized", - &this->allocator_); + Vector normalized("parse_identifier_slow normalized", + &this->allocator_); normalized.append(private_identifier_begin, input); Escape_Sequence_List* escape_sequences = @@ -1735,8 +1735,7 @@ Lexer::Parsed_Identifier Lexer::parse_identifier_slow( normalized.append(4, u8'\0'); const Char8* end = encode_utf_8(code_point, &normalized.data()[normalized.size() - 4]); - normalized.resize( - narrow_cast(end - normalized.data())); + normalized.resize(narrow_cast(end - normalized.data())); escape_sequences->emplace_back(escape_begin, escape.end); } } else { diff --git a/src/quick-lint-js/fe/parse-class.cpp b/src/quick-lint-js/fe/parse-class.cpp index 2a35eb9d04..d0b45c6902 100644 --- a/src/quick-lint-js/fe/parse-class.cpp +++ b/src/quick-lint-js/fe/parse-class.cpp @@ -294,8 +294,8 @@ void Parser::parse_and_visit_class_or_interface_member( this->type == Token_Type::kw_public; } }; - Bump_Vector modifiers = - Bump_Vector("class member modifiers", &p->temporary_memory_); + Vector modifiers = + Vector("class member modifiers", &p->temporary_memory_); // Example: // @@ -322,7 +322,7 @@ void Parser::parse_and_visit_class_or_interface_member( Source_Code_Span name_span; }; - Bump_Vector overload_signatures{ + Vector overload_signatures{ "class overload signatures", &p->temporary_memory_}; void reset_state_except_overload_signatures() { @@ -896,8 +896,8 @@ void Parser::parse_and_visit_class_or_interface_member( // this->overload_signatures then parse the next member. is_possibly_typescript_overload = true; const Char8 *expected_body = p->lexer_.end_of_previous_token(); - Bump_Vector semicolons("semicolons", - &p->temporary_memory_); + Vector semicolons("semicolons", + &p->temporary_memory_); while (p->peek().type == Token_Type::semicolon) { semicolons.push_back(p->peek().span()); p->skip(); diff --git a/src/quick-lint-js/fe/parse-expression.cpp b/src/quick-lint-js/fe/parse-expression.cpp index 821bdd1a6b..e35ebb5f2c 100644 --- a/src/quick-lint-js/fe/parse-expression.cpp +++ b/src/quick-lint-js/fe/parse-expression.cpp @@ -933,7 +933,7 @@ Expression* Parser::parse_async_expression_only( this->expressions_.allocator()); call_children.emplace_back(this->make_expression( async_or_await_token.identifier_name(), async_or_await_token.type)); - for (Bump_Vector_Size i = 0; i < parameters.size(); ++i) { + for (Vector_Size i = 0; i < parameters.size(); ++i) { if (parameters.data()[i]->kind() != Expression_Kind::Invalid) { call_children.emplace_back(parameters.data()[i]); } @@ -3763,8 +3763,8 @@ Expression* Parser::parse_jsx_element_or_fragment(Parse_Visitor_Base& v, mismatch = true; } if (mismatch) { - Bump_Vector opening_tag_name_pretty("opening_tag_name_pretty", - &this->diagnostic_memory_); + Vector opening_tag_name_pretty("opening_tag_name_pretty", + &this->diagnostic_memory_); if (tag_namespace) { opening_tag_name_pretty += tag_namespace->span().string_view(); opening_tag_name_pretty += u8':'; diff --git a/src/quick-lint-js/fe/parse-statement.cpp b/src/quick-lint-js/fe/parse-statement.cpp index a41a1b2d6f..6ff46bdd5f 100644 --- a/src/quick-lint-js/fe/parse-statement.cpp +++ b/src/quick-lint-js/fe/parse-statement.cpp @@ -1232,7 +1232,7 @@ void Parser::parse_and_visit_export(Parse_Visitor_Base &v, // NOTE[ambiguous-ambient-statement-in-namespace]. Stacked_Buffering_Visitor exports_visitor = this->buffering_visitor_stack_.push(); - Bump_Vector exported_bad_tokens( + Vector exported_bad_tokens( "parse_and_visit_export exported_bad_tokens", &this->temporary_memory_); this->parse_and_visit_named_exports( exports_visitor.visitor(), @@ -1595,7 +1595,7 @@ void Parser::parse_and_visit_typescript_generic_parameters( const Char8 *less_end = this->peek().end; this->skip(); - Bump_Vector leading_commas( + Vector leading_commas( "parse_and_visit_typescript_generic_parameters leading_commas", &this->temporary_memory_); while (this->peek().type == Token_Type::comma) { @@ -1610,7 +1610,7 @@ void Parser::parse_and_visit_typescript_generic_parameters( Diag_TypeScript_Generic_Parameter_List_Is_Empty{ .expected_parameter = Source_Code_Span::unit(less_end), }); - for (Bump_Vector_Size i = 1; i < leading_commas.size(); ++i) { + for (Vector_Size i = 1; i < leading_commas.size(); ++i) { this->diag_reporter_->report( Diag_Multiple_Commas_In_Generic_Parameter_List{ .unexpected_comma = leading_commas[i], @@ -1942,7 +1942,7 @@ void Parser::parse_and_visit_function_declaration( Identifier function_name = this->peek().identifier_name(); this->skip(); - Bump_Vector overload_names( + Vector overload_names( "parse_and_visit_function_declaration overload_names", &this->temporary_memory_); @@ -2019,7 +2019,7 @@ void Parser::parse_and_visit_function_declaration( // function f(a, b) {} // #3 // // The last overload (#3 above) is the real function. - for (Bump_Vector_Size i = 0; i < overload_names.size() - 1; ++i) { + for (Vector_Size i = 0; i < overload_names.size() - 1; ++i) { Identifier &overload_name = overload_names[i]; if (overload_name.normalized_name() != real_function_name.normalized_name()) { @@ -4626,7 +4626,7 @@ void Parser::parse_and_visit_named_exports_for_typescript_type_only_import( void Parser::parse_and_visit_named_exports( Parse_Visitor_Base &v, std::optional typescript_type_only_keyword, - Bump_Vector *out_exported_bad_tokens) { + Vector *out_exported_bad_tokens) { QLJS_ASSERT(this->peek().type == Token_Type::left_curly); this->skip(); diff --git a/src/quick-lint-js/fe/parse.cpp b/src/quick-lint-js/fe/parse.cpp index d3e15b6eb1..1f754ae97d 100644 --- a/src/quick-lint-js/fe/parse.cpp +++ b/src/quick-lint-js/fe/parse.cpp @@ -192,8 +192,8 @@ void Parser::check_jsx_attribute(const Identifier& attribute_name) { bool name_has_upper = any_of(name, isupper); if (!name_has_upper && is_event_attribute) { - Bump_Vector fixed_name("check_jsx_attribute fixed_name", - &this->diagnostic_memory_); + Vector fixed_name("check_jsx_attribute fixed_name", + &this->diagnostic_memory_); fixed_name += name; fixed_name[2] = toupper(fixed_name[2]); this->diag_reporter_->report(Diag_JSX_Event_Attribute_Should_Be_Camel_Case{ diff --git a/src/quick-lint-js/fe/parse.h b/src/quick-lint-js/fe/parse.h index 0e028d7bd8..2a70b300c6 100644 --- a/src/quick-lint-js/fe/parse.h +++ b/src/quick-lint-js/fe/parse.h @@ -566,7 +566,7 @@ class Parser { void parse_and_visit_named_exports( Parse_Visitor_Base &v, std::optional typescript_type_only_keyword, - Bump_Vector *out_exported_bad_tokens); + Vector *out_exported_bad_tokens); void parse_and_visit_variable_declaration_statement( Parse_Visitor_Base &v, diff --git a/src/quick-lint-js/fe/token.h b/src/quick-lint-js/fe/token.h index 6f61d76284..b9aaead869 100644 --- a/src/quick-lint-js/fe/token.h +++ b/src/quick-lint-js/fe/token.h @@ -289,7 +289,7 @@ enum class Token_Type { const char* to_string(Token_Type); std::ostream& operator<<(std::ostream&, Token_Type); -using Escape_Sequence_List = Bump_Vector; +using Escape_Sequence_List = Vector; struct Token { Identifier identifier_name() const; diff --git a/src/quick-lint-js/i18n/po-parser.cpp b/src/quick-lint-js/i18n/po-parser.cpp index c809b24bbc..890c8f13c5 100644 --- a/src/quick-lint-js/i18n/po-parser.cpp +++ b/src/quick-lint-js/i18n/po-parser.cpp @@ -131,7 +131,7 @@ class PO_Parser { this->fatal(); } this->input_ += 1; - Bump_Vector decoded("parse_string", this->allocator_); + Vector decoded("parse_string", this->allocator_); for (;;) { switch (*this->input_) { case u8'"': { @@ -218,7 +218,7 @@ class PO_Parser { const CLI_Locator* locator_; Monotonic_Allocator* allocator_; - Bump_Vector entries_{"PO_Parser::entries", this->allocator_}; + Vector entries_{"PO_Parser::entries", this->allocator_}; bool is_next_entry_fuzzy_ = false; }; diff --git a/src/quick-lint-js/i18n/translation-table-compiler.cpp b/src/quick-lint-js/i18n/translation-table-compiler.cpp index e4a843267d..900feb9bf9 100644 --- a/src/quick-lint-js/i18n/translation-table-compiler.cpp +++ b/src/quick-lint-js/i18n/translation-table-compiler.cpp @@ -36,7 +36,7 @@ struct String_Table { } private: - Bump_Vector strings_; + Vector strings_; }; } @@ -78,8 +78,8 @@ Compiled_Translation_Table compile_translation_table( Span keys = untranslated_strings; { - Bump_Vector locale_names( - "compile_translation_table locale_names", allocator); + Vector locale_names("compile_translation_table locale_names", + allocator); for (const PO_File& file : files) { locale_names.push_back(file.locale); } @@ -182,8 +182,8 @@ Compiled_Translation_Table compile_translation_table( Span get_all_untranslated(Span files, Monotonic_Allocator* allocator) { - Bump_Vector all_untranslated( - "get_all_untranslated all_untranslated", allocator); + Vector all_untranslated("get_all_untranslated all_untranslated", + allocator); auto add_untranslated = [&](String8_View untranslated) -> void { bool is_duplicate = contains(all_untranslated, untranslated); if (!is_duplicate) { diff --git a/src/quick-lint-js/i18n/translation.cpp b/src/quick-lint-js/i18n/translation.cpp index 673a494fb3..d050377864 100644 --- a/src/quick-lint-js/i18n/translation.cpp +++ b/src/quick-lint-js/i18n/translation.cpp @@ -26,7 +26,7 @@ Translator qljs_messages; namespace { Span split_on(const char* s, char separator, Monotonic_Allocator* allocator) { - Bump_Vector locales("locales", allocator); + Vector locales("locales", allocator); for (;;) { const char* sep = std::strchr(s, separator); if (sep) { @@ -64,7 +64,7 @@ Span get_user_locale_preferences( // TODO(strager): Determine the language using macOS' and Windows' native // APIs. See GNU gettext's _nl_language_preferences_default. - Bump_Vector locales("locales", allocator); + Vector locales("locales", allocator); locales.push_back(locale); return locales.release_to_span(); } diff --git a/src/quick-lint-js/io/event-loop-poll.cpp b/src/quick-lint-js/io/event-loop-poll.cpp index 6f1c7988b9..d3b6c300ba 100644 --- a/src/quick-lint-js/io/event-loop-poll.cpp +++ b/src/quick-lint-js/io/event-loop-poll.cpp @@ -74,8 +74,8 @@ Event_Loop_Poll::~Event_Loop_Poll() { delete this->impl_; } void Event_Loop_Poll::run() { Monotonic_Allocator allocator("Event_Loop_Poll"); // events[i] corresponds to event_registered_events[i]. - Bump_Vector<::pollfd> events("events", &allocator); - Bump_Vector event_registered_events( + Vector<::pollfd> events("events", &allocator); + Vector event_registered_events( "event_registered_events", &allocator); while (!this->is_stop_requested()) { @@ -116,7 +116,7 @@ void Event_Loop_Poll::run() { } QLJS_ASSERT(rc > 0); - for (Bump_Vector_Size i = 0; i < events.size(); ++i) { + for (Vector_Size i = 0; i < events.size(); ++i) { const ::pollfd& event = events[i]; if (event.revents == 0) { continue; diff --git a/src/quick-lint-js/lsp/lsp-workspace-configuration.h b/src/quick-lint-js/lsp/lsp-workspace-configuration.h index e203717a11..813d8a1ef3 100644 --- a/src/quick-lint-js/lsp/lsp-workspace-configuration.h +++ b/src/quick-lint-js/lsp/lsp-workspace-configuration.h @@ -61,7 +61,7 @@ class LSP_Workspace_Configuration { Item* find_item(String8_View name); bool set_item(Item&, ::simdjson::ondemand::value); - Bump_Vector items_; + Vector items_; }; } diff --git a/src/quick-lint-js/port/child-process.cpp b/src/quick-lint-js/port/child-process.cpp index 5510387e18..9bb6c76191 100644 --- a/src/quick-lint-js/port/child-process.cpp +++ b/src/quick-lint-js/port/child-process.cpp @@ -86,7 +86,7 @@ Run_Program_Result run_program(Span command) { Run_Program_Result run_program(Span command, Run_Program_Options options) { Monotonic_Allocator allocator("run_program"); - Bump_Vector command_raw("command_raw", &allocator); + Vector command_raw("command_raw", &allocator); for (const std::string& arg : command) { command_raw.push_back(arg.c_str()); } @@ -122,7 +122,7 @@ Run_Program_Result run_program(Span command, } Monotonic_Allocator allocator("run_program"); - Bump_Vector argv("argv", &allocator); + Vector argv("argv", &allocator); for (const char* arg : command) { argv.push_back(const_cast(arg)); } diff --git a/src/quick-lint-js/reflection/cxx-parser.cpp b/src/quick-lint-js/reflection/cxx-parser.cpp index b1ea8980cd..3649cd48f7 100644 --- a/src/quick-lint-js/reflection/cxx-parser.cpp +++ b/src/quick-lint-js/reflection/cxx-parser.cpp @@ -233,8 +233,8 @@ String8_View CXX_Lexer::lex_string_literal() { QLJS_ASSERT(*this->input_ == u8'"'); this->input_ += 1; - Bump_Vector decoded("CXX_Lexer::lex_string_literal", - &this->decoded_string_allocator_); + Vector decoded("CXX_Lexer::lex_string_literal", + &this->decoded_string_allocator_); for (;;) { switch (*this->input_) { case u8'"': { diff --git a/src/quick-lint-js/reflection/cxx-parser.h b/src/quick-lint-js/reflection/cxx-parser.h index 9ccd4005f0..464cae512f 100644 --- a/src/quick-lint-js/reflection/cxx-parser.h +++ b/src/quick-lint-js/reflection/cxx-parser.h @@ -198,10 +198,9 @@ class CXX_Diagnostic_Types_Parser : private CXX_Parser_Base { using Base::fatal_at; Monotonic_Allocator allocator_{"CXX_Diagnostic_Types_Parser"}; - Bump_Vector parsed_types{"parsed_types", - &this->allocator_}; - Bump_Vector reserved_codes{"reserved_codes", - &this->allocator_}; + Vector parsed_types{"parsed_types", &this->allocator_}; + Vector reserved_codes{"reserved_codes", + &this->allocator_}; }; // Precondition: variables.size() <= 4 diff --git a/test/quick-lint-js/tjson.cpp b/test/quick-lint-js/tjson.cpp index f2b078accb..46e6cd29cd 100644 --- a/test/quick-lint-js/tjson.cpp +++ b/test/quick-lint-js/tjson.cpp @@ -98,8 +98,8 @@ TJSON_Value TJSON_Value::operator[](std::size_t index) const { std::optional> TJSON_Value::try_get_array() const { TJSON::Impl* tjson_impl = this->impl_->tjson_impl; - Bump_Vector items("TJSON_Value::try_get_array items", - &tjson_impl->allocator); + Vector items("TJSON_Value::try_get_array items", + &tjson_impl->allocator); ::simdjson::dom::array array; if (this->impl_->value.get(array) != ::simdjson::SUCCESS) { return std::nullopt; diff --git a/test/test-vector.cpp b/test/test-vector.cpp index 0d40c099d8..be645e4654 100644 --- a/test/test-vector.cpp +++ b/test/test-vector.cpp @@ -14,17 +14,17 @@ using ::testing::IsEmpty; namespace quick_lint_js { namespace { -TEST(Test_Bump_Vector, empty) { +TEST(Test_Vector, empty) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Vector v("test", &alloc); EXPECT_TRUE(v.empty()); EXPECT_EQ(v.size(), 0); EXPECT_EQ(v.capacity(), 0); } -TEST(Test_Bump_Vector, append_into_reserved_memory) { +TEST(Test_Vector, append_into_reserved_memory) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Vector v("test", &alloc); v.reserve(2); EXPECT_EQ(v.capacity(), 2); EXPECT_EQ(v.size(), 0); @@ -40,10 +40,10 @@ TEST(Test_Bump_Vector, append_into_reserved_memory) { EXPECT_THAT(v, ElementsAreArray({100, 200})); } -TEST(Test_Bump_Vector, reserve_0_does_nothing) { +TEST(Test_Vector, reserve_0_does_nothing) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Vector v("test", &alloc); v.reserve(0); EXPECT_EQ(v.capacity(), 0); EXPECT_EQ(v.size(), 0); @@ -51,15 +51,15 @@ TEST(Test_Bump_Vector, reserve_0_does_nothing) { v.push_back(100); v.push_back(200); v.push_back(300); - Bump_Vector_Size old_capacity = v.capacity(); + Vector_Size old_capacity = v.capacity(); v.reserve(0); EXPECT_EQ(v.capacity(), old_capacity); EXPECT_EQ(v.size(), 3); } -TEST(Test_Bump_Vector, append_into_new_memory) { +TEST(Test_Vector, append_into_new_memory) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Vector v("test", &alloc); EXPECT_EQ(v.capacity(), 0); EXPECT_EQ(v.size(), 0); @@ -74,9 +74,9 @@ TEST(Test_Bump_Vector, append_into_new_memory) { EXPECT_THAT(v, ElementsAreArray({100, 200})); } -TEST(Test_Bump_Vector, growing_allocation_in_place) { +TEST(Test_Vector, growing_allocation_in_place) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Vector v("test", &alloc); v.reserve(2); v.emplace_back(100); @@ -90,9 +90,9 @@ TEST(Test_Bump_Vector, growing_allocation_in_place) { EXPECT_THAT(v, ElementsAreArray({100, 200, 300, 400})); } -TEST(Test_Bump_Vector, growing_allocation_by_copy) { +TEST(Test_Vector, growing_allocation_by_copy) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Vector v("test", &alloc); v.reserve(2); v.emplace_back(100); @@ -116,14 +116,14 @@ TEST(Test_Bump_Vector, growing_allocation_by_copy) { << "growing vector shouldn't change unrelated allocation"; } -TEST(Test_Bump_Vector, resize_allows_same_size) { +TEST(Test_Vector, resize_allows_same_size) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Vector v("test", &alloc); v.emplace_back(100); v.emplace_back(200); std::uintptr_t old_v_data_pointer = reinterpret_cast(v.data()); - Bump_Vector_Size old_capacity = v.capacity(); + Vector_Size old_capacity = v.capacity(); v.resize(2); @@ -135,15 +135,15 @@ TEST(Test_Bump_Vector, resize_allows_same_size) { << "resizing vector should not change data pointer"; } -TEST(Test_Bump_Vector, resize_allows_shrinking) { +TEST(Test_Vector, resize_allows_shrinking) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Vector v("test", &alloc); v.emplace_back(100); v.emplace_back(200); v.emplace_back(300); std::uintptr_t old_v_data_pointer = reinterpret_cast(v.data()); - Bump_Vector_Size old_capacity = v.capacity(); + Vector_Size old_capacity = v.capacity(); v.resize(2); @@ -156,14 +156,14 @@ TEST(Test_Bump_Vector, resize_allows_shrinking) { << "shrinking vector should not change data pointer"; } -TEST(Test_Bump_Vector, resize_allows_growing_within_capacity) { +TEST(Test_Vector, resize_allows_growing_within_capacity) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Vector v("test", &alloc); v.emplace_back(100); v.emplace_back(200); std::uintptr_t old_v_data_pointer = reinterpret_cast(v.data()); - Bump_Vector_Size old_capacity = v.capacity(); + Vector_Size old_capacity = v.capacity(); ASSERT_GE(old_capacity, 3); v.resize(3); @@ -177,9 +177,9 @@ TEST(Test_Bump_Vector, resize_allows_growing_within_capacity) { << "growing vector within capacity should not change data pointer"; } -TEST(Test_Bump_Vector, resize_allows_growing_outside_capacity) { +TEST(Test_Vector, resize_allows_growing_outside_capacity) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Vector v("test", &alloc); v.emplace_back(100); v.emplace_back(200); @@ -193,9 +193,9 @@ TEST(Test_Bump_Vector, resize_allows_growing_outside_capacity) { << "growing vector should default-construct new elements"; } -TEST(Test_Bump_Vector, pop_back_shrinks_vector) { +TEST(Test_Vector, pop_back_shrinks_vector) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Vector v("test", &alloc); v.push_back(100); v.push_back(200); v.push_back(300); @@ -205,9 +205,9 @@ TEST(Test_Bump_Vector, pop_back_shrinks_vector) { EXPECT_GE(v.capacity(), 3); } -TEST(Test_Bump_Vector, pop_back_then_push_back_reuses_memory) { +TEST(Test_Vector, pop_back_then_push_back_reuses_memory) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Vector v("test", &alloc); v.push_back(100); v.push_back(200); v.push_back(300); @@ -222,28 +222,28 @@ TEST(Test_Bump_Vector, pop_back_then_push_back_reuses_memory) { EXPECT_GE(v.capacity(), 3); } -TEST(Test_Bump_Vector, move_constructing_clears_old_vector) { +TEST(Test_Vector, move_constructing_clears_old_vector) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Vector v("test", &alloc); v.emplace_back(100); v.emplace_back(200); - Bump_Vector v2(std::move(v)); + Vector v2(std::move(v)); EXPECT_THAT(v, IsEmpty()); } -TEST(Test_Bump_Vector, move_constructor_preserves_pointers) { +TEST(Test_Vector, move_constructor_preserves_pointers) { Linked_Bump_Allocator alloc("test"); - Bump_Vector v("test", &alloc); + Vector v("test", &alloc); v.emplace_back(100); v.emplace_back(200); std::uintptr_t old_v_data_pointer = reinterpret_cast(v.data()); - Bump_Vector_Size old_v_capacity = v.capacity(); - Bump_Vector_Size old_v_size = v.size(); + Vector_Size old_v_capacity = v.capacity(); + Vector_Size old_v_size = v.size(); - Bump_Vector v2(std::move(v)); + Vector v2(std::move(v)); EXPECT_EQ(reinterpret_cast(v2.data()), old_v_data_pointer); EXPECT_EQ(v2.capacity(), old_v_capacity); diff --git a/tools/compile-translations.cpp b/tools/compile-translations.cpp index 54d654b3a6..3d4407838b 100644 --- a/tools/compile-translations.cpp +++ b/tools/compile-translations.cpp @@ -39,7 +39,7 @@ struct String_Table { // Copies the string. explicit Entry(String8_View string, Monotonic_Allocator* allocator); - Bump_Vector origin_file_paths; + Vector origin_file_paths; String8_View string; }; @@ -125,7 +125,7 @@ int main(int argc, char** argv) { write_messages_po_template(string_table, output_messages_pot_path); Monotonic_Allocator allocator("main"); - Bump_Vector po_files("PO files", &allocator); + Vector po_files("PO files", &allocator); for (const char* po_file_path : po_file_paths) { po_files.push_back(PO_File{ .locale = po_path_to_locale_name(po_file_path), @@ -484,8 +484,8 @@ void write_translation_test_header( Output_Stream& out) { Monotonic_Allocator allocator("write_translation_test_header"); - Bump_Vector locale_names( - "compile_translation_table locale_names", &allocator); + Vector locale_names("compile_translation_table locale_names", + &allocator); for (const PO_File& file : po_files) { locale_names.push_back(file.locale); } diff --git a/tools/generate-trace-sources.cpp b/tools/generate-trace-sources.cpp index cce75c810f..9c148caa67 100644 --- a/tools/generate-trace-sources.cpp +++ b/tools/generate-trace-sources.cpp @@ -141,8 +141,8 @@ class CXX_Trace_Types_Parser : public CXX_Parser_Base { this->skip(); this->expect_skip(CXX_Token_Type::less); this->expect_skip(u8"class"_sv); - Bump_Vector template_parameters("template_parameters", - &this->memory_); + Vector template_parameters("template_parameters", + &this->memory_); template_parameters.emplace_back(this->expect_skip_identifier()); this->expect_skip(CXX_Token_Type::greater); s.template_parameters = template_parameters.release_to_span(); @@ -154,7 +154,7 @@ class CXX_Trace_Types_Parser : public CXX_Parser_Base { s.ctf_name = this->cxx_name_to_ctf_name(s.cxx_name); this->expect_skip(CXX_Token_Type::left_curly); - Bump_Vector members("members", &this->memory_); + Vector members("members", &this->memory_); while (!this->peek_is(CXX_Token_Type::right_curly)) { if (this->peek_is(u8"static"_sv)) { // static constexpr std::uint8_t id = 0x03; @@ -291,7 +291,7 @@ class CXX_Trace_Types_Parser : public CXX_Parser_Base { e.underlying_cxx_type = this->expect_skip_identifier(); this->expect_skip(CXX_Token_Type::left_curly); - Bump_Vector members("members", &this->memory_); + Vector members("members", &this->memory_); while (!this->peek_is(CXX_Token_Type::right_curly)) { // name = 42, Parsed_Enum_Member& member = members.emplace_back(); @@ -392,7 +392,7 @@ class CXX_Trace_Types_Parser : public CXX_Parser_Base { } Monotonic_Allocator memory_{"CXX_Trace_Types_Parser"}; - Bump_Vector declarations{"declarations", &this->memory_}; + Vector declarations{"declarations", &this->memory_}; }; void write_010_editor_template(CXX_Trace_Types_Parser& types, From 539edff270134edd5a231472ef5d7afa1ae7c3f3 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sun, 5 Nov 2023 02:11:35 -0500 Subject: [PATCH 097/117] feat(container): implement Vector::push_front This function will be handy in the future. --- src/quick-lint-js/container/vector-profiler.h | 6 ++++++ src/quick-lint-js/container/vector.h | 20 +++++++++++++++++++ test/test-vector.cpp | 10 ++++++++++ 3 files changed, 36 insertions(+) diff --git a/src/quick-lint-js/container/vector-profiler.h b/src/quick-lint-js/container/vector-profiler.h index 4703250044..4880096e2e 100644 --- a/src/quick-lint-js/container/vector-profiler.h +++ b/src/quick-lint-js/container/vector-profiler.h @@ -268,6 +268,12 @@ class Instrumented_Vector { this->add_instrumentation_entry(Vector_Instrumentation::Event::resize); } + QLJS_FORCE_INLINE void push_front(value_type &&value) { + this->data_.push_front(std::move(value)); + // TODO(strager): Add instrumentation specific to prepending. + this->add_instrumentation_entry(Vector_Instrumentation::Event::resize); + } + QLJS_FORCE_INLINE void clear() { this->data_.clear(); this->add_instrumentation_entry(Vector_Instrumentation::Event::clear); diff --git a/src/quick-lint-js/container/vector.h b/src/quick-lint-js/container/vector.h index 111b30321f..98f6cedb81 100644 --- a/src/quick-lint-js/container/vector.h +++ b/src/quick-lint-js/container/vector.h @@ -74,6 +74,7 @@ class Uninstrumented_Vector : private Vector { using Vector::operator[]; using Vector::pop_back; using Vector::push_back; + using Vector::push_front; using Vector::reserve; using Vector::resize; using Vector::size; @@ -270,6 +271,25 @@ class Raw_Vector { this->data_end_ -= 1; } + void push_front(value_type &&value) { + if (this->empty()) { + this->push_back(std::move(value)); + } else { + if (this->capacity_end_ == this->data_end_) { + this->reserve_grow_by_at_least(1); + } + // Shift all items to the right one. The last item is move-constructed + // into place, and the remaining items are move-assigned into place right + // to left. + new (&this->data_end_[0]) value_type(std::move(this->data_end_[-1])); + for (value_type *p = this->data_end_; p-- > this->data_;) { + p[1] = p[0]; + } + this->data_[0] = std::move(value); + this->data_end_ += 1; + } + } + // Like clear(), but doesn't touch the allocated memory. Objects remain alive // and valid. void release() { diff --git a/test/test-vector.cpp b/test/test-vector.cpp index be645e4654..03501930f8 100644 --- a/test/test-vector.cpp +++ b/test/test-vector.cpp @@ -222,6 +222,16 @@ TEST(Test_Vector, pop_back_then_push_back_reuses_memory) { EXPECT_GE(v.capacity(), 3); } +TEST(Test_Vector, push_front_multiple_empty_is_push_back_backwards) { + Linked_Bump_Allocator alloc("test"); + Vector v("test", &alloc); + v.push_front(100); + v.push_front(200); + v.push_front(300); + v.push_front(400); + EXPECT_THAT(v, ElementsAreArray({400, 300, 200, 100})); +} + TEST(Test_Vector, move_constructing_clears_old_vector) { Linked_Bump_Allocator alloc("test"); Vector v("test", &alloc); From 127c598ee0579c5a7b0cea5d4b0498b19c86da0b Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sun, 5 Nov 2023 02:11:35 -0500 Subject: [PATCH 098/117] feat(container): implement Vector::erase(begin, end) This function will be handy in the future. --- src/quick-lint-js/container/vector-profiler.h | 6 ++ src/quick-lint-js/container/vector.h | 17 ++++ test/test-vector.cpp | 81 +++++++++++++++++++ 3 files changed, 104 insertions(+) diff --git a/src/quick-lint-js/container/vector-profiler.h b/src/quick-lint-js/container/vector-profiler.h index 4880096e2e..b7f4cf2e42 100644 --- a/src/quick-lint-js/container/vector-profiler.h +++ b/src/quick-lint-js/container/vector-profiler.h @@ -279,6 +279,12 @@ class Instrumented_Vector { this->add_instrumentation_entry(Vector_Instrumentation::Event::clear); } + QLJS_FORCE_INLINE void erase(iterator begin, iterator end) { + this->data_.erase(begin, end); + // TODO(strager): Add instrumentation specific to erasing. + this->add_instrumentation_entry(Vector_Instrumentation::Event::resize); + } + void reserve(size_type new_capacity) { this->data_.reserve(new_capacity); } void resize(size_type new_size) { diff --git a/src/quick-lint-js/container/vector.h b/src/quick-lint-js/container/vector.h index 98f6cedb81..d1d8651d81 100644 --- a/src/quick-lint-js/container/vector.h +++ b/src/quick-lint-js/container/vector.h @@ -69,6 +69,7 @@ class Uninstrumented_Vector : private Vector { using Vector::emplace_back; using Vector::empty; using Vector::end; + using Vector::erase; using Vector::front; using Vector::get_allocator; using Vector::operator[]; @@ -321,6 +322,22 @@ class Raw_Vector { } } + void erase(value_type *begin, value_type *end) { + // Shift items left (via move assignment), then destruct items on the right. + + value_type *assign_to_begin = begin; + value_type *assign_from_begin = end; + value_type *assign_from_end = this->data_end_; + value_type *assign_to_end = + std::move(assign_from_begin, assign_from_end, assign_to_begin); + + value_type *destroy_begin = assign_to_end; + value_type *destroy_end = this->data_end_; + std::destroy(destroy_begin, destroy_end); + + this->data_end_ = destroy_begin; + } + // If new_size > this->size(): default-construct new items at the end. // If new_size < this->size(): destruct items at the end. // diff --git a/test/test-vector.cpp b/test/test-vector.cpp index 03501930f8..44efb2b070 100644 --- a/test/test-vector.cpp +++ b/test/test-vector.cpp @@ -232,6 +232,87 @@ TEST(Test_Vector, push_front_multiple_empty_is_push_back_backwards) { EXPECT_THAT(v, ElementsAreArray({400, 300, 200, 100})); } +TEST(Test_Vector, erase_from_begin_to_end_is_clear) { + Linked_Bump_Allocator alloc("test"); + Vector v("test", &alloc); + v.push_back(100); + v.push_back(200); + v.push_back(300); + + v.erase(v.begin(), v.end()); + EXPECT_THAT(v, IsEmpty()); +} + +TEST(Test_Vector, + erase_from_begin_to_middle_where_assign_and_destroy_do_not_overlap) { + Linked_Bump_Allocator alloc("test"); + Vector v("test", &alloc); + v.push_back(100); + v.push_back(200); + v.push_back(300); + v.push_back(400); + + // 100, 200, 300, 400 + // _______/ | + // / ________/ + // | / + // 300, 400, ---, --- + // + // 100 = 300 + // 200 = 400 + + v.erase(v.begin(), v.begin() + 2); + EXPECT_THAT(v, ElementsAreArray({300, 400})); +} + +TEST(Test_Vector, erase_from_begin_to_middle_where_assign_and_destroy_overlap) { + Linked_Bump_Allocator alloc("test"); + Vector v("test", &alloc); + v.push_back(100); + v.push_back(200); + v.push_back(300); + v.push_back(400); + v.push_back(500); + + // 100, 200, 300, 400, 500 + // _______/ | | + // / _______/ | + // | / ________/ + // | | / + // 300, 400, 500, ---, --- + // + // 100 = 300 + // 200 = 400 + // 300 = 500 + + v.erase(v.begin(), v.begin() + 2); + EXPECT_THAT(v, ElementsAreArray({300, 400, 500})); +} + +TEST(Test_Vector, erase_from_middle_to_end_removes_suffix) { + Linked_Bump_Allocator alloc("test"); + Vector v("test", &alloc); + v.push_back(100); + v.push_back(200); + v.push_back(300); + v.push_back(400); + + v.erase(v.begin() + 2, v.end()); + EXPECT_THAT(v, ElementsAreArray({100, 200})); +} + +TEST(Test_Vector, erase_from_middle_to_middle_removes_inner_items) { + Linked_Bump_Allocator alloc("test"); + Vector v("test", &alloc); + v.push_back(100); + v.push_back(200); + v.push_back(300); + v.push_back(400); + + v.erase(v.begin() + 1, v.begin() + 3); + EXPECT_THAT(v, ElementsAreArray({100, 400})); +} + TEST(Test_Vector, move_constructing_clears_old_vector) { Linked_Bump_Allocator alloc("test"); Vector v("test", &alloc); From c61fae652906948d01d8d9f03190d020d40c071d Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sun, 5 Nov 2023 02:11:35 -0500 Subject: [PATCH 099/117] refactor(container): prefer Vector over std::vector Reduce our use of std::vector to reduce binary bloat: https://github.com/quick-lint/quick-lint-js/issues/689 --- src/quick-lint-js/container/byte-buffer.cpp | 11 +++++++---- src/quick-lint-js/container/byte-buffer.h | 6 +++--- src/quick-lint-js/container/vector-profiler.h | 4 ++++ src/quick-lint-js/container/vector.h | 4 ++++ 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/quick-lint-js/container/byte-buffer.cpp b/src/quick-lint-js/container/byte-buffer.cpp index 96e5fbfc37..ea02b207f6 100644 --- a/src/quick-lint-js/container/byte-buffer.cpp +++ b/src/quick-lint-js/container/byte-buffer.cpp @@ -68,7 +68,10 @@ Byte_Buffer_Chunk make_chunk(const void* data, Byte_Buffer::Size_Type size) { } -Byte_Buffer::Byte_Buffer() { this->add_new_chunk(this->default_chunk_size); } +Byte_Buffer::Byte_Buffer() + : chunks_("Byte_Buffer::chunks_", new_delete_resource()) { + this->add_new_chunk(this->default_chunk_size); +} Byte_Buffer::Byte_Buffer(Byte_Buffer&&) = default; @@ -107,7 +110,7 @@ void Byte_Buffer::prepend_copy(String8_View data) { std::copy_n(data_bytes, data.size(), chunk_begin(prefix_chunk)); QLJS_ASSERT(end == chunk_end(prefix_chunk)); - this->chunks_.insert(this->chunks_.begin(), std::move(prefix_chunk)); + this->chunks_.push_front(std::move(prefix_chunk)); } void Byte_Buffer::clear() { @@ -123,7 +126,7 @@ void Byte_Buffer::clear() { Byte_Buffer::Size_Type Byte_Buffer::size() const { Size_Type total_size = 0; - for (std::size_t chunk_index = 0; chunk_index < this->chunks_.size() - 1; + for (Vector_Size chunk_index = 0; chunk_index < this->chunks_.size() - 1; ++chunk_index) { const Byte_Buffer_Chunk& c = this->chunks_[chunk_index]; total_size += chunk_size(c); @@ -136,7 +139,7 @@ bool Byte_Buffer::empty() const { if (this->bytes_used_in_current_chunk() > 0) { return false; } - for (std::size_t chunk_index = 0; chunk_index < this->chunks_.size() - 1; + for (Vector_Size chunk_index = 0; chunk_index < this->chunks_.size() - 1; ++chunk_index) { const Byte_Buffer_Chunk& c = this->chunks_[chunk_index]; if (chunk_size(c) > 0) { diff --git a/src/quick-lint-js/container/byte-buffer.h b/src/quick-lint-js/container/byte-buffer.h index 0b3b98c440..4eb87905b8 100644 --- a/src/quick-lint-js/container/byte-buffer.h +++ b/src/quick-lint-js/container/byte-buffer.h @@ -6,12 +6,12 @@ #include #include #include +#include #include #include #include #include #include -#include #if QLJS_HAVE_WRITEV #include @@ -89,7 +89,7 @@ class Byte_Buffer { template void enumerate_chunks(Func&& on_chunk) const { - for (std::size_t chunk_index = 0; chunk_index < this->chunks_.size(); + for (Vector_Size chunk_index = 0; chunk_index < this->chunks_.size(); ++chunk_index) { const Byte_Buffer_Chunk* c = &this->chunks_[chunk_index]; const std::byte* c_begin = @@ -128,7 +128,7 @@ class Byte_Buffer { static Byte_Buffer_Chunk allocate_chunk(Size_Type size); static void delete_chunk(Byte_Buffer_Chunk&&); - std::vector chunks_; + Vector chunks_; std::byte* cursor_; std::byte* current_chunk_end_; diff --git a/src/quick-lint-js/container/vector-profiler.h b/src/quick-lint-js/container/vector-profiler.h index b7f4cf2e42..8ba414f4b3 100644 --- a/src/quick-lint-js/container/vector-profiler.h +++ b/src/quick-lint-js/container/vector-profiler.h @@ -236,6 +236,10 @@ class Instrumented_Vector { return this->data_[index]; } + QLJS_FORCE_INLINE const value_type &operator[](size_type index) const { + return this->data_[index]; + } + QLJS_FORCE_INLINE value_type *begin() { return this->data(); } QLJS_FORCE_INLINE value_type *end() { return this->begin() + this->size(); } diff --git a/src/quick-lint-js/container/vector.h b/src/quick-lint-js/container/vector.h index d1d8651d81..858351a99f 100644 --- a/src/quick-lint-js/container/vector.h +++ b/src/quick-lint-js/container/vector.h @@ -186,6 +186,10 @@ class Raw_Vector { QLJS_ASSERT(index < this->size()); return this->data_[index]; } + const T &operator[](size_type index) const { + QLJS_ASSERT(index < this->size()); + return this->data_[index]; + } // Precondition: (none) void reserve(size_type new_capacity) { From ab8b151808af1bcc36ddbbeb19436029c1f18a2c Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Sun, 5 Nov 2023 11:37:42 -0500 Subject: [PATCH 100/117] fix(port): work around GCC false positive warning GCC thinks that Memory_Resource::do_try_grow_in_place should be declared 'final', but it is overwritten by Linked_Bump_Allocator. Ignore GCC's false -Wsuggest-final-methods warning. After fixing -Wsuggest-final-methods, GCC decides to report that the entire Memory_Resource class can be marked final. Ignore this false -Wsuggest-final-types warning as well. --- src/quick-lint-js/port/memory-resource.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/quick-lint-js/port/memory-resource.h b/src/quick-lint-js/port/memory-resource.h index 05c0b6f186..51d8083233 100644 --- a/src/quick-lint-js/port/memory-resource.h +++ b/src/quick-lint-js/port/memory-resource.h @@ -8,9 +8,14 @@ #include #include #include +#include #include #include +QLJS_WARNING_PUSH +QLJS_WARNING_IGNORE_GCC("-Wsuggest-final-methods") +QLJS_WARNING_IGNORE_GCC("-Wsuggest-final-types") + namespace quick_lint_js { // Like std::pmr::memory_resource. // @@ -122,6 +127,8 @@ class Memory_Resource { Memory_Resource* new_delete_resource(); } +QLJS_WARNING_POP + // quick-lint-js finds bugs in JavaScript programs. // Copyright (C) 2020 Matthew "strager" Glazar // From f2d61a0736adb43254d8d8b3706a8fe3abde0b4c Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Mon, 6 Nov 2023 17:00:06 -0500 Subject: [PATCH 101/117] refactor(logging): prefer Vector over std::vector Reduce our use of std::vector to reduce binary bloat: https://github.com/quick-lint/quick-lint-js/issues/689 --- src/quick-lint-js/container/vector-profiler.h | 6 +++ src/quick-lint-js/container/vector.h | 2 + src/quick-lint-js/logging/logger.cpp | 8 +++- test/test-vector.cpp | 42 +++++++++++++++++++ 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/quick-lint-js/container/vector-profiler.h b/src/quick-lint-js/container/vector-profiler.h index 8ba414f4b3..d7e19aa0a6 100644 --- a/src/quick-lint-js/container/vector-profiler.h +++ b/src/quick-lint-js/container/vector-profiler.h @@ -289,6 +289,12 @@ class Instrumented_Vector { this->add_instrumentation_entry(Vector_Instrumentation::Event::resize); } + QLJS_FORCE_INLINE void erase(iterator item) { + this->data_.erase(item); + // TODO(strager): Add instrumentation specific to erasing. + this->add_instrumentation_entry(Vector_Instrumentation::Event::resize); + } + void reserve(size_type new_capacity) { this->data_.reserve(new_capacity); } void resize(size_type new_size) { diff --git a/src/quick-lint-js/container/vector.h b/src/quick-lint-js/container/vector.h index 858351a99f..72679b8dae 100644 --- a/src/quick-lint-js/container/vector.h +++ b/src/quick-lint-js/container/vector.h @@ -342,6 +342,8 @@ class Raw_Vector { this->data_end_ = destroy_begin; } + void erase(value_type *item) { erase(item, item + 1); } + // If new_size > this->size(): default-construct new items at the end. // If new_size < this->size(): destruct items at the end. // diff --git a/src/quick-lint-js/logging/logger.cpp b/src/quick-lint-js/logging/logger.cpp index 8823c92197..0ee1c56b65 100644 --- a/src/quick-lint-js/logging/logger.cpp +++ b/src/quick-lint-js/logging/logger.cpp @@ -9,15 +9,16 @@ #include #include #include +#include #include #include +#include #include #include #include #include #include #include -#include QLJS_WARNING_IGNORE_CLANG("-Wformat-nonliteral") QLJS_WARNING_IGNORE_GCC("-Wformat-security") @@ -31,7 +32,10 @@ QLJS_WARNING_IGNORE_GCC("-Wsuggest-attribute=format") namespace quick_lint_js { namespace { struct Global_Loggers { - std::vector loggers; + // NOTE(strager): We use Raw_Vector here instead of Vector. Otherwise, in + // vector instrumented builds, loggers might be initialized before the vector + // profiler is initialized, causing use-before-init issues. + Raw_Vector loggers{new_delete_resource()}; bool initialized = false; void initialize_if_needed() { diff --git a/test/test-vector.cpp b/test/test-vector.cpp index 44efb2b070..b22bb2ee31 100644 --- a/test/test-vector.cpp +++ b/test/test-vector.cpp @@ -313,6 +313,48 @@ TEST(Test_Vector, erase_from_middle_to_middle_removes_inner_items) { EXPECT_THAT(v, ElementsAreArray({100, 400})); } +TEST(Test_Vector, erase_only_element) { + Linked_Bump_Allocator alloc("test"); + Vector v("test", &alloc); + v.push_back(100); + + v.erase(v.begin()); + EXPECT_THAT(v, IsEmpty()); +} + +TEST(Test_Vector, erase_first_element) { + Linked_Bump_Allocator alloc("test"); + Vector v("test", &alloc); + v.push_back(100); + v.push_back(200); + v.push_back(300); + + v.erase(v.begin()); + EXPECT_THAT(v, ElementsAreArray({200, 300})); +} + +TEST(Test_Vector, erase_last_element) { + Linked_Bump_Allocator alloc("test"); + Vector v("test", &alloc); + v.push_back(100); + v.push_back(200); + v.push_back(300); + + v.erase(v.end() - 1); + EXPECT_THAT(v, ElementsAreArray({100, 200})); +} + +TEST(Test_Vector, erase_middle_element) { + Linked_Bump_Allocator alloc("test"); + Vector v("test", &alloc); + v.push_back(100); + v.push_back(200); + v.push_back(300); + + v.erase(v.begin() + 1); + EXPECT_THAT(v, ElementsAreArray({100, 300})); +} + TEST(Test_Vector, move_constructing_clears_old_vector) { Linked_Bump_Allocator alloc("test"); Vector v("test", &alloc); From 1a53022d8249f0f84f57147b33039d3beddea1a0 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Mon, 6 Nov 2023 22:52:13 -0500 Subject: [PATCH 102/117] fix(test): ensure profiling data is sent on debug server connect The test is not testing hard enough. Oops! --- test/test-debug-server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-debug-server.cpp b/test/test-debug-server.cpp index c578924528..a61d09b42a 100644 --- a/test/test-debug-server.cpp +++ b/test/test-debug-server.cpp @@ -170,7 +170,7 @@ TEST_F(Test_Debug_Server, ASSERT_EQ(v.size(), 0); } - bool received_vector_max_size_histogram_by_owner_event = true; + bool received_vector_max_size_histogram_by_owner_event = false; auto on_trace_event = [&](Debug_Server &, const Parsed_Trace_Event &event, [[maybe_unused]] std::uint64_t thread_index) -> bool { From d3e02c52e6876ac8b2104d994a9ffbfaee7aad60 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Mon, 6 Nov 2023 23:02:16 -0500 Subject: [PATCH 103/117] refactor(debug): prefer Vector over std::vector Reduce our use of std::vector to reduce binary bloat: https://github.com/quick-lint/quick-lint-js/issues/689 Because Debug_Server now uses Vector internally, make the vector instrumentation tests for Debug_Server tolerant of extra vector profile data. --- src/quick-lint-js/debug/debug-server.cpp | 16 ++++-- src/quick-lint-js/debug/debug-server.h | 6 +-- src/quick-lint-js/util/instance-tracker.h | 21 +++++--- src/quick-lint-js/util/synchronized.h | 4 ++ test/test-debug-server.cpp | 60 +++++++++++++---------- 5 files changed, 65 insertions(+), 42 deletions(-) diff --git a/src/quick-lint-js/debug/debug-server.cpp b/src/quick-lint-js/debug/debug-server.cpp index 2f6078cf81..21131181ba 100644 --- a/src/quick-lint-js/debug/debug-server.cpp +++ b/src/quick-lint-js/debug/debug-server.cpp @@ -14,7 +14,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -108,11 +110,13 @@ std::shared_ptr Debug_Server::create() { return instance; } -std::vector> Debug_Server::instances() { +Raw_Vector> Debug_Server::instances() { return Instance_Tracker::instances(); } -Debug_Server::Debug_Server(Create_Tag) {} +Debug_Server::Debug_Server(Create_Tag) + : tracer_backends_("Debug_Server::tracer_backends_", + new_delete_resource()) {} Debug_Server::~Debug_Server() { if (this->server_thread_.joinable()) { @@ -399,10 +403,14 @@ void Debug_Server::publish_lsp_documents_if_needed() { return; } - std::vector document_states; + Monotonic_Allocator temporary_allocator( + "Debug_Server::publish_lsp_documents_if_needed"); + Vector document_states("document_states", + &temporary_allocator); { Lock_Ptr documents = documents_raw->lock(); - document_states.reserve(documents->documents.size()); + document_states.reserve( + narrow_cast(documents->documents.size())); for (auto &[uri, doc] : documents->documents) { document_states.push_back(Trace_LSP_Document_State{ .type = doc->trace_type(), diff --git a/src/quick-lint-js/debug/debug-server.h b/src/quick-lint-js/debug/debug-server.h index 8686fde64f..a35cb3d233 100644 --- a/src/quick-lint-js/debug/debug-server.h +++ b/src/quick-lint-js/debug/debug-server.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -34,7 +35,7 @@ class Debug_Server { public: static std::shared_ptr create(); - static std::vector> instances(); + static Raw_Vector> instances(); explicit Debug_Server(Create_Tag); @@ -109,8 +110,7 @@ class Debug_Server { // Used by server thread only: // Each backend is associated with one WebSocket connection. - std::vector> - tracer_backends_; + Vector> tracer_backends_; #if QLJS_FEATURE_VECTOR_PROFILING Vector_Max_Size_Histogram_By_Owner max_size_histogram_; #endif diff --git a/src/quick-lint-js/util/instance-tracker.h b/src/quick-lint-js/util/instance-tracker.h index d4b95789c9..5a526db6eb 100644 --- a/src/quick-lint-js/util/instance-tracker.h +++ b/src/quick-lint-js/util/instance-tracker.h @@ -4,9 +4,9 @@ #pragma once #include +#include #include #include -#include namespace quick_lint_js { // Maintains a global list of instances of Tracked. Each Tracked must be managed @@ -18,16 +18,16 @@ template class Instance_Tracker { public: static void track(std::shared_ptr instance) { - Lock_Ptr>> weak_instances = + Lock_Ptr>> weak_instances = weak_instances_.lock(); sanitize_instances(weak_instances); weak_instances->push_back(std::move(instance)); } - static std::vector> instances() { - std::vector> instances; + static Raw_Vector> instances() { + Raw_Vector> instances(new_delete_resource()); { - Lock_Ptr>> weak_instances = + Lock_Ptr>> weak_instances = weak_instances_.lock(); sanitize_instances(weak_instances); instances.reserve(weak_instances->size()); @@ -38,12 +38,14 @@ class Instance_Tracker { } } } + // NOTE(strager): We cannot wink (e.g. use Linked_Bump_Allocator and return + // a Span) because std::shared_ptr destructors need to be called. return instances; } private: static void sanitize_instances( - Lock_Ptr>>& weak_instances) { + Lock_Ptr>>& weak_instances) { erase_if(*weak_instances, [](const std::weak_ptr& weak_instance) { return weak_instance.expired(); }); @@ -53,8 +55,11 @@ class Instance_Tracker { sanitize_instances(weak_instances_.lock()); } - static inline Synchronized>> - weak_instances_; + // NOTE(strager): We use Raw_Vector here instead of Vector. Otherwise, in + // vector instrumented builds, weak_instances_ might be initialized before the + // vector profiler is initialized, causing use-before-init issues. + static inline Synchronized>> + weak_instances_{new_delete_resource()}; }; } diff --git a/src/quick-lint-js/util/synchronized.h b/src/quick-lint-js/util/synchronized.h index a279028731..a965134d68 100644 --- a/src/quick-lint-js/util/synchronized.h +++ b/src/quick-lint-js/util/synchronized.h @@ -15,6 +15,10 @@ class Lock_Ptr; template class Synchronized { public: + // Construct Data, forwarding arguments to Data's constructor. + template + explicit Synchronized(Args&&... args) : data_(std::forward(args)...) {} + // Acquire the mutex. When the returned lock_ptr is destructed, the mutex is // released. Lock_Ptr lock(); diff --git a/test/test-debug-server.cpp b/test/test-debug-server.cpp index a61d09b42a..7ffbd49f59 100644 --- a/test/test-debug-server.cpp +++ b/test/test-debug-server.cpp @@ -179,15 +179,19 @@ TEST_F(Test_Debug_Server, // This should eventually be called. Span entries = event.vector_max_size_histogram_by_owner_event.entries; - EXPECT_EQ(entries.size(), 1); - if (entries.size() > 0) { - EXPECT_EQ(entries[0].owner, u8"debug server test vector"_sv); - EXPECT_THAT(entries[0].max_size_entries, - ::testing::ElementsAreArray({ - Trace_Vector_Max_Size_Histogram_Entry{.max_size = 0, - .count = 1}, - })); + bool found_entry = false; + for (const Trace_Vector_Max_Size_Histogram_By_Owner_Entry &entry : + entries) { + if (entry.owner == u8"debug server test vector"_sv) { + found_entry = true; + EXPECT_THAT(entry.max_size_entries, + ::testing::ElementsAreArray({ + Trace_Vector_Max_Size_Histogram_Entry{.max_size = 0, + .count = 1}, + })); + } } + EXPECT_TRUE(found_entry); received_vector_max_size_histogram_by_owner_event = true; return false; @@ -220,7 +224,7 @@ TEST_F(Test_Debug_Server, TEST_F(Test_Debug_Server, vector_profile_probe_publishes_stats) { Vector_Instrumentation::instance.clear(); - bool received_vector_max_size_histogram_by_owner_event = false; + bool received_vector_profile_entry = false; auto on_trace_event = [&](Debug_Server &server, const Parsed_Trace_Event &event, [[maybe_unused]] std::uint64_t thread_index) -> bool { @@ -245,28 +249,30 @@ TEST_F(Test_Debug_Server, vector_profile_probe_publishes_stats) { case Parsed_Trace_Event_Type::vector_max_size_histogram_by_owner_event: { // This should eventually be called. - if (event.vector_max_size_histogram_by_owner_event.entries.empty()) { - // We will receive an initial vector_max_size_histogram_by_owner - // event. Ignore it. - return true; - } Span entries = event.vector_max_size_histogram_by_owner_event.entries; - EXPECT_EQ(entries.size(), 1); - if (entries.size() > 0) { - EXPECT_EQ(entries[0].owner, u8"debug server test vector"_sv); - EXPECT_THAT(entries[0].max_size_entries, - ::testing::ElementsAreArray({ - Trace_Vector_Max_Size_Histogram_Entry{.max_size = 2, - .count = 1}, - Trace_Vector_Max_Size_Histogram_Entry{.max_size = 4, - .count = 1}, - })); + for (const Trace_Vector_Max_Size_Histogram_By_Owner_Entry &entry : + entries) { + if (entry.owner == u8"debug server test vector"_sv) { + received_vector_profile_entry = true; + EXPECT_EQ(entry.owner, u8"debug server test vector"_sv); + EXPECT_THAT(entry.max_size_entries, + ::testing::ElementsAreArray({ + Trace_Vector_Max_Size_Histogram_Entry{.max_size = 2, + .count = 1}, + Trace_Vector_Max_Size_Histogram_Entry{.max_size = 4, + .count = 1}, + })); + // Stop the server. + return false; + } } - received_vector_max_size_histogram_by_owner_event = true; - return false; + // We will receive an initial vector_max_size_histogram_by_owner event + // and perhaps spurious extra events. Ignore those events and keep waiting + // for the 'debug server test vector' events. + return true; } case Parsed_Trace_Event_Type::error_invalid_magic: @@ -289,7 +295,7 @@ TEST_F(Test_Debug_Server, vector_profile_probe_publishes_stats) { QLJS_UNREACHABLE(); }; test_web_socket(on_trace_event); - EXPECT_TRUE(received_vector_max_size_histogram_by_owner_event); + EXPECT_TRUE(received_vector_profile_entry); } #endif From b61b9d4eb7143a6ae12fc78cbe44e09429e42c37 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Mon, 6 Nov 2023 22:59:26 -0500 Subject: [PATCH 104/117] refactor(i18n): prefer Vector over std::vector Reduce our use of std::vector to reduce binary bloat: https://github.com/quick-lint/quick-lint-js/issues/689 --- src/quick-lint-js/i18n/locale.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/quick-lint-js/i18n/locale.cpp b/src/quick-lint-js/i18n/locale.cpp index d02ca9fe73..97b4cf675f 100644 --- a/src/quick-lint-js/i18n/locale.cpp +++ b/src/quick-lint-js/i18n/locale.cpp @@ -1,6 +1,8 @@ // Copyright (C) 2020 Matthew "strager" Glazar // See end of file for extended copyright information. +#include "quick-lint-js/container/linked-bump-allocator.h" +#include "quick-lint-js/container/vector.h" #include #include #include @@ -108,12 +110,13 @@ QLJS_WARNING_IGNORE_GCC("-Wzero-as-null-pointer-constant") template void locale_name_combinations(std::string_view locale_name, Func&& callback) { + Linked_Bump_Allocator temporary_allocator("locale_name_combinations"); Locale_Parts parts = parse_locale(locale_name); - std::vector locale; - std::size_t max_locale_size = locale_name.size(); + Vector locale("locale", &temporary_allocator); + Vector_Size max_locale_size = narrow_cast(locale_name.size()); locale.reserve(max_locale_size); - locale.insert(locale.end(), parts.language().begin(), parts.language().end()); + locale += parts.language(); unsigned present_parts_mask = 0; for (std::size_t part_index = 1; part_index < 4; ++part_index) { @@ -143,17 +146,18 @@ void locale_name_combinations(std::string_view locale_name, Func&& callback) { continue; } - locale.resize(parts.language().size()); + locale.resize(narrow_cast(parts.language().size())); for (std::size_t part_index = 1; part_index < 4; ++part_index) { if (mask & (1 << part_index)) { std::string_view part = parts.parts[part_index]; locale.push_back(locale_part_separators[part_index - 1]); - locale.insert(locale.end(), part.begin(), part.end()); + locale += part; } } QLJS_ASSERT(locale.size() <= max_locale_size); - bool keep_going = callback(std::string_view(locale.data(), locale.size())); + bool keep_going = callback(std::string_view( + locale.data(), narrow_cast(locale.size()))); if (!keep_going) { break; } From 24ec5256cf44d99b214b8469a1bb8867e27aec80 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Mon, 6 Nov 2023 22:59:26 -0500 Subject: [PATCH 105/117] refactor(lsp): reuse line offset allocations for non-incremental changes If we receive a non-incremental change from the LSP client, LSP_Document_Text construct a new LSP_Locator. This causes memory for LSP_Locator::offset_of_lines_ and LSP_Locator::line_is_ascii_ to be deallocated then reallocated, which is wasteful. It also requires move assignment in LSP_Locator which conflicts with future refactors. Implement LSP_Locator::reset which reuses allocations, likely improving efficiently. (I did not measure whether there was actually any performance improvement due to this change.) --- src/quick-lint-js/lsp/lsp-document-text.cpp | 2 +- src/quick-lint-js/lsp/lsp-location.cpp | 7 +++++++ src/quick-lint-js/lsp/lsp-location.h | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/quick-lint-js/lsp/lsp-document-text.cpp b/src/quick-lint-js/lsp/lsp-document-text.cpp index 1621463890..02bd08be8b 100644 --- a/src/quick-lint-js/lsp/lsp-document-text.cpp +++ b/src/quick-lint-js/lsp/lsp-document-text.cpp @@ -61,7 +61,7 @@ LSP_Document_Text::LSP_Document_Text() : locator_(this->buffers_.string()) {} void LSP_Document_Text::set_text(String8_View new_text) { this->buffers_.set_text(new_text); - this->locator_ = LSP_Locator(this->buffers_.string()); + this->locator_.set_text(this->buffers_.string()); } void LSP_Document_Text::replace_text(LSP_Range range, diff --git a/src/quick-lint-js/lsp/lsp-location.cpp b/src/quick-lint-js/lsp/lsp-location.cpp index 605230426c..ef1a83e03a 100644 --- a/src/quick-lint-js/lsp/lsp-location.cpp +++ b/src/quick-lint-js/lsp/lsp-location.cpp @@ -122,6 +122,13 @@ const Char8 *LSP_Locator::from_position(LSP_Position position) const { } } +void LSP_Locator::set_text(Padded_String_View new_input) { + this->input_ = new_input; + this->offset_of_lines_.clear(); + this->line_is_ascii_.clear(); + this->cache_offsets_of_lines(); +} + void LSP_Locator::replace_text(LSP_Range range, String8_View replacement_text, Padded_String_View new_input) { Offset_Type start_offset = narrow_cast( diff --git a/src/quick-lint-js/lsp/lsp-location.h b/src/quick-lint-js/lsp/lsp-location.h index 172c2e9ff9..63616c4784 100644 --- a/src/quick-lint-js/lsp/lsp-location.h +++ b/src/quick-lint-js/lsp/lsp-location.h @@ -40,6 +40,7 @@ class LSP_Locator { const Char8 *from_position(LSP_Position) const; + void set_text(Padded_String_View new_input); void replace_text(LSP_Range, String8_View replacement_text, Padded_String_View new_input); From 50f32dae6cb785eb04b0ab27a468d6dd6b8dc3f1 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Mon, 6 Nov 2023 22:59:26 -0500 Subject: [PATCH 106/117] refactor(lsp): prefer Vector over std::vector Reduce our use of std::vector to reduce binary bloat: https://github.com/quick-lint/quick-lint-js/issues/689 --- src/quick-lint-js/container/vector-profiler.h | 13 ++++++ src/quick-lint-js/container/vector.h | 25 ++++++++++ src/quick-lint-js/lsp/lsp-location.cpp | 46 ++++++++----------- src/quick-lint-js/lsp/lsp-location.h | 13 ++++-- src/quick-lint-js/lsp/lsp-message-parser.h | 7 +-- .../lsp/outgoing-json-rpc-message-queue.h | 4 +- 6 files changed, 73 insertions(+), 35 deletions(-) diff --git a/src/quick-lint-js/container/vector-profiler.h b/src/quick-lint-js/container/vector-profiler.h index d7e19aa0a6..87d53699e2 100644 --- a/src/quick-lint-js/container/vector-profiler.h +++ b/src/quick-lint-js/container/vector-profiler.h @@ -355,6 +355,14 @@ class Instrumented_Vector { return Span(this->data_); } + void swap(Instrumented_Vector &other) { + this->data_.swap(other.data_); + std::swap(this->debug_owner_, other.debug_owner_); + // TODO(strager): Add instrumentation specific to swapping. + this->add_instrumentation_entry(Vector_Instrumentation::Event::resize); + other.add_instrumentation_entry(Vector_Instrumentation::Event::resize); + } + private: QLJS_FORCE_INLINE void add_instrumentation_entry( Vector_Instrumentation::Event event) { @@ -370,6 +378,11 @@ class Instrumented_Vector { Vector data_; const char *debug_owner_; }; + +template +void swap(Instrumented_Vector &lhs, Instrumented_Vector &rhs) { + lhs.swap(rhs); +} #endif } diff --git a/src/quick-lint-js/container/vector.h b/src/quick-lint-js/container/vector.h index 72679b8dae..9f6e8c1715 100644 --- a/src/quick-lint-js/container/vector.h +++ b/src/quick-lint-js/container/vector.h @@ -90,8 +90,17 @@ class Uninstrumented_Vector : private Vector { using Vector::release_to_span; using Vector::release_to_string_view; using Vector::to_string_view; + + void swap(Uninstrumented_Vector &other) { + static_cast(*this).swap(static_cast(other)); + } }; +template +void swap(Uninstrumented_Vector &lhs, Uninstrumented_Vector &rhs) { + lhs.swap(rhs); +} + using Vector_Size = std::ptrdiff_t; // Like std::pmr::vector. Some differences: @@ -344,6 +353,17 @@ class Raw_Vector { void erase(value_type *item) { erase(item, item + 1); } + // Swap capacity pointers and sizes between *this and other. All items of + // *this and other are untouched. + // + // Precondition: this->get_allocator() == other.get_allocator() + void swap(Raw_Vector &other) { + QLJS_ALWAYS_ASSERT(this->get_allocator() == other.get_allocator()); + std::swap(this->data_, other.data_); + std::swap(this->data_end_, other.data_end_); + std::swap(this->capacity_end_, other.capacity_end_); + } + // If new_size > this->size(): default-construct new items at the end. // If new_size < this->size(): destruct items at the end. // @@ -415,6 +435,11 @@ class Raw_Vector { Memory_Resource *allocator_; }; +template +void swap(Raw_Vector &lhs, Raw_Vector &rhs) { + lhs.swap(rhs); +} + #if QLJS_FEATURE_VECTOR_PROFILING template using Vector = Instrumented_Vector>; diff --git a/src/quick-lint-js/lsp/lsp-location.cpp b/src/quick-lint-js/lsp/lsp-location.cpp index ef1a83e03a..b21e701f92 100644 --- a/src/quick-lint-js/lsp/lsp-location.cpp +++ b/src/quick-lint-js/lsp/lsp-location.cpp @@ -19,12 +19,10 @@ namespace { template void insert_back_transform(Input_It input_begin, Input_It input_end, Output &output, Transformer &&transformer) { - using Difference_Type = typename Output::difference_type; - std::size_t original_size = output.size(); - std::size_t final_size = - original_size + narrow_cast(input_end - input_begin); + Vector_Size original_size = output.size(); + Vector_Size final_size = original_size + input_end - input_begin; output.resize(final_size); - auto output_it = output.begin() + narrow_cast(original_size); + auto output_it = output.begin() + original_size; output_it = std::transform(input_begin, input_end, output_it, transformer); QLJS_ASSERT(output_it == output.end()); } @@ -66,9 +64,8 @@ const Char8 *LSP_Locator::from_position(LSP_Position position) const { return this->input_.null_terminator(); } - Offset_Type line_begin_offset = - this->offset_of_lines_[narrow_cast(line)]; - bool line_is_ascii = this->line_is_ascii_[narrow_cast(line)]; + Offset_Type line_begin_offset = this->offset_of_lines_[line]; + bool line_is_ascii = this->line_is_ascii_[line]; bool is_last_line = line == number_of_lines - 1; if (is_last_line) { // TODO(strager): Get rid of this narrow_cast. @@ -86,8 +83,7 @@ const Char8 *LSP_Locator::from_position(LSP_Position position) const { return advance_lsp_characters_in_utf_8(line_string, character); } } else { - Offset_Type line_end_offset = - this->offset_of_lines_[narrow_cast(line + 1)]; + Offset_Type line_end_offset = this->offset_of_lines_[line + 1]; Offset_Type line_length_including_terminator = line_end_offset - line_begin_offset; if (line_is_ascii) { @@ -139,24 +135,24 @@ void LSP_Locator::replace_text(LSP_Range range, String8_View replacement_text, narrow_cast(replacement_text.size()); QLJS_ASSERT(!this->offset_of_lines_.empty()); - std::size_t start_line = narrow_cast(range.start.line); - std::size_t end_line = std::min(this->offset_of_lines_.size() - 1, - narrow_cast(range.end.line)); + Vector_Size start_line = narrow_cast(range.start.line); + Vector_Size end_line = std::min(this->offset_of_lines_.size() - 1, + narrow_cast(range.end.line)); this->input_ = new_input; - std::swap(this->old_offset_of_lines_, this->offset_of_lines_); - std::swap(this->old_line_is_ascii_, this->line_is_ascii_); + swap(this->old_offset_of_lines_, this->offset_of_lines_); + swap(this->old_line_is_ascii_, this->line_is_ascii_); this->offset_of_lines_.reserve(this->old_offset_of_lines_.size()); this->offset_of_lines_.clear(); this->line_is_ascii_.reserve(this->old_line_is_ascii_.size()); this->line_is_ascii_.clear(); // Offsets before replacement: do not adjust. - this->offset_of_lines_.insert( - this->offset_of_lines_.end(), this->old_offset_of_lines_.begin(), + this->offset_of_lines_.append( + this->old_offset_of_lines_.begin(), this->old_offset_of_lines_.begin() + range.start.line + 1); - this->line_is_ascii_.insert( - this->line_is_ascii_.end(), this->old_line_is_ascii_.begin(), + this->line_is_ascii_.append( + this->old_line_is_ascii_.begin(), this->old_line_is_ascii_.begin() + range.start.line); // Offsets within replacement: re-parse newlines. @@ -183,8 +179,7 @@ void LSP_Locator::replace_text(LSP_Range range, String8_View replacement_text, [&](Offset_Type offset) -> Offset_Type { return offset + net_bytes_added; }); - this->line_is_ascii_.insert(this->line_is_ascii_.end(), - this->old_line_is_ascii_.begin() + + this->line_is_ascii_.append(this->old_line_is_ascii_.begin() + narrow_cast(end_line) + 1, this->old_line_is_ascii_.end()); @@ -216,8 +211,7 @@ void LSP_Locator::cache_offsets_of_lines() { QLJS_ASSERT(this->line_is_ascii_.empty()); constexpr int estimated_bytes_per_line = 64; - std::size_t estimated_lines = - narrow_cast(this->input_.size() / estimated_bytes_per_line); + Vector_Size estimated_lines = this->input_.size() / estimated_bytes_per_line; this->offset_of_lines_.reserve(estimated_lines); this->line_is_ascii_.reserve(estimated_lines); @@ -275,10 +269,8 @@ LSP_Locator::Offset_Type LSP_Locator::offset(const Char8 *source) const { } LSP_Position LSP_Locator::position(int line_number, Offset_Type offset) const { - Offset_Type beginning_of_line_offset = - this->offset_of_lines_[narrow_cast(line_number)]; - bool line_is_ascii = - this->line_is_ascii_[narrow_cast(line_number)]; + Offset_Type beginning_of_line_offset = this->offset_of_lines_[line_number]; + bool line_is_ascii = this->line_is_ascii_[line_number]; int character; if (line_is_ascii) { diff --git a/src/quick-lint-js/lsp/lsp-location.h b/src/quick-lint-js/lsp/lsp-location.h index 63616c4784..96dcdd7c53 100644 --- a/src/quick-lint-js/lsp/lsp-location.h +++ b/src/quick-lint-js/lsp/lsp-location.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -58,13 +59,17 @@ class LSP_Locator { LSP_Position position(int line_number, Offset_Type offset) const; Padded_String_View input_; - std::vector offset_of_lines_; - std::vector line_is_ascii_; + Vector offset_of_lines_{"LSP_Locator::offset_of_lines_", + new_delete_resource()}; + Vector line_is_ascii_{"LSP_Locator::line_is_ascii_", + new_delete_resource()}; // old_offset_of_lines_ and old_line_is_ascii_ are used for double buffering // of offset_of_lines_ and line_is_ascii_. This reduces allocations. - std::vector old_offset_of_lines_; - std::vector old_line_is_ascii_; + Vector old_offset_of_lines_{"LSP_Locator::old_offset_of_lines_", + new_delete_resource()}; + Vector old_line_is_ascii_{"LSP_Locator::old_line_is_ascii_", + new_delete_resource()}; }; } diff --git a/src/quick-lint-js/lsp/lsp-message-parser.h b/src/quick-lint-js/lsp/lsp-message-parser.h index 3a99302a8a..45eda29fe8 100644 --- a/src/quick-lint-js/lsp/lsp-message-parser.h +++ b/src/quick-lint-js/lsp/lsp-message-parser.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -37,7 +38,8 @@ class LSP_Message_Parser_Base { static bool header_is(String8_View header_name, String8_View expected_header_name); - std::vector buffer_; + Vector buffer_{"LSP_Message_Parser_Base::buffer_", + new_delete_resource()}; // If !pending_message_content_length_.has_value(), buffer_ contains message // headers (and possibly message content and other messages afterwards). @@ -63,8 +65,7 @@ template class LSP_Message_Parser : private LSP_Message_Parser_Base { public: void append(String8_View data) { - this->buffer_.insert(this->buffer_.end(), data.data(), - data.data() + data.size()); + this->buffer_ += data; this->parse(); } diff --git a/src/quick-lint-js/lsp/outgoing-json-rpc-message-queue.h b/src/quick-lint-js/lsp/outgoing-json-rpc-message-queue.h index 2c81c536cc..a147f9bc29 100644 --- a/src/quick-lint-js/lsp/outgoing-json-rpc-message-queue.h +++ b/src/quick-lint-js/lsp/outgoing-json-rpc-message-queue.h @@ -8,6 +8,7 @@ #else #include +#include #include namespace quick_lint_js { @@ -30,7 +31,8 @@ class Outgoing_JSON_RPC_Message_Queue { void send(LSP_Endpoint_Remote&); private: - std::vector messages_; + Vector messages_{"Outgoing_JSON_RPC_Message_Queue::messages_", + new_delete_resource()}; }; } From eaf6cf12c89ab1e285cbd6aa2a4ca88838de5bfa Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Mon, 6 Nov 2023 22:59:26 -0500 Subject: [PATCH 107/117] refactor(configuration): prefer Vector over std::vector Reduce our use of std::vector to reduce binary bloat: https://github.com/quick-lint/quick-lint-js/issues/689 --- src/quick-lint-js/configuration/configuration-loader.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/quick-lint-js/configuration/configuration-loader.h b/src/quick-lint-js/configuration/configuration-loader.h index 0f403e79f8..f26c04107e 100644 --- a/src/quick-lint-js/configuration/configuration-loader.h +++ b/src/quick-lint-js/configuration/configuration-loader.h @@ -11,9 +11,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -189,8 +191,10 @@ class Configuration_Loader { // Value: cached parsed configuration Hash_Map loaded_config_files_; - std::vector watched_config_paths_; - std::vector watched_input_paths_; + Vector watched_config_paths_{ + "Configuration_Loader::watched_config_paths_", new_delete_resource()}; + Vector watched_input_paths_{ + "Configuration_Loader::watched_input_paths_", new_delete_resource()}; }; } From 1d4ce4575000af5f867e74b5e976310ae9a452a4 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Mon, 6 Nov 2023 22:59:26 -0500 Subject: [PATCH 108/117] refactor(configuration): rename string_allocator -> allocator * Rename Configuration::string_allocator_ to Configuration::allocator_ in preparation for using it for more than just strings. * Move Configuration::allocator_ above other member variables in preparation for using it for other member variables. --- src/quick-lint-js/configuration/configuration.cpp | 4 ++-- src/quick-lint-js/configuration/configuration.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/quick-lint-js/configuration/configuration.cpp b/src/quick-lint-js/configuration/configuration.cpp index 6f3422b87f..4f41f163ca 100644 --- a/src/quick-lint-js/configuration/configuration.cpp +++ b/src/quick-lint-js/configuration/configuration.cpp @@ -145,7 +145,7 @@ void Configuration::reset() { enabled = true; } this->literally_anything_global_group_enabled_ = false; - this->string_allocator_.release(); + this->allocator_.release(); } bool Configuration::load_global_groups_from_json( @@ -306,7 +306,7 @@ String8_View Configuration::save_string(std::string_view s) { String8_View s8 = to_string8_view(s); // TODO(strager): Use Linked_Bump_Allocator::new_objects_copy. Span out = - string_allocator_.allocate_uninitialized_span(s8.size()); + this->allocator_.allocate_uninitialized_span(s8.size()); std::uninitialized_copy(s8.begin(), s8.end(), out.data()); return String8_View(out.data(), narrow_cast(out.size())); } diff --git a/src/quick-lint-js/configuration/configuration.h b/src/quick-lint-js/configuration/configuration.h index f10733b96b..25c36a2443 100644 --- a/src/quick-lint-js/configuration/configuration.h +++ b/src/quick-lint-js/configuration/configuration.h @@ -43,12 +43,12 @@ class Configuration { void report_json_error(Padded_String_View json, Diag_Reporter*); + Monotonic_Allocator allocator_{"Configuration::allocator_"}; Global_Declared_Variable_Set globals_; std::vector globals_to_remove_; bool did_add_globals_from_groups_ = false; std::array enabled_global_groups_; bool literally_anything_global_group_enabled_ = false; - Monotonic_Allocator string_allocator_{"configuration::string_allocator_"}; String8_View save_string(std::string_view s); }; From 00af184b7f5c72d9a1b8cb4d522e8a1f0fbea426 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Mon, 6 Nov 2023 22:59:26 -0500 Subject: [PATCH 109/117] refactor(configuration): avoid string copy remove_global_variable makes a copy of the input string. All callers already either make copies in this->allocator_ or assume that the string must live long anyway. Remove the unnecessary copy. --- src/quick-lint-js/configuration/configuration.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/quick-lint-js/configuration/configuration.h b/src/quick-lint-js/configuration/configuration.h index 25c36a2443..830a3b0da0 100644 --- a/src/quick-lint-js/configuration/configuration.h +++ b/src/quick-lint-js/configuration/configuration.h @@ -27,6 +27,10 @@ class Configuration { bool add_global_group(String8_View group_name); void add_global_variable(Global_Declared_Variable); + + // For testing and internal use only. + // + // name must live as long as this Configuration object. void remove_global_variable(String8_View name); void load_from_json(Padded_String_View, Diag_Reporter*); @@ -45,7 +49,7 @@ class Configuration { Monotonic_Allocator allocator_{"Configuration::allocator_"}; Global_Declared_Variable_Set globals_; - std::vector globals_to_remove_; + std::vector globals_to_remove_; bool did_add_globals_from_groups_ = false; std::array enabled_global_groups_; bool literally_anything_global_group_enabled_ = false; From a79dcc5e63aeeb5a115902d55ebaaf9cf6a74c90 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Mon, 6 Nov 2023 22:59:26 -0500 Subject: [PATCH 110/117] refactor(container): lazily-load Vector_Instrumentation Some global objects, such as Configuration objects in tests, want to use Vector. However, they cannot use Vector because, in instrumented builds, Instrumented_Vector<>'s constructor appends data to Vector_Instrumentation and the initialization order is not guaranteed (thus Vector_Instrumentation could be initialized *after* the Instrumented_Vector<>.) Fix the initialization order problem by lazily-loading the Vector_Instrumentation singleton. Deinitialization order is still a problem and will be fixed in a future commit. --- .../container/vector-profiler.cpp | 7 +++-- src/quick-lint-js/container/vector-profiler.h | 4 +-- src/quick-lint-js/debug/debug-server.cpp | 2 +- test/test-debug-server.cpp | 4 +-- test/test-vector-profiler.cpp | 26 +++++++++---------- 5 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/quick-lint-js/container/vector-profiler.cpp b/src/quick-lint-js/container/vector-profiler.cpp index fcd319a586..71437b8dba 100644 --- a/src/quick-lint-js/container/vector-profiler.cpp +++ b/src/quick-lint-js/container/vector-profiler.cpp @@ -23,7 +23,10 @@ QLJS_WARNING_IGNORE_MSVC(4996) // Function or variable may be unsafe. namespace quick_lint_js { #if QLJS_FEATURE_VECTOR_PROFILING -Vector_Instrumentation Vector_Instrumentation::instance; +Vector_Instrumentation &Vector_Instrumentation::instance() { + static Vector_Instrumentation instrumentation; + return instrumentation; +} #endif void Vector_Instrumentation::clear() { this->entries_.lock()->clear(); } @@ -68,7 +71,7 @@ void Vector_Instrumentation::register_dump_on_exit_if_requested() { (void)File_Output_Stream::get_stderr(); std::atexit([]() -> void { - auto entries = instance.entries(); + auto entries = instance().entries(); Output_Stream &out = *File_Output_Stream::get_stderr(); { diff --git a/src/quick-lint-js/container/vector-profiler.h b/src/quick-lint-js/container/vector-profiler.h index 87d53699e2..c7c53684e8 100644 --- a/src/quick-lint-js/container/vector-profiler.h +++ b/src/quick-lint-js/container/vector-profiler.h @@ -52,7 +52,7 @@ class Vector_Instrumentation { }; #if QLJS_FEATURE_VECTOR_PROFILING - static Vector_Instrumentation instance; + static Vector_Instrumentation &instance(); #endif void clear(); @@ -366,7 +366,7 @@ class Instrumented_Vector { private: QLJS_FORCE_INLINE void add_instrumentation_entry( Vector_Instrumentation::Event event) { - Vector_Instrumentation::instance.add_entry( + Vector_Instrumentation::instance().add_entry( /*object_id=*/reinterpret_cast(this), /*owner=*/this->debug_owner_, /*event=*/event, diff --git a/src/quick-lint-js/debug/debug-server.cpp b/src/quick-lint-js/debug/debug-server.cpp index 21131181ba..45b0523186 100644 --- a/src/quick-lint-js/debug/debug-server.cpp +++ b/src/quick-lint-js/debug/debug-server.cpp @@ -356,7 +356,7 @@ void Debug_Server::wakeup_pipe_callback(::mg_connection *c, int ev, void *) { this->need_publish_vector_profile_.store(false); this->max_size_histogram_.add_entries( - Vector_Instrumentation::instance.take_entries()); + Vector_Instrumentation::instance().take_entries()); Trace_Writer *tw = Trace_Flusher::instance()->trace_writer_for_current_thread(); diff --git a/test/test-debug-server.cpp b/test/test-debug-server.cpp index 7ffbd49f59..518082508c 100644 --- a/test/test-debug-server.cpp +++ b/test/test-debug-server.cpp @@ -164,7 +164,7 @@ TEST_F(Test_Debug_Server, two_servers_listening_on_same_port_fails) { #if QLJS_FEATURE_VECTOR_PROFILING TEST_F(Test_Debug_Server, web_socket_publishes_vector_profile_stats_on_connect) { - Vector_Instrumentation::instance.clear(); + Vector_Instrumentation::instance().clear(); { Instrumented_Vector> v("debug server test vector", {}); ASSERT_EQ(v.size(), 0); @@ -222,7 +222,7 @@ TEST_F(Test_Debug_Server, } TEST_F(Test_Debug_Server, vector_profile_probe_publishes_stats) { - Vector_Instrumentation::instance.clear(); + Vector_Instrumentation::instance().clear(); bool received_vector_profile_entry = false; auto on_trace_event = diff --git a/test/test-vector-profiler.cpp b/test/test-vector-profiler.cpp index c35ecfe705..d4b4327d5e 100644 --- a/test/test-vector-profiler.cpp +++ b/test/test-vector-profiler.cpp @@ -40,7 +40,7 @@ using Test_Vector = Instrumented_Vector>; class Test_Instrumented_Vector : public ::testing::Test { public: - void SetUp() override { Vector_Instrumentation::instance.clear(); } + void SetUp() override { Vector_Instrumentation::instance().clear(); } }; TEST_F(Test_Instrumented_Vector, @@ -53,7 +53,7 @@ TEST_F(Test_Instrumented_Vector, } EXPECT_THAT( - Vector_Instrumentation::instance.take_entries(), + Vector_Instrumentation::instance().take_entries(), ElementsAre( AllOf(FIELD_EQ(Vector_Instrumentation::Entry, object_id, v_object_id), FIELD_EQ(Vector_Instrumentation::Entry, owner, owner), @@ -74,7 +74,7 @@ TEST_F(Test_Instrumented_Vector, creating_vector_from_range_adds_entry) { std::uintptr_t v_object_id = reinterpret_cast(&v); EXPECT_THAT( - Vector_Instrumentation::instance.take_entries(), + Vector_Instrumentation::instance().take_entries(), ElementsAreArray({ AllOf(FIELD_EQ(Vector_Instrumentation::Entry, object_id, v_object_id), FIELD_EQ(Vector_Instrumentation::Entry, owner, owner), @@ -87,7 +87,7 @@ TEST_F(Test_Instrumented_Vector, creating_vector_from_range_adds_entry) { TEST_F(Test_Instrumented_Vector, append_to_vector_adds_entries) { Test_Vector v("test vector", {}); - Vector_Instrumentation::instance.clear(); + Vector_Instrumentation::instance().clear(); v.emplace_back(100); v.emplace_back(200); @@ -95,7 +95,7 @@ TEST_F(Test_Instrumented_Vector, append_to_vector_adds_entries) { v.emplace_back(400); EXPECT_THAT( - Vector_Instrumentation::instance.take_entries(), + Vector_Instrumentation::instance().take_entries(), ElementsAre(AllOf(FIELD_EQ(Vector_Instrumentation::Entry, event, Vector_Instrumentation::Event::append), FIELD_EQ(Vector_Instrumentation::Entry, size, 1)), @@ -114,11 +114,11 @@ TEST_F(Test_Instrumented_Vector, clearing_vector_adds_entry) { Test_Vector v("test vector", {}); v.emplace_back(100); v.emplace_back(200); - Vector_Instrumentation::instance.clear(); + Vector_Instrumentation::instance().clear(); v.clear(); - EXPECT_THAT(Vector_Instrumentation::instance.take_entries(), + EXPECT_THAT(Vector_Instrumentation::instance().take_entries(), ElementsAreArray({ AllOf(FIELD_EQ(Vector_Instrumentation::Entry, event, Vector_Instrumentation::Event::clear), @@ -132,14 +132,14 @@ TEST_F(Test_Instrumented_Vector, moving_vector_with_new_owner_adds_entries) { std::uintptr_t v_1_object_id = reinterpret_cast(&v_1); v_1.emplace_back(100); v_1.emplace_back(200); - Vector_Instrumentation::instance.clear(); + Vector_Instrumentation::instance().clear(); const char *v_2_owner = "v2"; Test_Vector v_2(v_2_owner, std::move(v_1)); std::uintptr_t v_2_object_id = reinterpret_cast(&v_2); EXPECT_THAT( - Vector_Instrumentation::instance.take_entries(), + Vector_Instrumentation::instance().take_entries(), ElementsAre( AllOf( FIELD_EQ(Vector_Instrumentation::Entry, owner, v_2_owner), @@ -161,13 +161,13 @@ TEST_F(Test_Instrumented_Vector, moving_vector_with_no_owner_adds_entries) { std::uintptr_t v_1_object_id = reinterpret_cast(&v_1); v_1.emplace_back(100); v_1.emplace_back(200); - Vector_Instrumentation::instance.clear(); + Vector_Instrumentation::instance().clear(); Test_Vector v_2(std::move(v_1)); std::uintptr_t v_2_object_id = reinterpret_cast(&v_2); EXPECT_THAT( - Vector_Instrumentation::instance.take_entries(), + Vector_Instrumentation::instance().take_entries(), ElementsAre( AllOf( FIELD_EQ(Vector_Instrumentation::Entry, owner, v_1_owner), @@ -193,12 +193,12 @@ TEST_F(Test_Instrumented_Vector, move_assigning_vector_adds_entries) { v_2.emplace_back(200); v_2.emplace_back(300); std::uintptr_t v_2_object_id = reinterpret_cast(&v_2); - Vector_Instrumentation::instance.clear(); + Vector_Instrumentation::instance().clear(); v_1 = std::move(v_2); EXPECT_THAT( - Vector_Instrumentation::instance.take_entries(), + Vector_Instrumentation::instance().take_entries(), ElementsAre( AllOf( FIELD_EQ(Vector_Instrumentation::Entry, owner, v_1_owner), From 3ed1c3f11ae0b704b0524d6ac318a6bcf1275ef9 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Mon, 6 Nov 2023 22:59:26 -0500 Subject: [PATCH 111/117] fix(container): fix possible init order issues with Vector_Instrumentation See inline comment in Vector_Instrumentation::instance. --- .../container/vector-profiler.cpp | 8 ++++++-- src/quick-lint-js/debug/debug-server.cpp | 2 +- src/quick-lint-js/debug/debug-server.h | 2 +- src/quick-lint-js/logging/logger.cpp | 5 +---- src/quick-lint-js/util/instance-tracker.h | 18 ++++++++---------- 5 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/quick-lint-js/container/vector-profiler.cpp b/src/quick-lint-js/container/vector-profiler.cpp index 71437b8dba..490637cb9d 100644 --- a/src/quick-lint-js/container/vector-profiler.cpp +++ b/src/quick-lint-js/container/vector-profiler.cpp @@ -24,8 +24,12 @@ QLJS_WARNING_IGNORE_MSVC(4996) // Function or variable may be unsafe. namespace quick_lint_js { #if QLJS_FEATURE_VECTOR_PROFILING Vector_Instrumentation &Vector_Instrumentation::instance() { - static Vector_Instrumentation instrumentation; - return instrumentation; + // NOTE(strager): We intentionally leak the Vector_Instrumentation. We want to + // avoid deinitialization order issues, so defer deinitialization forever. + // Also, cleaning up the memory is wasteful and is unnecessary for modern leak + // checkers anyway. + static Vector_Instrumentation *instrumentation = new Vector_Instrumentation(); + return *instrumentation; } #endif diff --git a/src/quick-lint-js/debug/debug-server.cpp b/src/quick-lint-js/debug/debug-server.cpp index 45b0523186..b8734b770e 100644 --- a/src/quick-lint-js/debug/debug-server.cpp +++ b/src/quick-lint-js/debug/debug-server.cpp @@ -110,7 +110,7 @@ std::shared_ptr Debug_Server::create() { return instance; } -Raw_Vector> Debug_Server::instances() { +Vector> Debug_Server::instances() { return Instance_Tracker::instances(); } diff --git a/src/quick-lint-js/debug/debug-server.h b/src/quick-lint-js/debug/debug-server.h index a35cb3d233..b8186c8502 100644 --- a/src/quick-lint-js/debug/debug-server.h +++ b/src/quick-lint-js/debug/debug-server.h @@ -35,7 +35,7 @@ class Debug_Server { public: static std::shared_ptr create(); - static Raw_Vector> instances(); + static Vector> instances(); explicit Debug_Server(Create_Tag); diff --git a/src/quick-lint-js/logging/logger.cpp b/src/quick-lint-js/logging/logger.cpp index 0ee1c56b65..584af20506 100644 --- a/src/quick-lint-js/logging/logger.cpp +++ b/src/quick-lint-js/logging/logger.cpp @@ -32,10 +32,7 @@ QLJS_WARNING_IGNORE_GCC("-Wsuggest-attribute=format") namespace quick_lint_js { namespace { struct Global_Loggers { - // NOTE(strager): We use Raw_Vector here instead of Vector. Otherwise, in - // vector instrumented builds, loggers might be initialized before the vector - // profiler is initialized, causing use-before-init issues. - Raw_Vector loggers{new_delete_resource()}; + Vector loggers{"Global_Loggers::loggers", new_delete_resource()}; bool initialized = false; void initialize_if_needed() { diff --git a/src/quick-lint-js/util/instance-tracker.h b/src/quick-lint-js/util/instance-tracker.h index 5a526db6eb..74c1bf9d7a 100644 --- a/src/quick-lint-js/util/instance-tracker.h +++ b/src/quick-lint-js/util/instance-tracker.h @@ -18,16 +18,17 @@ template class Instance_Tracker { public: static void track(std::shared_ptr instance) { - Lock_Ptr>> weak_instances = + Lock_Ptr>> weak_instances = weak_instances_.lock(); sanitize_instances(weak_instances); weak_instances->push_back(std::move(instance)); } - static Raw_Vector> instances() { - Raw_Vector> instances(new_delete_resource()); + static Vector> instances() { + Vector> instances("instances", + new_delete_resource()); { - Lock_Ptr>> weak_instances = + Lock_Ptr>> weak_instances = weak_instances_.lock(); sanitize_instances(weak_instances); instances.reserve(weak_instances->size()); @@ -45,7 +46,7 @@ class Instance_Tracker { private: static void sanitize_instances( - Lock_Ptr>>& weak_instances) { + Lock_Ptr>>& weak_instances) { erase_if(*weak_instances, [](const std::weak_ptr& weak_instance) { return weak_instance.expired(); }); @@ -55,11 +56,8 @@ class Instance_Tracker { sanitize_instances(weak_instances_.lock()); } - // NOTE(strager): We use Raw_Vector here instead of Vector. Otherwise, in - // vector instrumented builds, weak_instances_ might be initialized before the - // vector profiler is initialized, causing use-before-init issues. - static inline Synchronized>> - weak_instances_{new_delete_resource()}; + static inline Synchronized>> weak_instances_{ + "weak_instances_", new_delete_resource()}; }; } From a413f4b4f3d591c051379eaf94b7ca688442edc8 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Mon, 6 Nov 2023 22:59:26 -0500 Subject: [PATCH 112/117] refactor(fe): remove stale TODO comment --- src/quick-lint-js/fe/variable-analyzer.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/quick-lint-js/fe/variable-analyzer.cpp b/src/quick-lint-js/fe/variable-analyzer.cpp index 5a47417d78..934e7b912a 100644 --- a/src/quick-lint-js/fe/variable-analyzer.cpp +++ b/src/quick-lint-js/fe/variable-analyzer.cpp @@ -466,9 +466,6 @@ void Variable_Analyzer::visit_variable_namespace_use(Identifier) { } void Variable_Analyzer::visit_variable_type_predicate_use(Identifier name) { - // TODO(#690) - static_cast(name); - QLJS_ASSERT(!this->scopes_.empty()); Scope ¤t_scope = this->current_scope(); Declared_Variable *var = current_scope.declared_variables.find_runtime(name); From 260c3c3c506c0c4f2c5d7980e536060bbb1b82b4 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Mon, 6 Nov 2023 22:59:26 -0500 Subject: [PATCH 113/117] refactor(fe): add visit_variable_assertion_signature use Prepare for parsing TypeScript assertion signatures by adding a new visit type. --- src/quick-lint-js/fe/buffering-visitor.cpp | 8 +++ src/quick-lint-js/fe/buffering-visitor.h | 2 + src/quick-lint-js/fe/debug-parse-visitor.h | 7 +++ src/quick-lint-js/fe/multi-parse-visitor.h | 5 ++ src/quick-lint-js/fe/null-visitor.h | 1 + src/quick-lint-js/fe/parse-visitor.h | 1 + src/quick-lint-js/fe/variable-analyzer.cpp | 6 ++ src/quick-lint-js/fe/variable-analyzer.h | 1 + test/quick-lint-js/spy-visitor.h | 5 ++ test/test-buffering-visitor.cpp | 66 +++++++++++----------- 10 files changed, 70 insertions(+), 32 deletions(-) diff --git a/src/quick-lint-js/fe/buffering-visitor.cpp b/src/quick-lint-js/fe/buffering-visitor.cpp index a0c24954eb..9bf5ac8aa6 100644 --- a/src/quick-lint-js/fe/buffering-visitor.cpp +++ b/src/quick-lint-js/fe/buffering-visitor.cpp @@ -121,6 +121,9 @@ void Buffering_Visitor::copy_into(Parse_Visitor_Base &target) const { case Visit_Kind::variable_assignment: target.visit_variable_assignment(v.name); break; + case Visit_Kind::variable_assertion_signature_use: + target.visit_variable_assertion_signature_use(v.name); + break; case Visit_Kind::variable_delete_use: target.visit_variable_delete_use(v.name, v.extra_span); break; @@ -298,6 +301,11 @@ void Buffering_Visitor::visit_variable_declaration( flags); } +void Buffering_Visitor::visit_variable_assertion_signature_use( + Identifier name) { + this->add(name, Visit_Kind::variable_assertion_signature_use); +} + void Buffering_Visitor::visit_variable_delete_use( Identifier name, Source_Code_Span delete_keyword) { this->visits_.emplace_back(Visit_Kind::variable_delete_use, name, diff --git a/src/quick-lint-js/fe/buffering-visitor.h b/src/quick-lint-js/fe/buffering-visitor.h index 96fb84e5c9..0e0b43a58e 100644 --- a/src/quick-lint-js/fe/buffering-visitor.h +++ b/src/quick-lint-js/fe/buffering-visitor.h @@ -69,6 +69,7 @@ class Buffering_Visitor final : public Parse_Visitor_Base { void visit_variable_assignment(Identifier name) override; void visit_variable_declaration(Identifier name, Variable_Kind kind, Variable_Declaration_Flags flags) override; + void visit_variable_assertion_signature_use(Identifier name) override; void visit_variable_delete_use(Identifier name, Source_Code_Span delete_keyword) override; void visit_variable_export_use(Identifier name) override; @@ -114,6 +115,7 @@ class Buffering_Visitor final : public Parse_Visitor_Base { keyword_variable_use, property_declaration_with_name, property_declaration_without_name, + variable_assertion_signature_use, variable_assignment, variable_delete_use, variable_export_use, diff --git a/src/quick-lint-js/fe/debug-parse-visitor.h b/src/quick-lint-js/fe/debug-parse-visitor.h index 69130feeca..c886308957 100644 --- a/src/quick-lint-js/fe/debug-parse-visitor.h +++ b/src/quick-lint-js/fe/debug-parse-visitor.h @@ -204,6 +204,13 @@ class Debug_Parse_Visitor final : public Parse_Visitor_Base { this->output_->flush(); } + void visit_variable_assertion_signature_use(Identifier name) override { + this->output_->append_copy(u8"variable assertion signature use: "_sv); + this->output_->append_copy(name.normalized_name()); + this->output_->append_copy(u8'\n'); + this->output_->flush(); + } + void visit_variable_delete_use( Identifier name, [[maybe_unused]] Source_Code_Span delete_keyword) override { diff --git a/src/quick-lint-js/fe/multi-parse-visitor.h b/src/quick-lint-js/fe/multi-parse-visitor.h index 4545b23f25..18df922ffe 100644 --- a/src/quick-lint-js/fe/multi-parse-visitor.h +++ b/src/quick-lint-js/fe/multi-parse-visitor.h @@ -185,6 +185,11 @@ class Multi_Parse_Visitor final : public Parse_Visitor_Base { this->visitor_2_->visit_variable_declaration(name, kind, flags); } + void visit_variable_assertion_signature_use(Identifier name) override { + this->visitor_1_->visit_variable_assertion_signature_use(name); + this->visitor_2_->visit_variable_assertion_signature_use(name); + } + void visit_variable_delete_use(Identifier name, Source_Code_Span delete_keyword) override { this->visitor_1_->visit_variable_delete_use(name, delete_keyword); diff --git a/src/quick-lint-js/fe/null-visitor.h b/src/quick-lint-js/fe/null-visitor.h index 61b416afb2..297c61e667 100644 --- a/src/quick-lint-js/fe/null-visitor.h +++ b/src/quick-lint-js/fe/null-visitor.h @@ -46,6 +46,7 @@ class Null_Visitor final : public Parse_Visitor_Base { void visit_variable_assignment(Identifier) override {} void visit_variable_declaration(Identifier, Variable_Kind, Variable_Declaration_Flags) override {} + void visit_variable_assertion_signature_use(Identifier) override {} void visit_variable_delete_use(Identifier, Source_Code_Span) override {} void visit_variable_export_use(Identifier) override {} void visit_variable_namespace_use(Identifier) override {} diff --git a/src/quick-lint-js/fe/parse-visitor.h b/src/quick-lint-js/fe/parse-visitor.h index 101315ca71..cdcc959b2b 100644 --- a/src/quick-lint-js/fe/parse-visitor.h +++ b/src/quick-lint-js/fe/parse-visitor.h @@ -57,6 +57,7 @@ class Parse_Visitor_Base { virtual void visit_variable_declaration(Identifier name, Variable_Kind kind, Variable_Declaration_Flags flags) = 0; virtual void visit_variable_assignment(Identifier name) = 0; + virtual void visit_variable_assertion_signature_use(Identifier name) = 0; virtual void visit_variable_delete_use(Identifier name, Source_Code_Span delete_keyword) = 0; virtual void visit_variable_export_use(Identifier name) = 0; diff --git a/src/quick-lint-js/fe/variable-analyzer.cpp b/src/quick-lint-js/fe/variable-analyzer.cpp index 934e7b912a..479b7a71db 100644 --- a/src/quick-lint-js/fe/variable-analyzer.cpp +++ b/src/quick-lint-js/fe/variable-analyzer.cpp @@ -431,6 +431,12 @@ void Variable_Analyzer::visit_variable_assignment(Identifier name) { } } +void Variable_Analyzer::visit_variable_assertion_signature_use([ + [maybe_unused]] Identifier name) { + // TODO(#690) + QLJS_UNIMPLEMENTED(); +} + void Variable_Analyzer::visit_variable_delete_use( Identifier name, Source_Code_Span delete_keyword) { QLJS_ASSERT(delete_keyword.end() <= name.span().begin()); diff --git a/src/quick-lint-js/fe/variable-analyzer.h b/src/quick-lint-js/fe/variable-analyzer.h index 7d773eb5e1..2f0bda1e94 100644 --- a/src/quick-lint-js/fe/variable-analyzer.h +++ b/src/quick-lint-js/fe/variable-analyzer.h @@ -80,6 +80,7 @@ class Variable_Analyzer final : public Parse_Visitor_Base { void visit_variable_declaration(Identifier name, Variable_Kind kind, Variable_Declaration_Flags flags) override; void visit_variable_assignment(Identifier name) override; + void visit_variable_assertion_signature_use(Identifier name) override; void visit_variable_delete_use(Identifier name, Source_Code_Span delete_keyword) override; void visit_variable_export_use(Identifier name) override; diff --git a/test/quick-lint-js/spy-visitor.h b/test/quick-lint-js/spy-visitor.h index 0fc5c09de3..a24aaf1baf 100644 --- a/test/quick-lint-js/spy-visitor.h +++ b/test/quick-lint-js/spy-visitor.h @@ -393,6 +393,11 @@ struct Parse_Visit_Collector : public Parse_Visitor_Base { std::vector variable_declarations; + void visit_variable_assertion_signature_use(Identifier name) override { + this->variable_uses.emplace_back(name.normalized_name()); + this->visits.emplace_back("visit_variable_assertion_signature_use"); + } + void visit_variable_delete_use( Identifier name, [[maybe_unused]] Source_Code_Span delete_keyword) override { diff --git a/test/test-buffering-visitor.cpp b/test/test-buffering-visitor.cpp index 9fee4882f7..94cc628035 100644 --- a/test/test-buffering-visitor.cpp +++ b/test/test-buffering-visitor.cpp @@ -52,6 +52,7 @@ TEST(Test_Buffering_Visitor, buffers_all_visits) { v.visit_variable_declaration( identifier_of(variable_name), Variable_Kind::_var, Variable_Declaration_Flags::initialized_with_equals); + v.visit_variable_assertion_signature_use(identifier_of(variable_name)); v.visit_variable_delete_use(identifier_of(variable_name), span_of(delete_keyword)); v.visit_variable_export_use(identifier_of(variable_name)); @@ -63,38 +64,39 @@ TEST(Test_Buffering_Visitor, buffers_all_visits) { Spy_Visitor spy; v.move_into(spy); EXPECT_THAT(spy.visits, ElementsAreArray({ - "visit_end_of_module", // - "visit_enter_block_scope", // - "visit_enter_with_scope", // - "visit_enter_class_scope", // - "visit_enter_class_scope_body", // - "visit_enter_class_scope_body", // - "visit_enter_enum_scope", // - "visit_enter_for_scope", // - "visit_enter_named_function_scope", // - "visit_enter_function_scope", // - "visit_enter_function_scope_body", // - "visit_enter_index_signature_scope", // - "visit_enter_interface_scope", // - "visit_exit_block_scope", // - "visit_exit_with_scope", // - "visit_exit_class_scope", // - "visit_exit_enum_scope", // - "visit_exit_for_scope", // - "visit_exit_function_scope", // - "visit_exit_index_signature_scope", // - "visit_exit_interface_scope", // - "visit_keyword_variable_use", // - "visit_property_declaration", // - "visit_property_declaration", // - "visit_variable_assignment", // - "visit_variable_declaration", // - "visit_variable_delete_use", // - "visit_variable_export_use", // - "visit_variable_type_predicate_use", // - "visit_variable_type_use", // - "visit_variable_typeof_use", // - "visit_variable_use", // + "visit_end_of_module", // + "visit_enter_block_scope", // + "visit_enter_with_scope", // + "visit_enter_class_scope", // + "visit_enter_class_scope_body", // + "visit_enter_class_scope_body", // + "visit_enter_enum_scope", // + "visit_enter_for_scope", // + "visit_enter_named_function_scope", // + "visit_enter_function_scope", // + "visit_enter_function_scope_body", // + "visit_enter_index_signature_scope", // + "visit_enter_interface_scope", // + "visit_exit_block_scope", // + "visit_exit_with_scope", // + "visit_exit_class_scope", // + "visit_exit_enum_scope", // + "visit_exit_for_scope", // + "visit_exit_function_scope", // + "visit_exit_index_signature_scope", // + "visit_exit_interface_scope", // + "visit_keyword_variable_use", // + "visit_property_declaration", // + "visit_property_declaration", // + "visit_variable_assignment", // + "visit_variable_declaration", // + "visit_variable_assertion_signature_use", // + "visit_variable_delete_use", // + "visit_variable_export_use", // + "visit_variable_type_predicate_use", // + "visit_variable_type_use", // + "visit_variable_typeof_use", // + "visit_variable_use", // })); } From 274472b93cf3fb2a553689dc403f5ae3daa633c6 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Mon, 6 Nov 2023 22:59:26 -0500 Subject: [PATCH 114/117] fix(typescript): parse types named 'await', 'implements', etc. Various contextual keywords are incorrectly not allowed in types for whatever reason. Allow them. --- docs/CHANGELOG.md | 7 +++++++ src/quick-lint-js/fe/parse-type.cpp | 10 ++++++++++ test/test-parse-typescript-type.cpp | 8 ++++---- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 81879ea155..309382d02f 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -15,6 +15,13 @@ Semantic Versioning. * `case await x:` no longer treats `:` as if it was a type annotation colon in an arrow function parameter list. +### Fixed + +* TypeScript support (still experimental): + * Types named `await`, `implements`, `interface`, `let`, `package`, `private`, + `protected`, `public`, `static`, and `yield` are now recognized in type + signatures. + ## 2.18.0 (2023-11-03) [Downloads](https://c.quick-lint-js.com/releases/2.18.0/) diff --git a/src/quick-lint-js/fe/parse-type.cpp b/src/quick-lint-js/fe/parse-type.cpp index 3c5d9fb56f..0efa1b9858 100644 --- a/src/quick-lint-js/fe/parse-type.cpp +++ b/src/quick-lint-js/fe/parse-type.cpp @@ -140,23 +140,33 @@ void Parser::parse_and_visit_typescript_type_expression( case Token_Type::kw_assert: case Token_Type::kw_asserts: case Token_Type::kw_async: + case Token_Type::kw_await: case Token_Type::kw_constructor: case Token_Type::kw_declare: case Token_Type::kw_from: case Token_Type::kw_get: case Token_Type::kw_global: + case Token_Type::kw_implements: + case Token_Type::kw_interface: case Token_Type::kw_intrinsic: case Token_Type::kw_is: + case Token_Type::kw_let: case Token_Type::kw_module: case Token_Type::kw_namespace: case Token_Type::kw_of: case Token_Type::kw_out: case Token_Type::kw_override: + case Token_Type::kw_package: + case Token_Type::kw_private: + case Token_Type::kw_protected: + case Token_Type::kw_public: case Token_Type::kw_readonly: case Token_Type::kw_require: case Token_Type::kw_satisfies: case Token_Type::kw_set: + case Token_Type::kw_static: case Token_Type::kw_type: + case Token_Type::kw_yield: case Token_Type::identifier: { Identifier name = this->peek().identifier_name(); bool had_dot = false; diff --git a/test/test-parse-typescript-type.cpp b/test/test-parse-typescript-type.cpp index 1869736fb2..da92d7a167 100644 --- a/test/test-parse-typescript-type.cpp +++ b/test/test-parse-typescript-type.cpp @@ -43,19 +43,19 @@ TEST_F(Test_Parse_TypeScript_Type, direct_type_reference) { TEST_F(Test_Parse_TypeScript_Type, direct_type_reference_with_keyword_name) { for (String8 keyword : - contextual_keywords - typescript_builtin_type_keywords - - typescript_special_type_keywords - typescript_type_only_keywords - + ((contextual_keywords - typescript_builtin_type_keywords - + typescript_special_type_keywords - typescript_type_only_keywords) | + strict_only_reserved_keywords | + Dirty_Set{u8"await", u8"yield"}) - Dirty_Set{ // NOTE(strager): keyof is omitted on purpose because of // ambiguities in the grammar: // https://github.com/microsoft/TypeScript/issues/49724 u8"keyof", - u8"let", // NOTE(strager): readonly is omitted on purpose because // TypeScript complains about it, even though there is no // ambiguity in this case. u8"readonly", - u8"static", // NOTE(strager): unique is omitted on purpose because of // ambiguities in the grammar. u8"unique", From 15b65abea73e4334241b8727fc31d55f7544692b Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Mon, 6 Nov 2023 22:59:26 -0500 Subject: [PATCH 115/117] refactor(fe): merge type predicate parsing into main type parsing function Type predicate parsing is performed when it's unnecessary, and is not performed when it would be nice (e.g. to provide better diagnostics). Move the type predicate parsing code into parse_and_visit_typescript_type_expression to give us more flexibility. --- src/quick-lint-js/fe/parse-type.cpp | 159 ++++++++++++++++++---------- src/quick-lint-js/fe/parse.h | 2 + 2 files changed, 105 insertions(+), 56 deletions(-) diff --git a/src/quick-lint-js/fe/parse-type.cpp b/src/quick-lint-js/fe/parse-type.cpp index 0efa1b9858..c70f991ad8 100644 --- a/src/quick-lint-js/fe/parse-type.cpp +++ b/src/quick-lint-js/fe/parse-type.cpp @@ -90,31 +90,68 @@ void Parser::parse_and_visit_typescript_type_expression( if (this->peek().type == Token_Type::kw_readonly) { // readonly Type[] // readonly [Type, Type] - readonly_keyword = this->peek().span(); + // readonly is Type + Lexer_Transaction transaction = this->lexer_.begin_transaction(); + Identifier readonly = this->peek().identifier_name(); this->skip(); + + if (parse_options.allow_type_predicate && + this->peek().type == Token_Type::kw_is) { + // readonly is Type + this->lexer_.roll_back_transaction(std::move(transaction)); + goto type_variable_or_namespace_or_type_predicate; + } + this->lexer_.commit_transaction(std::move(transaction)); + readonly_keyword = readonly.span(); } switch (this->peek().type) { case Token_Type::complete_template: + case Token_Type::kw_false: + case Token_Type::kw_null: + case Token_Type::kw_true: + case Token_Type::kw_void: + case Token_Type::number: + case Token_Type::string: + this->skip(); + break; + + // any + // any is Type case Token_Type::kw_any: case Token_Type::kw_bigint: case Token_Type::kw_boolean: - case Token_Type::kw_false: case Token_Type::kw_never: - case Token_Type::kw_null: case Token_Type::kw_number: case Token_Type::kw_object: case Token_Type::kw_string: case Token_Type::kw_symbol: - case Token_Type::kw_this: - case Token_Type::kw_true: case Token_Type::kw_undefined: - case Token_Type::kw_unknown: - case Token_Type::kw_void: - case Token_Type::number: - case Token_Type::string: + case Token_Type::kw_unknown: { + Lexer_Transaction transaction = this->lexer_.begin_transaction(); + this->skip(); + if (this->peek().type == Token_Type::kw_is) { + // param is Type + this->lexer_.roll_back_transaction(std::move(transaction)); + goto type_variable_or_namespace_or_type_predicate; + } + this->lexer_.commit_transaction(std::move(transaction)); + break; + } + + // this + // this is Type + case Token_Type::kw_this: { + Lexer_Transaction transaction = this->lexer_.begin_transaction(); this->skip(); + if (this->peek().type == Token_Type::kw_is) { + // this is Type + this->lexer_.roll_back_transaction(std::move(transaction)); + goto type_variable_or_namespace_or_type_predicate; + } + this->lexer_.commit_transaction(std::move(transaction)); break; + } // `template ${sometype}` case Token_Type::incomplete_template: @@ -134,6 +171,8 @@ void Parser::parse_and_visit_typescript_type_expression( // Type // ns.Type + // param is Type + type_variable_or_namespace_or_type_predicate: case Token_Type::kw_abstract: case Token_Type::kw_accessor: case Token_Type::kw_as: @@ -168,10 +207,24 @@ void Parser::parse_and_visit_typescript_type_expression( case Token_Type::kw_type: case Token_Type::kw_yield: case Token_Type::identifier: { + Token_Type name_type = this->peek().type; Identifier name = this->peek().identifier_name(); - bool had_dot = false; this->skip(); + if (this->peek().type == Token_Type::kw_is) { + // param is Type + // this is Type + this->skip(); + if (name_type != Token_Type::kw_this) { + // this is Type + v.visit_variable_type_predicate_use(name); + } + this->parse_and_visit_typescript_type_expression(v); + return; + } + + bool had_dot = false; while (this->peek().type == Token_Type::dot) { + // ns.Type had_dot = true; this->skip(); switch (this->peek().type) { @@ -215,6 +268,7 @@ void Parser::parse_and_visit_typescript_type_expression( // T extends infer U ? V : W // T extends infer U extends X ? V : W case Token_Type::kw_infer: { + Lexer_Transaction transaction = this->lexer_.begin_transaction(); Source_Code_Span infer_keyword_span = this->peek().span(); this->skip(); switch (this->peek().type) { @@ -232,7 +286,6 @@ void Parser::parse_and_visit_typescript_type_expression( case Token_Type::kw_global: case Token_Type::kw_infer: case Token_Type::kw_intrinsic: - case Token_Type::kw_is: case Token_Type::kw_keyof: case Token_Type::kw_module: case Token_Type::kw_namespace: @@ -248,10 +301,21 @@ void Parser::parse_and_visit_typescript_type_expression( case Token_Type::kw_unique: break; + // infer is // 'is' is the declared name. + // infer is Type // Type predicate where 'infer' is the parameter name. + case Token_Type::kw_is: + if (parse_options.allow_type_predicate) { + // infer is Type + this->lexer_.roll_back_transaction(std::move(transaction)); + goto type_variable_or_namespace_or_type_predicate; + } + break; + default: QLJS_PARSER_UNIMPLEMENTED(); break; } + this->lexer_.commit_transaction(std::move(transaction)); Identifier variable = this->peek().identifier_name(); this->skip(); @@ -288,13 +352,22 @@ void Parser::parse_and_visit_typescript_type_expression( } // unique - // unique.prop // unique symbol - case Token_Type::kw_unique: + // unique is Type + case Token_Type::kw_unique: { + Lexer_Transaction transaction = this->lexer_.begin_transaction(); this->skip(); + if (parse_options.allow_type_predicate && + this->peek().type == Token_Type::kw_is) { + // unique is Type + this->lexer_.roll_back_transaction(std::move(transaction)); + goto type_variable_or_namespace_or_type_predicate; + } + this->lexer_.commit_transaction(std::move(transaction)); QLJS_PARSER_UNIMPLEMENTED_IF_NOT_TOKEN(Token_Type::kw_symbol); this->skip(); break; + } // [A, B, C] case Token_Type::left_square: @@ -477,10 +550,21 @@ void Parser::parse_and_visit_typescript_type_expression( break; // keyof Type - case Token_Type::kw_keyof: + // keyof is Type + case Token_Type::kw_keyof: { + Lexer_Transaction transaction = this->lexer_.begin_transaction(); this->skip(); + if (parse_options.allow_type_predicate && + this->peek().type == Token_Type::kw_is) { + // keyof is Type + this->lexer_.roll_back_transaction(std::move(transaction)); + goto type_variable_or_namespace_or_type_predicate; + } + // keyof Type + this->lexer_.commit_transaction(std::move(transaction)); this->parse_and_visit_typescript_type_expression(v, parse_options); break; + } // import("module").Name case Token_Type::kw_import: { @@ -620,48 +704,11 @@ void Parser::parse_and_visit_typescript_colon_type_expression_or_type_predicate( void Parser::parse_and_visit_typescript_type_expression_or_type_predicate( Parse_Visitor_Base &v, bool allow_parenthesized_type) { - switch (this->peek().type) { - // param is Type - // Type - QLJS_CASE_CONTEXTUAL_KEYWORD: - QLJS_CASE_STRICT_ONLY_RESERVED_KEYWORD: - case Token_Type::identifier: - case Token_Type::kw_await: - case Token_Type::kw_this: - case Token_Type::kw_yield: { - Token_Type parameter_type = this->peek().type; - Identifier parameter_name = this->peek().identifier_name(); - Lexer_Transaction transaction = this->lexer_.begin_transaction(); - this->skip(); - if (this->peek().type == Token_Type::kw_is) { - // param is Type - this->lexer_.commit_transaction(std::move(transaction)); - this->skip(); - if (parameter_type != Token_Type::kw_this) { - v.visit_variable_type_predicate_use(parameter_name); - } - this->parse_and_visit_typescript_type_expression(v); - } else { - // Type - this->lexer_.roll_back_transaction(std::move(transaction)); - this->parse_and_visit_typescript_type_expression(v); - } - break; - } - - // {key: Value} - // typeof v - // (param, param) => ReturnType - // ((((param, param) => ReturnType))) - // // Only if allow_parenthesized_type: - // (typeexpr) - default: - this->parse_and_visit_typescript_type_expression( - v, TypeScript_Type_Parse_Options{ - .allow_parenthesized_type = allow_parenthesized_type, - }); - break; - } + this->parse_and_visit_typescript_type_expression( + v, TypeScript_Type_Parse_Options{ + .allow_parenthesized_type = allow_parenthesized_type, + .allow_type_predicate = true, + }); } void Parser::parse_and_visit_typescript_arrow_type_expression( diff --git a/src/quick-lint-js/fe/parse.h b/src/quick-lint-js/fe/parse.h index 2a70b300c6..7d83392d41 100644 --- a/src/quick-lint-js/fe/parse.h +++ b/src/quick-lint-js/fe/parse.h @@ -211,6 +211,8 @@ class Parser { std::optional type_being_declared = std::nullopt; bool parse_question_as_invalid = true; bool allow_parenthesized_type = true; + // If false, a type predicate is parsed but a diagnostic is reported. + bool allow_type_predicate = false; }; void parse_and_visit_typescript_colon_type_expression(Parse_Visitor_Base &v); From aaed13793699a42fe91b5f8a2fe374bcdb03477f Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Mon, 6 Nov 2023 22:59:26 -0500 Subject: [PATCH 116/117] refactor(fe): inline parse_..._type_expression_or_type_predicate helpers parse_and_visit_typescript_type_expression_or_type_predicate and parse_and_visit_colon_typescript_type_expression_or_type_predicate just translate arguments then forward to parse_and_visit_typescript_type_expression. This is no simpler than just calling parse_and_visit_typescript_type_expression, so make callers call the parse function directly. --- src/quick-lint-js/fe/parse-expression.cpp | 42 +++++++++++++++-------- src/quick-lint-js/fe/parse-statement.cpp | 7 ++-- src/quick-lint-js/fe/parse-type.cpp | 32 +++++++---------- src/quick-lint-js/fe/parse.h | 7 ++-- 4 files changed, 46 insertions(+), 42 deletions(-) diff --git a/src/quick-lint-js/fe/parse-expression.cpp b/src/quick-lint-js/fe/parse-expression.cpp index e35ebb5f2c..ef803e5bd7 100644 --- a/src/quick-lint-js/fe/parse-expression.cpp +++ b/src/quick-lint-js/fe/parse-expression.cpp @@ -889,9 +889,11 @@ Expression* Parser::parse_async_expression_only( Buffering_Visitor return_type_visits(&this->type_expression_memory_); if (this->peek().type == Token_Type::colon && this->options_.typescript) { // async (params): ReturnType => {} // TypeScript only. - this->parse_and_visit_typescript_colon_type_expression_or_type_predicate( - return_type_visits, - /*allow_parenthesized_type=*/false); + this->parse_and_visit_typescript_colon_type_expression( + return_type_visits, TypeScript_Type_Parse_Options{ + .allow_parenthesized_type = false, + .allow_type_predicate = true, + }); } bool is_arrow_function = this->peek().type == Token_Type::equal_greater; @@ -1028,9 +1030,11 @@ Expression* Parser::parse_async_expression_only( // code path). Buffering_Visitor return_type_visits(&this->type_expression_memory_); if (this->peek().type == Token_Type::colon) { - this->parse_and_visit_typescript_colon_type_expression_or_type_predicate( - return_type_visits, - /*allow_parenthesized_type=*/false); + this->parse_and_visit_typescript_colon_type_expression( + return_type_visits, TypeScript_Type_Parse_Options{ + .allow_parenthesized_type = false, + .allow_type_predicate = true, + }); } QLJS_PARSER_UNIMPLEMENTED_IF_NOT_TOKEN(Token_Type::equal_greater); @@ -2168,9 +2172,13 @@ Expression* Parser::parse_expression_remainder(Parse_Visitor_Base& v, bool is_possibly_arrow_function_return_type_annotation = child->kind() == Expression_Kind::Paren || child->kind() == Expression_Kind::Paren_Empty; - this->parse_and_visit_typescript_colon_type_expression_or_type_predicate( - type_visitor, /*allow_parenthesized_type=*/ - !is_possibly_arrow_function_return_type_annotation); + this->parse_and_visit_typescript_colon_type_expression( + type_visitor, + TypeScript_Type_Parse_Options{ + .allow_parenthesized_type = + !is_possibly_arrow_function_return_type_annotation, + .allow_type_predicate = true, + }); const Char8* type_end = this->lexer_.end_of_previous_token(); binary_builder.replace_last( this->make_expression( @@ -3870,9 +3878,11 @@ Expression* Parser::parse_typescript_generic_arrow_expression( Buffering_Visitor return_type_visits(&this->type_expression_memory_); if (this->peek().type == Token_Type::colon) { - this->parse_and_visit_typescript_colon_type_expression_or_type_predicate( - return_type_visits, - /*allow_parenthesized_type=*/false); + this->parse_and_visit_typescript_colon_type_expression( + return_type_visits, TypeScript_Type_Parse_Options{ + .allow_parenthesized_type = false, + .allow_type_predicate = true, + }); } QLJS_PARSER_UNIMPLEMENTED_IF_NOT_TOKEN(Token_Type::equal_greater); @@ -3941,9 +3951,11 @@ Expression* Parser::parse_typescript_angle_type_assertion_expression( ast->kind() == Expression_Kind::Paren_Empty) { Buffering_Visitor return_type_visits(&this->type_expression_memory_); if (this->peek().type == Token_Type::colon) { - this->parse_and_visit_typescript_colon_type_expression_or_type_predicate( - return_type_visits, - /*allow_parenthesized_type=*/false); + this->parse_and_visit_typescript_colon_type_expression( + return_type_visits, TypeScript_Type_Parse_Options{ + .allow_parenthesized_type = false, + .allow_type_predicate = true, + }); } if (this->peek().type == Token_Type::equal_greater) { // (param) => body diff --git a/src/quick-lint-js/fe/parse-statement.cpp b/src/quick-lint-js/fe/parse-statement.cpp index 6ff46bdd5f..372475ed7b 100644 --- a/src/quick-lint-js/fe/parse-statement.cpp +++ b/src/quick-lint-js/fe/parse-statement.cpp @@ -2274,8 +2274,11 @@ Parser::parse_and_visit_function_parameter_list( this->skip(); if (this->peek().type == Token_Type::colon) { - this->parse_and_visit_typescript_colon_type_expression_or_type_predicate( - v, /*allow_parenthesized_type=*/true); + this->parse_and_visit_typescript_colon_type_expression( + v, TypeScript_Type_Parse_Options{ + .allow_parenthesized_type = true, + .allow_type_predicate = true, + }); } if (this->peek().type == Token_Type::equal_greater) { diff --git a/src/quick-lint-js/fe/parse-type.cpp b/src/quick-lint-js/fe/parse-type.cpp index c70f991ad8..27102bb05d 100644 --- a/src/quick-lint-js/fe/parse-type.cpp +++ b/src/quick-lint-js/fe/parse-type.cpp @@ -37,8 +37,14 @@ void Parser::parse_typescript_colon_for_type() { void Parser::parse_and_visit_typescript_colon_type_expression( Parse_Visitor_Base &v) { + this->parse_and_visit_typescript_colon_type_expression( + v, TypeScript_Type_Parse_Options()); +} + +void Parser::parse_and_visit_typescript_colon_type_expression( + Parse_Visitor_Base &v, const TypeScript_Type_Parse_Options &parse_options) { this->parse_typescript_colon_for_type(); - this->parse_and_visit_typescript_type_expression(v); + this->parse_and_visit_typescript_type_expression(v, parse_options); } void Parser::parse_and_visit_typescript_type_expression(Parse_Visitor_Base &v) { @@ -694,23 +700,6 @@ void Parser::parse_and_visit_typescript_type_expression( } } -void Parser::parse_and_visit_typescript_colon_type_expression_or_type_predicate( - Parse_Visitor_Base &v, bool allow_parenthesized_type) { - this->parse_typescript_colon_for_type(); - this->parse_and_visit_typescript_type_expression_or_type_predicate( - v, /*allow_parenthesized_type=*/ - allow_parenthesized_type); -} - -void Parser::parse_and_visit_typescript_type_expression_or_type_predicate( - Parse_Visitor_Base &v, bool allow_parenthesized_type) { - this->parse_and_visit_typescript_type_expression( - v, TypeScript_Type_Parse_Options{ - .allow_parenthesized_type = allow_parenthesized_type, - .allow_type_predicate = true, - }); -} - void Parser::parse_and_visit_typescript_arrow_type_expression( Parse_Visitor_Base &v) { v.visit_enter_function_scope(); @@ -741,8 +730,11 @@ void Parser:: this->skip(); QLJS_PARSER_UNIMPLEMENTED_IF_NOT_TOKEN(Token_Type::equal_greater); this->skip(); - this->parse_and_visit_typescript_type_expression_or_type_predicate( - v, /*allow_parenthesized_type=*/false); + this->parse_and_visit_typescript_type_expression( + v, TypeScript_Type_Parse_Options{ + .allow_parenthesized_type = false, + .allow_type_predicate = true, + }); } Parser::TypeScript_Type_Arrow_Or_Paren diff --git a/src/quick-lint-js/fe/parse.h b/src/quick-lint-js/fe/parse.h index 7d83392d41..c9eaa97348 100644 --- a/src/quick-lint-js/fe/parse.h +++ b/src/quick-lint-js/fe/parse.h @@ -216,15 +216,12 @@ class Parser { }; void parse_and_visit_typescript_colon_type_expression(Parse_Visitor_Base &v); + void parse_and_visit_typescript_colon_type_expression( + Parse_Visitor_Base &v, const TypeScript_Type_Parse_Options &); void parse_and_visit_typescript_type_expression(Parse_Visitor_Base &v); void parse_and_visit_typescript_type_expression( Parse_Visitor_Base &v, const TypeScript_Type_Parse_Options &); - void parse_and_visit_typescript_colon_type_expression_or_type_predicate( - Parse_Visitor_Base &v, bool allow_parenthesized_type); - void parse_and_visit_typescript_type_expression_or_type_predicate( - Parse_Visitor_Base &v, bool allow_parenthesized_type); - enum class TypeScript_Type_Arrow_Or_Paren { arrow, paren, From 4ac79ee093592303a0959f275560a1205a9e7fd8 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Mon, 6 Nov 2023 22:59:26 -0500 Subject: [PATCH 117/117] feat(typescript): error on 'var foo: p is Type' Report a diagnostic if a TypeScript type predicate appears where it shouldn't appear. --- docs/CHANGELOG.md | 3 ++ po/messages.pot | 4 +++ .../diag/diagnostic-metadata-generated.cpp | 14 ++++++++ .../diag/diagnostic-metadata-generated.h | 3 +- src/quick-lint-js/diag/diagnostic-types-2.h | 7 ++++ src/quick-lint-js/fe/parse-expression.cpp | 3 +- src/quick-lint-js/fe/parse-type.cpp | 13 ++++++- .../i18n/translation-table-generated.cpp | 2 ++ .../i18n/translation-table-generated.h | 5 +-- .../i18n/translation-table-test-generated.h | 13 ++++++- test/test-parse-typescript-function.cpp | 35 +++++++++++++++++++ 11 files changed, 96 insertions(+), 6 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 309382d02f..f542153f19 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -14,6 +14,8 @@ Semantic Versioning. * `export as namespace` statements are now parsed. * `case await x:` no longer treats `:` as if it was a type annotation colon in an arrow function parameter list. + * If a type predicate appears outside a return type, quick-lint-js now reports + [E0426][] ("type predicates are only allowed as function return types"). ### Fixed @@ -1293,6 +1295,7 @@ Beta release. [E0383]: https://quick-lint-js.com/errors/E0383/ [E0384]: https://quick-lint-js.com/errors/E0384/ [E0398]: https://quick-lint-js.com/errors/E0398/ +[E0426]: https://quick-lint-js.com/errors/E0426/ [E0450]: https://quick-lint-js.com/errors/E0450/ [E0451]: https://quick-lint-js.com/errors/E0451/ [E0452]: https://quick-lint-js.com/errors/E0452/ diff --git a/po/messages.pot b/po/messages.pot index 13d2f7dcc9..ea3e7c348f 100644 --- a/po/messages.pot +++ b/po/messages.pot @@ -1509,6 +1509,10 @@ msgstr "" msgid "TypeScript type exports are not allowed in JavaScript" msgstr "" +#: src/quick-lint-js/diag/diagnostic-metadata-generated.cpp +msgid "type predicates are only allowed as function return types" +msgstr "" + #: src/quick-lint-js/diag/diagnostic-metadata-generated.cpp msgid "'type' cannot be used twice in export" msgstr "" diff --git a/src/quick-lint-js/diag/diagnostic-metadata-generated.cpp b/src/quick-lint-js/diag/diagnostic-metadata-generated.cpp index a5043b249b..510a6bb47a 100644 --- a/src/quick-lint-js/diag/diagnostic-metadata-generated.cpp +++ b/src/quick-lint-js/diag/diagnostic-metadata-generated.cpp @@ -4481,6 +4481,20 @@ const QLJS_CONSTINIT Diagnostic_Info all_diagnostic_infos[] = { }, }, + // Diag_TypeScript_Type_Predicate_Only_Allowed_As_Return_Type + { + .code = 426, + .severity = Diagnostic_Severity::error, + .message_formats = { + QLJS_TRANSLATABLE("type predicates are only allowed as function return types"), + }, + .message_args = { + { + Diagnostic_Message_Arg_Info(offsetof(Diag_TypeScript_Type_Predicate_Only_Allowed_As_Return_Type, is_keyword), Diagnostic_Arg_Type::source_code_span), + }, + }, + }, + // Diag_TypeScript_Inline_Type_Export_Not_Allowed_In_Type_Only_Export { .code = 280, diff --git a/src/quick-lint-js/diag/diagnostic-metadata-generated.h b/src/quick-lint-js/diag/diagnostic-metadata-generated.h index 4057886cc0..9f688f67c8 100644 --- a/src/quick-lint-js/diag/diagnostic-metadata-generated.h +++ b/src/quick-lint-js/diag/diagnostic-metadata-generated.h @@ -309,6 +309,7 @@ namespace quick_lint_js { QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Global_Block_Not_Allowed_In_JavaScript) \ QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Global_Block_Not_Allowed_In_Namespace) \ QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Type_Export_Not_Allowed_In_JavaScript) \ + QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Type_Predicate_Only_Allowed_As_Return_Type) \ QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Inline_Type_Export_Not_Allowed_In_Type_Only_Export) \ QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Inline_Type_Import_Not_Allowed_In_Type_Only_Import) \ QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Interfaces_Cannot_Contain_Static_Blocks) \ @@ -446,7 +447,7 @@ namespace quick_lint_js { /* END */ // clang-format on -inline constexpr int Diag_Type_Count = 432; +inline constexpr int Diag_Type_Count = 433; extern const Diagnostic_Info all_diagnostic_infos[Diag_Type_Count]; } diff --git a/src/quick-lint-js/diag/diagnostic-types-2.h b/src/quick-lint-js/diag/diagnostic-types-2.h index 306439507d..bb40450e40 100644 --- a/src/quick-lint-js/diag/diagnostic-types-2.h +++ b/src/quick-lint-js/diag/diagnostic-types-2.h @@ -2318,6 +2318,13 @@ struct Diag_TypeScript_Type_Export_Not_Allowed_In_JavaScript { Source_Code_Span type_keyword; }; +struct Diag_TypeScript_Type_Predicate_Only_Allowed_As_Return_Type { + [[qljs::diag("E0426", Diagnostic_Severity::error)]] // + [[qljs::message("type predicates are only allowed as function return types", + ARG(is_keyword))]] // + Source_Code_Span is_keyword; +}; + struct Diag_TypeScript_Inline_Type_Export_Not_Allowed_In_Type_Only_Export { [[qljs::diag("E0280", Diagnostic_Severity::error)]] // [[qljs::message("'type' cannot be used twice in export", diff --git a/src/quick-lint-js/fe/parse-expression.cpp b/src/quick-lint-js/fe/parse-expression.cpp index ef803e5bd7..e106b5d7b2 100644 --- a/src/quick-lint-js/fe/parse-expression.cpp +++ b/src/quick-lint-js/fe/parse-expression.cpp @@ -2177,7 +2177,8 @@ Expression* Parser::parse_expression_remainder(Parse_Visitor_Base& v, TypeScript_Type_Parse_Options{ .allow_parenthesized_type = !is_possibly_arrow_function_return_type_annotation, - .allow_type_predicate = true, + .allow_type_predicate = + is_possibly_arrow_function_return_type_annotation, }); const Char8* type_end = this->lexer_.end_of_previous_token(); binary_builder.replace_last( diff --git a/src/quick-lint-js/fe/parse-type.cpp b/src/quick-lint-js/fe/parse-type.cpp index 27102bb05d..7fabbb8502 100644 --- a/src/quick-lint-js/fe/parse-type.cpp +++ b/src/quick-lint-js/fe/parse-type.cpp @@ -219,10 +219,21 @@ void Parser::parse_and_visit_typescript_type_expression( if (this->peek().type == Token_Type::kw_is) { // param is Type // this is Type + Source_Code_Span is_keyword = this->peek().span(); this->skip(); if (name_type != Token_Type::kw_this) { // this is Type - v.visit_variable_type_predicate_use(name); + if (parse_options.allow_type_predicate) { + v.visit_variable_type_predicate_use(name); + } else { + v.visit_variable_use(name); + } + } + if (!parse_options.allow_type_predicate) { + this->diag_reporter_->report( + Diag_TypeScript_Type_Predicate_Only_Allowed_As_Return_Type{ + .is_keyword = is_keyword, + }); } this->parse_and_visit_typescript_type_expression(v); return; diff --git a/src/quick-lint-js/i18n/translation-table-generated.cpp b/src/quick-lint-js/i18n/translation-table-generated.cpp index 18aebffa7f..1f573c60d6 100644 --- a/src/quick-lint-js/i18n/translation-table-generated.cpp +++ b/src/quick-lint-js/i18n/translation-table-generated.cpp @@ -469,6 +469,7 @@ const Translation_Table translation_data = { {50, 25, 0, 70, 0, 78}, // {33, 21, 74, 25, 44, 21}, // {0, 0, 0, 0, 0, 26}, // + {0, 0, 0, 0, 0, 58}, // {27, 19, 30, 29, 22, 31}, // {25, 50, 0, 36, 0, 23}, // {66, 43, 31, 36, 30, 44}, // @@ -2268,6 +2269,7 @@ const Translation_Table translation_data = { u8"this tuple type is a named tuple type because at least one element has a name\0" u8"this {0} looks fishy\0" u8"try statement starts here\0" + u8"type predicates are only allowed as function return types\0" u8"type {1} is being defined here\0" u8"unclosed block comment\0" u8"unclosed class; expected '}' by end of file\0" diff --git a/src/quick-lint-js/i18n/translation-table-generated.h b/src/quick-lint-js/i18n/translation-table-generated.h index 28be58721d..6e775216c6 100644 --- a/src/quick-lint-js/i18n/translation-table-generated.h +++ b/src/quick-lint-js/i18n/translation-table-generated.h @@ -18,8 +18,8 @@ namespace quick_lint_js { using namespace std::literals::string_view_literals; constexpr std::uint32_t translation_table_locale_count = 5; -constexpr std::uint16_t translation_table_mapping_table_size = 529; -constexpr std::size_t translation_table_string_table_size = 80304; +constexpr std::uint16_t translation_table_mapping_table_size = 530; +constexpr std::size_t translation_table_string_table_size = 80362; constexpr std::size_t translation_table_locale_table_size = 35; QLJS_CONSTEVAL std::uint16_t translation_table_const_look_up( @@ -483,6 +483,7 @@ QLJS_CONSTEVAL std::uint16_t translation_table_const_look_up( "this tuple type is a named tuple type because at least one element has a name"sv, "this {0} looks fishy"sv, "try statement starts here"sv, + "type predicates are only allowed as function return types"sv, "type {1} is being defined here"sv, "unclosed block comment"sv, "unclosed class; expected '}' by end of file"sv, diff --git a/src/quick-lint-js/i18n/translation-table-test-generated.h b/src/quick-lint-js/i18n/translation-table-test-generated.h index b283c2ade5..28145cd15d 100644 --- a/src/quick-lint-js/i18n/translation-table-test-generated.h +++ b/src/quick-lint-js/i18n/translation-table-test-generated.h @@ -27,7 +27,7 @@ struct Translated_String { }; // clang-format off -inline const Translated_String test_translation_table[528] = { +inline const Translated_String test_translation_table[529] = { { "\"global-groups\" entries must be strings"_translatable, u8"\"global-groups\" entries must be strings", @@ -5055,6 +5055,17 @@ inline const Translated_String test_translation_table[528] = { u8"try sats startar h\u00e4r", }, }, + { + "type predicates are only allowed as function return types"_translatable, + u8"type predicates are only allowed as function return types", + { + u8"type predicates are only allowed as function return types", + u8"type predicates are only allowed as function return types", + u8"type predicates are only allowed as function return types", + u8"type predicates are only allowed as function return types", + u8"type predicates are only allowed as function return types", + }, + }, { "type {1} is being defined here"_translatable, u8"type {1} is being defined here", diff --git a/test/test-parse-typescript-function.cpp b/test/test-parse-typescript-function.cpp index 46a1e846b6..04e0c184b6 100644 --- a/test/test-parse-typescript-function.cpp +++ b/test/test-parse-typescript-function.cpp @@ -991,6 +991,41 @@ TEST_F(Test_Parse_TypeScript_Function, type_predicate_on_generator_function) { } } +TEST_F(Test_Parse_TypeScript_Function, + type_predicate_is_only_allowed_as_return_type) { + { + Spy_Visitor p = test_parse_and_visit_statement( + u8"function f(p, q: p is SomeType) {}"_sv, // + u8" ^^ Diag_TypeScript_Type_Predicate_Only_Allowed_As_Return_Type"_diag, + typescript_options); + EXPECT_THAT(p.visits, ElementsAreArray({ + "visit_enter_function_scope", // + "visit_variable_declaration", // p + "visit_variable_use", // p + "visit_variable_type_use", // SomeType + "visit_variable_declaration", // q + "visit_enter_function_scope_body", // { + "visit_exit_function_scope", // } + "visit_variable_declaration", // f + })); + EXPECT_THAT(p.variable_uses, ElementsAreArray({u8"p", u8"SomeType"})); + } + + { + test_parse_and_visit_statement( + u8"var x: p is T;"_sv, // + u8" ^^ Diag_TypeScript_Type_Predicate_Only_Allowed_As_Return_Type"_diag, + typescript_options); + } + + { + test_parse_and_visit_statement( + u8"function f(p): p is p is T {}"_sv, // + u8" ^^ Diag_TypeScript_Type_Predicate_Only_Allowed_As_Return_Type"_diag, + typescript_options); + } +} + TEST_F(Test_Parse_TypeScript_Function, type_predicate_in_type) { { Spy_Visitor p = test_parse_and_visit_typescript_type_expression(