| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef TOOLS_FIDL_FIDLC_INCLUDE_FIDL_UTILS_H_ |
| #define TOOLS_FIDL_FIDLC_INCLUDE_FIDL_UTILS_H_ |
| |
| #include <errno.h> |
| |
| #include <clocale> |
| #include <cstring> |
| #include <regex> |
| #include <set> |
| #include <string> |
| #include <string_view> |
| |
| #include <fidl/findings.h> |
| #include <fidl/reporter.h> |
| |
| namespace fidl { |
| namespace utils { |
| |
| // An enumeration of supported syntaxes for the purposes of the ongoing |
| // old-to-new migration. The kOld represents the syntax as of Jan 1, 2021 and |
| // the kNew is the new syntax per FTP-050 and its amendments. |
| // TODO(fxbug.dev/70247): Remove this when old syntax support is removed |
| enum struct Syntax { |
| kOld, |
| kNew, |
| }; |
| |
| template <class> |
| inline constexpr bool always_false_v = false; |
| |
| // Helper object for creating a callable argument to std::visit by passing in |
| // lambdas for handling each variant (code comes from |
| // https://en.cppreference.com/w/cpp/utility/variant/visit) |
| template <class... Ts> |
| struct matchers : Ts... { |
| using Ts::operator()...; |
| }; |
| template <class... Ts> |
| matchers(Ts...) -> matchers<Ts...>; |
| |
| using reporter::Reporter; |
| |
| constexpr char kWhitespaceChars[] = " \t\n\v\f\r"; |
| constexpr char kWhitespaceNoNewlineChars[] = " \t\v\f\r"; |
| |
| inline bool IsWhitespace(char ch) { return ch != '\0' && strchr(kWhitespaceChars, ch) != nullptr; } |
| |
| inline bool IsWhitespaceNoNewline(char ch) { |
| return ch != '\0' && strchr(kWhitespaceNoNewlineChars, ch) != nullptr; |
| } |
| |
| // Returns true if the view has anything other than whitespace |
| inline bool IsBlank(std::string_view view) { |
| return view.find_first_not_of(kWhitespaceChars) == std::string::npos; |
| } |
| |
| // IsValidLibraryComponent validates individual components of a library |
| // identifier. |
| // |
| // See https://fuchsia.dev/fuchsia-src/reference/fidl/language/language#identifiers |
| bool IsValidLibraryComponent(const std::string& component); |
| |
| // IsValidIdentifierComponent validates individual components of an identifier |
| // (other than a library identifier). |
| // |
| // See https://fuchsia.dev/fuchsia-src/reference/fidl/language/language#identifiers |
| bool IsValidIdentifierComponent(const std::string& component); |
| |
| // IsValidFullyQualifiedMethodIdentifier validates fully qualified method |
| // identifiers, i.e. a library identifier, followed by a slash, followed by a |
| // protocol identifier, a dot, and lastly the method name. |
| bool IsValidFullyQualifiedMethodIdentifier(const std::string& fq_identifier); |
| |
| inline bool LineFromOffsetIsBlank(const std::string& str, size_t offset) { |
| for (size_t i = offset; i < str.size() && str[i] != '\n'; i++) { |
| if (!IsWhitespaceNoNewline(str[i])) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| inline bool FirstLineIsBlank(const std::string& str) { return LineFromOffsetIsBlank(str, 0); } |
| |
| inline bool LineFromOffsetIsRegularComment(std::string_view view, size_t offset) { |
| size_t i = offset; |
| if ((i + 1 < view.size()) && view[i] == '/' && view[i + 1] == '/') { |
| // Doc comments, which start with three slashes, should not |
| // be treated as comments since they get internally converted |
| // to attributes. But comments that start with more than three |
| // slashes are not converted to doc comment attributes. |
| if (view.size() == 2) { |
| return true; |
| } else { |
| return (i + 2 == view.size()) || (view[i + 2] != '/') || |
| ((i + 3 < view.size()) && (view[i + 3] == '/')); |
| } |
| } else { |
| return false; |
| } |
| } |
| |
| inline bool FirstLineIsRegularComment(std::string_view view) { |
| return LineFromOffsetIsRegularComment(view, 0); |
| } |
| |
| enum class ParseNumericResult { |
| kSuccess, |
| kOutOfBounds, |
| kMalformed, |
| }; |
| |
| template <typename NumericType> |
| ParseNumericResult ParseNumeric(const std::string& input, NumericType* out_value, int base = 0) { |
| assert(out_value != nullptr); |
| |
| // Set locale to "C" for numeric types, since all strtox() functions are locale-dependent |
| setlocale(LC_NUMERIC, "C"); |
| |
| const char* startptr = input.data(); |
| if (base == 0 && 2 < input.size() && input[0] == '0' && (input[1] == 'b' || input[1] == 'B')) { |
| startptr += 2; |
| base = 2; |
| } |
| char* endptr; |
| if constexpr (std::is_unsigned<NumericType>::value) { |
| if (input[0] == '-') |
| return ParseNumericResult::kOutOfBounds; |
| errno = 0; |
| unsigned long long value = strtoull(startptr, &endptr, base); |
| if (errno != 0) |
| return ParseNumericResult::kMalformed; |
| if (value > std::numeric_limits<NumericType>::max()) |
| return ParseNumericResult::kOutOfBounds; |
| *out_value = static_cast<NumericType>(value); |
| } else if constexpr (std::is_floating_point<NumericType>::value) { |
| errno = 0; |
| long double value = strtold(startptr, &endptr); |
| if (errno != 0) |
| return ParseNumericResult::kMalformed; |
| if (value > std::numeric_limits<NumericType>::max()) |
| return ParseNumericResult::kOutOfBounds; |
| if (value < std::numeric_limits<NumericType>::lowest()) |
| return ParseNumericResult::kOutOfBounds; |
| *out_value = static_cast<NumericType>(value); |
| } else { |
| errno = 0; |
| long long value = strtoll(startptr, &endptr, base); |
| if (errno != 0) |
| return ParseNumericResult::kMalformed; |
| if (value > std::numeric_limits<NumericType>::max()) |
| return ParseNumericResult::kOutOfBounds; |
| if (value < std::numeric_limits<NumericType>::lowest()) |
| return ParseNumericResult::kOutOfBounds; |
| *out_value = static_cast<NumericType>(value); |
| } |
| if (endptr != (input.c_str() + input.size())) |
| return ParseNumericResult::kMalformed; |
| return ParseNumericResult::kSuccess; |
| } |
| |
| bool ends_with_underscore(const std::string& str); |
| bool has_adjacent_underscores(const std::string& str); |
| |
| std::vector<std::string> id_to_words(const std::string& str); |
| |
| // Split the identifier into words, excluding words in the |stop_words| set. |
| std::vector<std::string> id_to_words(const std::string& str, |
| const std::set<std::string> stop_words); |
| |
| bool is_konstant_case(const std::string& str); |
| bool is_lower_no_separator_case(const std::string& str); |
| bool is_lower_snake_case(const std::string& str); |
| bool is_upper_snake_case(const std::string& str); |
| bool is_lower_camel_case(const std::string& str); |
| bool is_upper_camel_case(const std::string& str); |
| |
| std::string strip_konstant_k(const std::string& str); |
| std::string to_konstant_case(const std::string& str); |
| std::string to_lower_no_separator_case(const std::string& str); |
| std::string to_lower_snake_case(const std::string& str); |
| std::string to_upper_snake_case(const std::string& str); |
| std::string to_lower_camel_case(const std::string& str); |
| std::string to_upper_camel_case(const std::string& str); |
| |
| // Returns the canonical form of an identifier, used to detect name collisions |
| // in FIDL libraries. For example, the identifers "FooBar" and "FOO_BAR" collide |
| // because canonicalize returns "foo_bar" for both. |
| std::string canonicalize(std::string_view identifier); |
| |
| // Used by fidl-lint FormatFindings, and for testing, |
| // this generates the linter error message string in the format |
| // required for the fidl::Reporter. |
| void PrintFinding(std::ostream& os, const Finding& finding); |
| |
| // Used by fidl-lint main() and for testing, this generates the linter error |
| // messages for a list of findings. |
| std::vector<std::string> FormatFindings(const Findings& findings, bool enable_color); |
| |
| // Gets a string with the original file contents, and a string with the |
| // formatted file, and makes sure that the only difference is in the whitespace. |
| // Used by the formatter to make sure that formatting was not destructive. |
| bool OnlyWhitespaceChanged(const std::string& unformatted_input, |
| const std::string& formatted_output); |
| |
| } // namespace utils |
| } // namespace fidl |
| |
| #endif // TOOLS_FIDL_FIDLC_INCLUDE_FIDL_UTILS_H_ |