diff --git a/plugin/vscode/quick-lint-js/vscode/qljs-workspace.cpp b/plugin/vscode/quick-lint-js/vscode/qljs-workspace.cpp index f4b629cdd2..432045936c 100644 --- a/plugin/vscode/quick-lint-js/vscode/qljs-workspace.cpp +++ b/plugin/vscode/quick-lint-js/vscode/qljs-workspace.cpp @@ -372,7 +372,10 @@ void QLJS_Workspace::check_for_config_file_changes_from_thread( } void QLJS_Workspace::check_for_config_file_changes(::Napi::Env env) { - std::vector changes = this->config_loader_.refresh(); + Monotonic_Allocator temporary_allocator( + "QLJS_Workspace::check_for_config_file_changes"); + Span changes = + this->config_loader_.refresh(&temporary_allocator); for (const Configuration_Change& change : changes) { QLJS_DEBUG_LOG("Configuration changed for %s\n", change.watched_path->c_str()); diff --git a/src/quick-lint-js/configuration/configuration-loader.cpp b/src/quick-lint-js/configuration/configuration-loader.cpp index 58ea653658..658a902d1b 100644 --- a/src/quick-lint-js/configuration/configuration-loader.cpp +++ b/src/quick-lint-js/configuration/configuration-loader.cpp @@ -315,8 +315,10 @@ void Configuration_Loader::unwatch_all_files() { this->watched_input_paths_.clear(); } -std::vector Configuration_Loader::refresh() { - std::vector changes; +Span Configuration_Loader::refresh( + Monotonic_Allocator* allocator) { + Vector changes("Configuration_Loader::refresh changes", + allocator); Hash_Map loaded_config_files = std::move(this->loaded_config_files_); @@ -515,7 +517,7 @@ std::vector Configuration_Loader::refresh() { } } - return changes; + return changes.release_to_span(); } bool Configuration_Loader::is_config_file_path( diff --git a/src/quick-lint-js/configuration/configuration-loader.h b/src/quick-lint-js/configuration/configuration-loader.h index f26c04107e..2492243869 100644 --- a/src/quick-lint-js/configuration/configuration-loader.h +++ b/src/quick-lint-js/configuration/configuration-loader.h @@ -10,12 +10,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -140,7 +142,7 @@ class Configuration_Loader { // quick-lint-js.config's content changed. // * A quick-lint-js.config file didn't exist, and now one does. // * A quick-lint-js.config file was moved into an ancestor directory. - std::vector refresh(); + Span refresh(Monotonic_Allocator*); // Returns true if the path might possibly be a configuration file detected by // load_for_file or watch_and_load_for_file. diff --git a/src/quick-lint-js/lsp/lsp-server.cpp b/src/quick-lint-js/lsp/lsp-server.cpp index d862ee4519..a3d2247ae4 100644 --- a/src/quick-lint-js/lsp/lsp-server.cpp +++ b/src/quick-lint-js/lsp/lsp-server.cpp @@ -219,12 +219,13 @@ void Linting_LSP_Server_Handler::handle_notification( } void Linting_LSP_Server_Handler::filesystem_changed() { - std::vector config_changes = - this->config_loader_.refresh(); + Monotonic_Allocator temporary_allocator( + "Linting_LSP_Server_Handler::filesystem_changed"); + Span config_changes = + this->config_loader_.refresh(&temporary_allocator); { Lock_Ptr documents = this->documents_.lock(); - this->handle_config_file_changes( - documents, Span(config_changes)); + this->handle_config_file_changes(documents, config_changes); } } @@ -366,10 +367,12 @@ void Linting_LSP_Server_Handler::handle_text_document_did_change_notification( switch (doc.type) { case LSP_Documents::Document_Type::config: { - std::vector config_changes = - this->config_loader_.refresh(); - this->handle_config_file_changes( - documents, Span(config_changes)); + Monotonic_Allocator temporary_allocator( + "Linting_LSP_Server_Handler::handle_text_document_did_change_" + "notification"); + Span config_changes = + this->config_loader_.refresh(&temporary_allocator); + this->handle_config_file_changes(documents, config_changes); break; } @@ -516,12 +519,14 @@ void Linting_LSP_Server_Handler::handle_text_document_did_open_notification( *config_file, notification.uri.json, doc->version_json, config_diagnostics_json); - std::vector config_changes = - this->config_loader_.refresh(); + Monotonic_Allocator temporary_allocator( + "Linting_LSP_Server_Handler::handle_text_document_did_open_" + "notification"); + Span config_changes = + this->config_loader_.refresh(&temporary_allocator); { Lock_Ptr documents = this->documents_.lock(); - this->handle_config_file_changes( - documents, Span(config_changes)); + this->handle_config_file_changes(documents, config_changes); } doc_ptr = std::move(doc); diff --git a/test/test-configuration-loader.cpp b/test/test-configuration-loader.cpp index e20ffd4113..005dcbf26e 100644 --- a/test/test-configuration-loader.cpp +++ b/test/test-configuration-loader.cpp @@ -149,7 +149,7 @@ class Change_Detecting_Configuration_Loader { return this->fs_.take_watch_errors(); } - std::vector detect_changes_and_refresh(); + Span detect_changes_and_refresh(); private: bool detect_changes(); @@ -187,6 +187,7 @@ class Change_Detecting_Configuration_Loader { // Protected by mutex_ if present: Configuration_Loader loader_; + Monotonic_Allocator allocator{"Change_Detecting_Configuration_Loader"}; }; class Test_Configuration_Loader : public ::testing::Test, @@ -643,8 +644,7 @@ TEST_F(Test_Configuration_Loader, EXPECT_EQ(::rmdir(parent_dir.c_str()), 0) << "failed to delete " << parent_dir << ": " << std::strerror(errno); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); EXPECT_THAT(changes, IsEmpty()); } @@ -659,8 +659,7 @@ TEST_F(Test_Configuration_Loader, config_found_initially_is_unchanged) { Change_Detecting_Configuration_Loader loader; loader.watch_and_load_for_file(js_file, /*token=*/nullptr); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); EXPECT_THAT(changes, IsEmpty()); } } @@ -678,8 +677,7 @@ TEST_F(Test_Configuration_Loader, write_file_or_exit(config_file, u8R"({"globals": {"after": true}})"_sv); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_SAME_FILE(*changes[0].watched_path, js_file); EXPECT_SAME_FILE(*changes[0].config_file->config_path, config_file); @@ -708,8 +706,7 @@ TEST_F(Test_Configuration_Loader, ASSERT_EQ(std::fclose(file), 0) << std::strerror(errno); } - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_SAME_FILE(*changes[0].watched_path, js_file); EXPECT_SAME_FILE(*changes[0].config_file->config_path, config_file); @@ -729,8 +726,7 @@ TEST_F(Test_Configuration_Loader, write_file_or_exit(config_file, u8R"({"globals": {"b": true}})"_sv); write_file_or_exit(config_file, u8R"({"globals": {"a": true}})"_sv); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); EXPECT_THAT(changes, IsEmpty()); } @@ -751,8 +747,7 @@ TEST_F(Test_Configuration_Loader, move_file(new_config_file, config_file); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_SAME_FILE(*changes[0].watched_path, js_file); EXPECT_SAME_FILE(*changes[0].config_file->config_path, config_file); @@ -775,8 +770,7 @@ TEST_F(Test_Configuration_Loader, move_file(new_config_file, config_file); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); EXPECT_THAT(changes, IsEmpty()); } @@ -795,8 +789,7 @@ TEST_F(Test_Configuration_Loader, move_file(config_file, temp_config_file); move_file(temp_config_file, config_file); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); EXPECT_THAT(changes, IsEmpty()); } @@ -811,8 +804,7 @@ TEST_F(Test_Configuration_Loader, creating_config_in_same_dir_is_detected) { std::string config_file = project_dir + "/quick-lint-js.config"; write_file_or_exit(config_file, u8"{}"_sv); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_SAME_FILE(*changes[0].watched_path, js_file); EXPECT_SAME_FILE(*changes[0].config_file->config_path, config_file); @@ -829,8 +821,7 @@ TEST_F(Test_Configuration_Loader, std::string config_file = project_dir + "/quick-lint-js.config"; write_file_or_exit(config_file, u8"{}"_sv); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_THAT(*changes[0].watched_path, ::testing::HasSubstr("hello.js")); EXPECT_SAME_FILE(*changes[0].config_file->config_path, config_file); @@ -848,8 +839,7 @@ TEST_F(Test_Configuration_Loader, creating_config_in_parent_dir_is_detected) { std::string config_file = project_dir + "/quick-lint-js.config"; write_file_or_exit(config_file, u8"{}"_sv); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_SAME_FILE(*changes[0].watched_path, js_file); EXPECT_SAME_FILE(*changes[0].config_file->config_path, config_file); @@ -870,8 +860,7 @@ TEST_F(Test_Configuration_Loader, std::string inner_config_file = project_dir + "/dir/quick-lint-js.config"; write_file_or_exit(inner_config_file, u8"{}"_sv); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_SAME_FILE(*changes[0].watched_path, js_file); EXPECT_SAME_FILE(*changes[0].config_file->config_path, inner_config_file); @@ -890,8 +879,7 @@ TEST_F(Test_Configuration_Loader, deleting_config_in_same_dir_is_detected) { EXPECT_EQ(std::remove(config_file.c_str()), 0) << "failed to delete " << config_file << ": " << std::strerror(errno); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_SAME_FILE(*changes[0].watched_path, js_file); EXPECT_EQ(changes[0].config_file, nullptr); @@ -915,8 +903,7 @@ TEST_F(Test_Configuration_Loader, << "failed to delete " << inner_config_file << ": " << std::strerror(errno); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_SAME_FILE(*changes[0].watched_path, js_file); EXPECT_SAME_FILE(*changes[0].config_file->config_path, outer_config_file); @@ -934,8 +921,7 @@ TEST_F(Test_Configuration_Loader, moving_config_away_in_same_dir_is_detected) { move_file(config_file, (project_dir + "/moved.config")); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_SAME_FILE(*changes[0].watched_path, js_file); EXPECT_EQ(changes[0].config_file, nullptr); @@ -957,8 +943,7 @@ TEST_F(Test_Configuration_Loader, move_file(inner_config_file, (project_dir + "/dir/moved.config")); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_SAME_FILE(*changes[0].watched_path, js_file); EXPECT_SAME_FILE(*changes[0].config_file->config_path, outer_config_file); @@ -977,8 +962,7 @@ TEST_F(Test_Configuration_Loader, moving_config_into_same_dir_is_detected) { move_file(temp_config_file, renamed_config_file); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_SAME_FILE(*changes[0].watched_path, js_file); EXPECT_SAME_FILE(*changes[0].config_file->config_path, renamed_config_file); @@ -998,8 +982,7 @@ TEST_F(Test_Configuration_Loader, moving_config_into_parent_dir_is_detected) { move_file(temp_config_file, renamed_config_file); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_SAME_FILE(*changes[0].watched_path, js_file); EXPECT_SAME_FILE(*changes[0].config_file->config_path, renamed_config_file); @@ -1022,8 +1005,7 @@ TEST_F(Test_Configuration_Loader, move_file(temp_config_file, inner_config_file); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_SAME_FILE(*changes[0].watched_path, js_file); EXPECT_SAME_FILE(*changes[0].config_file->config_path, inner_config_file); @@ -1043,8 +1025,7 @@ TEST_F(Test_Configuration_Loader, move_file((project_dir + "/olddir"), (project_dir + "/newdir")); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_THAT(*changes[0].watched_path, ::testing::HasSubstr("hello.js")); EXPECT_THAT(*changes[0].watched_path, ::testing::HasSubstr("olddir")); @@ -1066,8 +1047,7 @@ TEST_F(Test_Configuration_Loader, move_file((project_dir + "/olddir"), (project_dir + "/newdir")); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_THAT(*changes[0].watched_path, ::testing::HasSubstr("hello.js")); EXPECT_THAT(*changes[0].watched_path, ::testing::HasSubstr("olddir")); @@ -1088,8 +1068,7 @@ TEST_F(Test_Configuration_Loader, move_file((project_dir + "/olddir"), (project_dir + "/newdir")); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); EXPECT_THAT(changes, IsEmpty()); } @@ -1105,8 +1084,7 @@ TEST_F(Test_Configuration_Loader, moving_file_keeps_config) { move_file((project_dir + "/oldfile.js"), (project_dir + "/newfile.js")); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); EXPECT_THAT(changes, IsEmpty()); } @@ -1119,8 +1097,7 @@ TEST_F(Test_Configuration_Loader, loader.watch_and_load_for_file(js_file, /*token=*/nullptr); create_directory_or_exit(project_dir + "/dir"); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); EXPECT_THAT(changes, IsEmpty()) << "creating dir should not change associated config file"; @@ -1147,8 +1124,7 @@ TEST_F( std::string config_file = project_dir + "/dir/quick-lint-js.config"; write_file_or_exit(config_file, u8"{}"_sv); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_THAT(*changes[0].watched_path, ::testing::HasSubstr("test.js")); EXPECT_SAME_FILE(*changes[0].config_file->config_path, config_file); @@ -1174,8 +1150,7 @@ TEST_F(Test_Configuration_Loader, std::string config_file = project_dir + "/quick-lint-js.config"; write_file_or_exit(config_file, u8"{}"_sv); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); Hash_Set unconfigured_js_files = js_files; for (const Configuration_Change& change : changes) { SCOPED_TRACE(*change.watched_path); @@ -1218,8 +1193,7 @@ TEST_F(Test_Configuration_Loader, << std::strerror(errno); write_file_or_exit(outer_config_file, u8R"({"globals": {"after": true}})"_sv); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); std::vector watched_paths; std::vector watched_tokens; @@ -1266,8 +1240,7 @@ TEST_F(Test_Configuration_Loader, write_file_or_exit(config_file, u8R"({"globals": {"after": true}})"_sv); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_EQ(*changes[0].watched_path, config_file); EXPECT_EQ(changes[0].token, &config_file); @@ -1289,8 +1262,7 @@ TEST_F(Test_Configuration_Loader, write_file_or_exit(config_file, u8R"({"globals": {"testGlobalVariable": true}})"_sv); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_EQ(*changes[0].watched_path, config_file); EXPECT_EQ(changes[0].token, &config_file); @@ -1312,8 +1284,7 @@ TEST_F(Test_Configuration_Loader, EXPECT_EQ(std::remove(config_file.c_str()), 0) << "failed to delete " << config_file << ": " << std::strerror(errno); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_EQ(*changes[0].watched_path, config_file); EXPECT_EQ(changes[0].token, &config_file); @@ -1407,8 +1378,7 @@ TEST_F(Test_Configuration_Loader, << "failed to make " << config_file << " unreadable: " << std::strerror(errno); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_EQ(changes[0].token, &js_file); EXPECT_EQ(changes[0].config_file, nullptr); @@ -1439,8 +1409,7 @@ TEST_F(Test_Configuration_Loader, << "failed to make " << config_file << " unreadable: " << std::strerror(errno); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_EQ(changes[0].token, &config_file); EXPECT_EQ(changes[0].config_file, nullptr); @@ -1485,8 +1454,7 @@ TEST_F(Test_Configuration_Loader, << "failed to make " << config_file << " readable: " << std::strerror(errno); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_EQ(changes[0].token, &js_file); EXPECT_TRUE( @@ -1528,8 +1496,7 @@ TEST_F(Test_Configuration_Loader, << "failed to make " << config_file << " readable: " << std::strerror(errno); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_EQ(changes[0].token, &config_file); EXPECT_TRUE( @@ -1562,8 +1529,7 @@ TEST_F(Test_Configuration_Loader, canonicalize_path(config_file)->c_str()); EXPECT_EQ(loaded_config.error().io_error.error, EACCES); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); EXPECT_THAT(changes, IsEmpty()); } @@ -1589,8 +1555,7 @@ TEST_F(Test_Configuration_Loader, canonicalize_path(config_file)->c_str()); EXPECT_THAT(loaded_config.error().io_error.error, EACCES); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); EXPECT_THAT(changes, IsEmpty()); } @@ -1615,15 +1580,14 @@ TEST_F(Test_Configuration_Loader, << "failed to make " << config_file << " unreadable: " << std::strerror(errno); - [[maybe_unused]] std::vector changes_1 = + [[maybe_unused]] Span changes_1 = loader.detect_changes_and_refresh(); EXPECT_EQ(::chmod(config_file.c_str(), 0644), 0) << "failed to make " << config_file << " readable: " << std::strerror(errno); - std::vector changes_2 = - loader.detect_changes_and_refresh(); + Span changes_2 = loader.detect_changes_and_refresh(); ASSERT_THAT(changes_2, ElementsAreArray({::testing::_})); EXPECT_EQ(changes_2[0].token, &js_file); EXPECT_TRUE(changes_2[0].config_file->config.globals().find( @@ -1650,15 +1614,14 @@ TEST_F( << "failed to make " << config_file << " unreadable: " << std::strerror(errno); - [[maybe_unused]] std::vector changes_1 = + [[maybe_unused]] Span changes_1 = loader.detect_changes_and_refresh(); EXPECT_EQ(::chmod(config_file.c_str(), 0644), 0) << "failed to make " << config_file << " readable: " << std::strerror(errno); - std::vector changes_2 = - loader.detect_changes_and_refresh(); + Span changes_2 = loader.detect_changes_and_refresh(); ASSERT_THAT(changes_2, ElementsAreArray({::testing::_})); EXPECT_EQ(changes_2[0].token, &config_file); EXPECT_TRUE(changes_2[0].config_file->config.globals().find( @@ -1702,15 +1665,14 @@ TEST_F( << "failed to make " << config_file << " readable: " << std::strerror(errno); - [[maybe_unused]] std::vector changes_1 = + [[maybe_unused]] Span changes_1 = loader.detect_changes_and_refresh(); EXPECT_EQ(::chmod(config_file.c_str(), 0000), 0) << "failed to make " << config_file << " unreadable: " << std::strerror(errno); - std::vector changes_2 = - loader.detect_changes_and_refresh(); + Span changes_2 = loader.detect_changes_and_refresh(); ASSERT_THAT(changes_2, ElementsAreArray({::testing::_})); EXPECT_EQ(changes_2[0].token, &js_file); EXPECT_EQ(changes_2[0].config_file, nullptr); @@ -1752,15 +1714,14 @@ TEST_F( << "failed to make " << config_file << " readable: " << std::strerror(errno); - [[maybe_unused]] std::vector changes_1 = + [[maybe_unused]] Span changes_1 = loader.detect_changes_and_refresh(); EXPECT_EQ(::chmod(config_file.c_str(), 0000), 0) << "failed to make " << config_file << " unreadable: " << std::strerror(errno); - std::vector changes_2 = - loader.detect_changes_and_refresh(); + Span changes_2 = loader.detect_changes_and_refresh(); ASSERT_THAT(changes_2, ElementsAreArray({::testing::_})); EXPECT_EQ(changes_2[0].token, &config_file); EXPECT_EQ(changes_2[0].config_file, nullptr); @@ -1799,8 +1760,7 @@ TEST_F(Test_Configuration_Loader, EXPECT_EQ(::chmod(dir.c_str(), 0700), 0) << "failed to make " << dir << " readable: " << std::strerror(errno); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_EQ(changes[0].token, &js_file); EXPECT_TRUE( @@ -1838,8 +1798,7 @@ TEST_F( EXPECT_EQ(::chmod(dir.c_str(), 0700), 0) << "failed to make " << dir << " readable: " << std::strerror(errno); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_EQ(changes[0].token, &config_file); EXPECT_TRUE( @@ -1874,8 +1833,7 @@ TEST_F(Test_Configuration_Loader, EXPECT_EQ(::chmod(dir.c_str(), 0600), 0) << "failed to make " << dir << " unreadable: " << std::strerror(errno); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_EQ(changes[0].token, &js_file); EXPECT_EQ(changes[0].config_file, nullptr); @@ -1912,8 +1870,7 @@ TEST_F( EXPECT_EQ(::chmod(dir.c_str(), 0600), 0) << "failed to make " << dir << " unreadable: " << std::strerror(errno); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_EQ(changes[0].token, &config_file); EXPECT_EQ(changes[0].config_file, nullptr); @@ -1950,8 +1907,7 @@ TEST_F(Test_Configuration_Loader, EXPECT_EQ(loaded_config.error().canonicalizing_path, js_file_canonical_path); EXPECT_EQ(loaded_config.error().io_error.error, EACCES); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); EXPECT_THAT(changes, IsEmpty()); } @@ -1981,8 +1937,7 @@ TEST_F(Test_Configuration_Loader, config_file_canonical_path); EXPECT_EQ(loaded_config.error().io_error.error, EACCES); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); EXPECT_THAT(changes, IsEmpty()); } #endif @@ -2008,8 +1963,7 @@ TEST_F(Test_Configuration_Loader, ASSERT_EQ(::symlink("after.config", config_symlink.c_str()), 0) << std::strerror(errno); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_EQ(changes[0].token, &config_symlink); EXPECT_EQ(*changes[0].config_file->config_path, @@ -2043,8 +1997,7 @@ TEST_F(Test_Configuration_Loader, ASSERT_EQ(::symlink("after", subdir_symlink.c_str()), 0) << std::strerror(errno); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_EQ(*changes[0].config_file->config_path, canonicalize_path(after_config_file)->canonical()); @@ -2075,8 +2028,7 @@ TEST_F(Test_Configuration_Loader, move_file(subdir, project_dir + "/before"); move_file(project_dir + "/after", subdir); - std::vector changes = - loader.detect_changes_and_refresh(); + Span changes = loader.detect_changes_and_refresh(); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_EQ(*changes[0].config_file->config_path, canonicalize_path(subdir + "/quick-lint-js.config")->canonical()); @@ -2205,8 +2157,13 @@ TEST_F(Test_Configuration_Loader, } #endif -TEST(Test_Configuration_Loader_Fake, - file_with_no_config_file_gets_default_config) { +class Test_Configuration_Loader_Fake : public ::testing::Test { + public: + Monotonic_Allocator allocator{"Test_Configuration_Loader_Fake"}; +}; + +TEST_F(Test_Configuration_Loader_Fake, + file_with_no_config_file_gets_default_config) { Fake_Configuration_Filesystem fs; fs.create_file(fs.rooted("hello.js"), u8""_sv); @@ -2219,8 +2176,8 @@ TEST(Test_Configuration_Loader_Fake, EXPECT_EQ(*loaded_config, nullptr); } -TEST(Test_Configuration_Loader_Fake, - find_quick_lint_js_config_in_same_directory) { +TEST_F(Test_Configuration_Loader_Fake, + find_quick_lint_js_config_in_same_directory) { Fake_Configuration_Filesystem fs; fs.create_file(fs.rooted("hello.js"), u8""_sv); fs.create_file(fs.rooted("quick-lint-js.config"), u8"{}"_sv); @@ -2235,7 +2192,7 @@ TEST(Test_Configuration_Loader_Fake, EXPECT_EQ(*(*loaded_config)->config_path, fs.rooted("quick-lint-js.config")); } -TEST(Test_Configuration_Loader_Fake, find_config_in_parent_directory) { +TEST_F(Test_Configuration_Loader_Fake, find_config_in_parent_directory) { Fake_Configuration_Filesystem fs; fs.create_file(fs.rooted("dir/hello.js"), u8""_sv); fs.create_file(fs.rooted("quick-lint-js.config"), u8"{}"_sv); @@ -2250,8 +2207,8 @@ TEST(Test_Configuration_Loader_Fake, find_config_in_parent_directory) { EXPECT_EQ(*(*loaded_config)->config_path, fs.rooted("quick-lint-js.config")); } -TEST(Test_Configuration_Loader_Fake, - adding_json_syntax_error_makes_config_default) { +TEST_F(Test_Configuration_Loader_Fake, + adding_json_syntax_error_makes_config_default) { Fake_Configuration_Filesystem fs; fs.create_file(fs.rooted("hello.js"), u8""_sv); fs.create_file(fs.rooted("quick-lint-js.config"), u8"{}"_sv); @@ -2264,13 +2221,13 @@ TEST(Test_Configuration_Loader_Fake, ASSERT_TRUE((*loaded_config)->config.globals().find(u8"console"_sv)); fs.create_file(fs.rooted("quick-lint-js.config"), u8"{\\}"_sv); - std::vector changes = loader.refresh(); + Span changes = loader.refresh(&this->allocator); ASSERT_THAT(changes, ElementsAreArray({::testing::_})); EXPECT_TRUE(changes[0].config_file->config.globals().find(u8"console"_sv)); } -TEST(Test_Configuration_Loader_Fake, - multiple_watches_for_same_token_are_notified_together) { +TEST_F(Test_Configuration_Loader_Fake, + multiple_watches_for_same_token_are_notified_together) { Fake_Configuration_Filesystem fs; fs.create_file(fs.rooted("quick-lint-js.config"), u8"{}"_sv); char token_1; @@ -2284,7 +2241,7 @@ TEST(Test_Configuration_Loader_Fake, fs.create_file(fs.rooted("quick-lint-js.config"), u8"{\"_svglobal-groups\": false}"_sv); - std::vector changes = loader.refresh(); + Span changes = loader.refresh(&this->allocator); std::vector tokens; for (Configuration_Change& change : changes) { tokens.push_back(change.token); @@ -2293,10 +2250,14 @@ TEST(Test_Configuration_Loader_Fake, ::testing::UnorderedElementsAreArray({&token_1, &token_2})); } -std::vector +Span Change_Detecting_Configuration_Loader::detect_changes_and_refresh() { +#if defined(_WIN32) + std::lock_guard lock(this->mutex_); +#endif bool fs_changed = this->detect_changes(); - std::vector config_changes = this->loader_.refresh(); + Span config_changes = + this->loader_.refresh(&this->allocator); if (fs_changed) { // NOTE(strager): We cannot assert that at least one change happened, // because filesystem notifications might be spurious.