From 89c02cfe81fdc04d172d6bb6b3a82c6709dac328 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Mon, 27 Sep 2021 17:34:49 -0700 Subject: [PATCH] Put lots of things in anonymous namespaces This is an attempt to help prevent ODR violations by making stuff local to a file, instead of emitting weak symbols. --- src/autoload.cpp | 2 + src/builtin_argparse.cpp | 2 + src/builtin_function.cpp | 2 + src/builtin_printf.cpp | 10 +-- src/builtin_read.cpp | 2 + src/builtin_set.cpp | 2 + src/builtin_status.cpp | 2 + src/builtin_string.cpp | 7 +- src/common.cpp | 6 +- src/complete.cpp | 156 +++++++++++++++++++-------------------- 10 files changed, 100 insertions(+), 91 deletions(-) diff --git a/src/autoload.cpp b/src/autoload.cpp index 156c13f0a..339c052ab 100644 --- a/src/autoload.cpp +++ b/src/autoload.cpp @@ -16,6 +16,7 @@ static const int kAutoloadStalenessInterval = 15; /// Represents a file that we might want to autoload. +namespace { struct autoloadable_file_t { /// The path to the file. wcstring path; @@ -23,6 +24,7 @@ struct autoloadable_file_t { /// The metadata for the file. file_id_t file_id; }; +} // namespace /// Class representing a cache of files that may be autoloaded. /// This is responsible for performing cached accesses to a set of paths. diff --git a/src/builtin_argparse.cpp b/src/builtin_argparse.cpp index 5783f83fa..75543969e 100644 --- a/src/builtin_argparse.cpp +++ b/src/builtin_argparse.cpp @@ -31,6 +31,7 @@ static const wcstring var_name_prefix = L"_flag_"; #define BUILTIN_ERR_INVALID_OPT_SPEC _(L"%ls: Invalid option spec '%ls' at char '%lc'\n") +namespace { struct option_spec_t { wchar_t short_flag; wcstring long_flag; @@ -58,6 +59,7 @@ struct argparse_cmd_opts_t { std::unordered_map long_to_short_flag; std::vector> exclusive_flag_sets; }; +} // namespace static const wchar_t *const short_options = L"+:hn:six:N:X:"; static const struct woption long_options[] = { diff --git a/src/builtin_function.cpp b/src/builtin_function.cpp index 241e08dec..56f5b6351 100644 --- a/src/builtin_function.cpp +++ b/src/builtin_function.cpp @@ -26,6 +26,7 @@ #include "wgetopt.h" #include "wutil.h" // IWYU pragma: keep +namespace { struct function_cmd_opts_t { bool print_help = false; bool shadow_scope = true; @@ -35,6 +36,7 @@ struct function_cmd_opts_t { wcstring_list_t inherit_vars; wcstring_list_t wrap_targets; }; +} // namespace // This command is atypical in using the "-" (RETURN_IN_ORDER) option for flag parsing. // This is needed due to the semantics of the -a/--argument-names flag. diff --git a/src/builtin_printf.cpp b/src/builtin_printf.cpp index 90fa3a116..57434225d 100644 --- a/src/builtin_printf.cpp +++ b/src/builtin_printf.cpp @@ -71,6 +71,7 @@ class parser_t; +namespace { struct builtin_printf_state_t { // Out and err streams. Note this is a captured reference! io_streams_t &streams; @@ -100,9 +101,9 @@ struct builtin_printf_state_t { void print_esc_char(wchar_t c); void append_output(wchar_t c); - void append_output(const wchar_t *c); void append_format_output(const wchar_t *fmt, ...); }; +} // namespace static bool is_octal_digit(wchar_t c) { return iswdigit(c) && c < L'8'; } @@ -237,13 +238,6 @@ void builtin_printf_state_t::append_output(wchar_t c) { streams.out.push_back(c); } -void builtin_printf_state_t::append_output(const wchar_t *c) { - // Don't output if we're done. - if (early_exit) return; - - streams.out.append(c); -} - void builtin_printf_state_t::append_format_output(const wchar_t *fmt, ...) { // Don't output if we're done. if (early_exit) return; diff --git a/src/builtin_read.cpp b/src/builtin_read.cpp index c51f50d30..58dfad570 100644 --- a/src/builtin_read.cpp +++ b/src/builtin_read.cpp @@ -35,6 +35,7 @@ #include "wgetopt.h" #include "wutil.h" // IWYU pragma: keep +namespace { struct read_cmd_opts_t { bool print_help = false; int place = ENV_USER; @@ -56,6 +57,7 @@ struct read_cmd_opts_t { int nchars = 0; bool one_line = false; }; +} // namespace static const wchar_t *const short_options = L":ac:d:fghiLln:p:sStuxzP:UR:L"; static const struct woption long_options[] = {{L"array", no_argument, nullptr, 'a'}, diff --git a/src/builtin_set.cpp b/src/builtin_set.cpp index 7d256daee..3067ae321 100644 --- a/src/builtin_set.cpp +++ b/src/builtin_set.cpp @@ -295,6 +295,7 @@ static int env_set_reporting_errors(const wchar_t *cmd, const wcstring &key, int return retval; } +namespace { /// A helper type returned by split_var_and_indexes. struct split_var_t { wcstring varname; // name of the variable @@ -304,6 +305,7 @@ struct split_var_t { /// \return the number of elements in our variable, or 0 if missing. long varsize() const { return var ? static_cast(var->as_list().size()) : 0L; } }; +} // namespace /// Extract indexes from an argument of the form `var_name[index1 index2...]`. /// The argument \p arg is split into a variable name and list of indexes, which is returned by diff --git a/src/builtin_status.cpp b/src/builtin_status.cpp index 2d873523c..f007ed4fd 100644 --- a/src/builtin_status.cpp +++ b/src/builtin_status.cpp @@ -95,6 +95,7 @@ static maybe_t job_control_str_to_mode(const wchar_t *mode, const return none(); } +namespace { struct status_cmd_opts_t { int level{1}; maybe_t new_job_control_mode{}; @@ -102,6 +103,7 @@ struct status_cmd_opts_t { status_cmd_t status_cmd{STATUS_UNDEF}; bool print_help{false}; }; +} // namespace /// Note: Do not add new flags that represent subcommands. We're encouraging people to switch to /// the non-flag subcommand form. While these flags are deprecated they must be supported at diff --git a/src/builtin_string.cpp b/src/builtin_string.cpp index b6cf4f936..c40c60b94 100644 --- a/src/builtin_string.cpp +++ b/src/builtin_string.cpp @@ -42,6 +42,8 @@ // This should be about the size of a line. #define STRING_CHUNK_SIZE 128 +namespace { + static void string_error(io_streams_t &streams, const wchar_t *fmt, ...) { streams.err.append(L"string "); va_list va; @@ -66,7 +68,6 @@ static const wchar_t *string_get_arg_argv(int *argidx, const wchar_t *const *arg } // A helper type for extracting arguments from either argv or stdin. -namespace { class arg_iterator_t { // The list of arguments passed to the string builtin. const wchar_t *const *argv_; @@ -132,7 +133,6 @@ class arg_iterator_t { } } }; -} // namespace // This is used by the string subcommands to communicate with the option parser which flags are // valid and get the result of parsing the command for flags. @@ -808,6 +808,7 @@ static int string_length(parser_t &parser, io_streams_t &streams, int argc, cons return nnonempty > 0 ? STATUS_CMD_OK : STATUS_CMD_ERROR; } +namespace { class string_matcher_t { protected: const options_t opts; @@ -1210,6 +1211,7 @@ class pcre2_matcher_t final : public string_matcher_t { bool is_valid() const override { return regex.is_valid(); } }; +} // namespace static int string_match(parser_t &parser, io_streams_t &streams, int argc, const wchar_t **argv) { const wchar_t *cmd = argv[0]; @@ -1881,6 +1883,7 @@ static constexpr const struct string_subcommand { {L"upper", &string_upper}, }; ASSERT_SORTED_BY_NAME(string_subcommands); +} // namespace /// The string builtin, for manipulating strings. maybe_t builtin_string(parser_t &parser, io_streams_t &streams, const wchar_t **argv) { diff --git a/src/common.cpp b/src/common.cpp index 391aa795b..ae5f7c071 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -242,7 +242,7 @@ bool is_windows_subsystem_for_linux() { /// alignment must be a power of 2 and in range [1, 64]. /// This is intended to return the end point of the "unaligned prefix" of a vectorized loop. template -inline const char *align_start(const char *start, size_t len) { +static inline const char *align_start(const char *start, size_t len) { static_assert(Align >= 1 && Align <= 64, "Alignment must be in range [1, 64]"); static_assert((Align & (Align - 1)) == 0, "Alignment must be power of 2"); uintptr_t startu = reinterpret_cast(start); @@ -262,7 +262,7 @@ inline const char *align_start(const char *start, size_t len) { /// If there is no such pointer, return \p start. /// This is intended to be the start point of the "unaligned suffix" of a vectorized loop. template -inline const char *align_end(const char *start, size_t len) { +static inline const char *align_end(const char *start, size_t len) { static_assert(Align >= 1 && Align <= 64, "Alignment must be in range [1, 64]"); static_assert((Align & (Align - 1)) == 0, "Alignment must be power of 2"); // How much do we have to subtract to align it? Its value, mod Align. @@ -617,7 +617,7 @@ static unsigned long long absolute_value(long long x) { } template -void format_safe_impl(CharT *buff, size_t size, unsigned long long val) { +static void format_safe_impl(CharT *buff, size_t size, unsigned long long val) { size_t idx = 0; if (val == 0) { buff[idx++] = '0'; diff --git a/src/complete.cpp b/src/complete.cpp index 2b2678891..10d8462d1 100644 --- a/src/complete.cpp +++ b/src/complete.cpp @@ -88,7 +88,7 @@ static const wcstring &C_(const wcstring &s) { return s; } /// If option is non-empty, it specifies a switch for the command. If \c comp is also not empty, it /// contains a list of non-switch arguments that may only follow directly after the specified /// switch. -using complete_entry_opt_t = struct complete_entry_opt { +struct complete_entry_opt_t { // Text of the option (like 'foo'). wcstring option; // Type of the option: args-oly, short, single_long, or double_long. @@ -139,16 +139,32 @@ class completion_entry_t { const unsigned int order; /// Getters for option list. - const option_list_t &get_options() const; + const option_list_t &get_options() const { return options; } /// Adds or removes an option. - void add_option(const complete_entry_opt_t &opt); + void add_option(const complete_entry_opt_t &opt) { options.push_front(opt); } bool remove_option(const wcstring &option, complete_option_type_t type); completion_entry_t(wcstring c, bool type) : cmd(std::move(c)), cmd_is_path(type), order(++k_complete_order) {} }; +/// Remove all completion options in the specified entry that match the specified short / long +/// option strings. Returns true if it is now empty and should be deleted, false if it's not empty. +/// Must be called while locked. +bool completion_entry_t::remove_option(const wcstring &option, complete_option_type_t type) { + auto iter = this->options.begin(); + while (iter != this->options.end()) { + if (iter->option == option && iter->type == type) { + iter = this->options.erase(iter); + } else { + // Just go to the next one. + ++iter; + } + } + return this->options.empty(); +} + /// Set of all completion entries. namespace std { template <> @@ -164,6 +180,7 @@ struct equal_to { return c1.cmd == c2.cmd; } }; + } // namespace std using completion_entry_set_t = std::unordered_set; static owning_lock s_completion_set; @@ -178,10 +195,6 @@ static bool compare_completions_by_order(const completion_entry_t &p1, return p1.order < p2.order; } -void completion_entry_t::add_option(const complete_entry_opt_t &opt) { options.push_front(opt); } - -const option_list_t &completion_entry_t::get_options() const { return options; } - description_func_t const_desc(const wcstring &s) { return [=](const wcstring &ignored) { UNUSED(ignored); @@ -343,6 +356,7 @@ void completions_sort_and_prioritize(completion_list_t *comps, completion_reques } } +namespace { /// Class representing an attempt to compute completions. class completer_t { /// The operation context for this completion. @@ -461,12 +475,6 @@ class completer_t { // Autoloader for completions. static owning_lock completion_autoloader{autoload_t(L"fish_complete_path")}; -/// Create a new completion entry. -void append_completion(completion_list_t *completions, wcstring comp, wcstring desc, - complete_flags_t flags, string_fuzzy_match_t match) { - completions->emplace_back(std::move(comp), std::move(desc), match, flags); -} - /// Test if the specified script returns zero. The result is cached, so that if multiple completions /// use the same condition, it needs only be evaluated once. condition_cache_clear must be called /// after a completion run to make sure that there are no stale completions. @@ -504,71 +512,6 @@ static completion_entry_t &complete_get_exact_entry(completion_entry_set_t &comp return const_cast(*ins.first); } -void complete_add(const wchar_t *cmd, bool cmd_is_path, const wcstring &option, - complete_option_type_t option_type, completion_mode_t result_mode, - const wchar_t *condition, const wchar_t *comp, const wchar_t *desc, - complete_flags_t flags) { - assert(cmd && "Null command"); - // option should be empty iff the option type is arguments only. - assert(option.empty() == (option_type == option_type_args_only)); - - // Lock the lock that allows us to edit the completion entry list. - auto completion_set = s_completion_set.acquire(); - completion_entry_t &c = complete_get_exact_entry(*completion_set, cmd, cmd_is_path); - - // Create our new option. - complete_entry_opt_t opt; - opt.option = option; - opt.type = option_type; - opt.result_mode = result_mode; - - if (comp) opt.comp = comp; - if (condition) opt.condition = condition; - if (desc) opt.desc = desc; - opt.flags = flags; - - c.add_option(opt); -} - -/// Remove all completion options in the specified entry that match the specified short / long -/// option strings. Returns true if it is now empty and should be deleted, false if it's not empty. -/// Must be called while locked. -bool completion_entry_t::remove_option(const wcstring &option, complete_option_type_t type) { - auto iter = this->options.begin(); - while (iter != this->options.end()) { - if (iter->option == option && iter->type == type) { - iter = this->options.erase(iter); - } else { - // Just go to the next one. - ++iter; - } - } - return this->options.empty(); -} - -void complete_remove(const wcstring &cmd, bool cmd_is_path, const wcstring &option, - complete_option_type_t type) { - auto completion_set = s_completion_set.acquire(); - - completion_entry_t tmp_entry(cmd, cmd_is_path); - auto iter = completion_set->find(tmp_entry); - if (iter != completion_set->end()) { - // const_cast: See SET_ELEMENTS_ARE_IMMUTABLE. - auto &entry = const_cast(*iter); - - bool delete_it = entry.remove_option(option, type); - if (delete_it) { - completion_set->erase(iter); - } - } -} - -void complete_remove_all(const wcstring &cmd, bool cmd_is_path) { - auto completion_set = s_completion_set.acquire(); - completion_entry_t tmp_entry(cmd, cmd_is_path); - completion_set->erase(tmp_entry); -} - /// Find the full path and commandname from a command string 'str'. static void parse_cmd_string(const wcstring &str, wcstring *path, wcstring *cmd, const environment_t &vars) { @@ -1760,6 +1703,63 @@ void completer_t::perform_for_commandline(wcstring cmdline) { mark_completions_duplicating_arguments(cmdline, current_token, tokens); } +} // namespace + +/// Create a new completion entry. +void append_completion(completion_list_t *completions, wcstring comp, wcstring desc, + complete_flags_t flags, string_fuzzy_match_t match) { + completions->emplace_back(std::move(comp), std::move(desc), match, flags); +} + +void complete_add(const wchar_t *cmd, bool cmd_is_path, const wcstring &option, + complete_option_type_t option_type, completion_mode_t result_mode, + const wchar_t *condition, const wchar_t *comp, const wchar_t *desc, + complete_flags_t flags) { + assert(cmd && "Null command"); + // option should be empty iff the option type is arguments only. + assert(option.empty() == (option_type == option_type_args_only)); + + // Lock the lock that allows us to edit the completion entry list. + auto completion_set = s_completion_set.acquire(); + completion_entry_t &c = complete_get_exact_entry(*completion_set, cmd, cmd_is_path); + + // Create our new option. + complete_entry_opt_t opt; + opt.option = option; + opt.type = option_type; + opt.result_mode = result_mode; + + if (comp) opt.comp = comp; + if (condition) opt.condition = condition; + if (desc) opt.desc = desc; + opt.flags = flags; + + c.add_option(opt); +} + +void complete_remove(const wcstring &cmd, bool cmd_is_path, const wcstring &option, + complete_option_type_t type) { + auto completion_set = s_completion_set.acquire(); + + completion_entry_t tmp_entry(cmd, cmd_is_path); + auto iter = completion_set->find(tmp_entry); + if (iter != completion_set->end()) { + // const_cast: See SET_ELEMENTS_ARE_IMMUTABLE. + auto &entry = const_cast(*iter); + + bool delete_it = entry.remove_option(option, type); + if (delete_it) { + completion_set->erase(iter); + } + } +} + +void complete_remove_all(const wcstring &cmd, bool cmd_is_path) { + auto completion_set = s_completion_set.acquire(); + completion_entry_t tmp_entry(cmd, cmd_is_path); + completion_set->erase(tmp_entry); +} + completion_list_t complete(const wcstring &cmd_with_subcmds, completion_request_flags_t flags, const operation_context_t &ctx) { // Determine the innermost subcommand.