blob: 2e622989f7688c0794e84e8063795437cb53f4e5 [file] [log] [blame]
// Copyright 2019 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.
#include <fidl/utils.h>
#include <regex>
namespace fidl {
namespace utils {
bool ends_with_underscore(const std::string& str) {
assert(str.size() > 0);
return str.back() == '_';
}
bool has_adjacent_underscores(const std::string& str) {
return str.find("__") != std::string::npos;
}
bool has_konstant_k(const std::string& str) {
return str.size() >= 2 && str[0] == 'k' && isupper(str[1]);
}
std::string strip_konstant_k(const std::string& str) {
if (has_konstant_k(str)) {
return str.substr(1);
} else {
return str;
}
}
bool is_lower_no_separator_case(const std::string& str) {
static std::regex re{"^[a-z][a-z0-9]*$"};
return str.size() > 0 && std::regex_match(str, re);
}
bool is_lower_snake_case(const std::string& str) {
static std::regex re{"^[a-z][a-z0-9_]*$"};
return str.size() > 0 && std::regex_match(str, re);
}
bool is_upper_snake_case(const std::string& str) {
static std::regex re{"^[A-Z][A-Z0-9_]*$"};
return str.size() > 0 && std::regex_match(str, re);
}
bool is_lower_camel_case(const std::string& str) {
if (has_konstant_k(str)) {
return false;
}
static std::regex re{"^[a-z][a-z0-9]*([A-Z][a-z0-9]+)*$"};
return str.size() > 0 && std::regex_match(str, re);
}
bool is_upper_camel_case(const std::string& str) {
static std::regex re{"^([A-Z][a-z0-9]+)+$"};
return str.size() > 0 && std::regex_match(str, re);
}
bool is_konstant_case(const std::string& astr) {
if (!has_konstant_k(astr)) {
return false;
}
std::string str = strip_konstant_k(astr);
return is_upper_camel_case(str);
}
static void add_word(std::string word, std::vector<std::string>& words,
const std::set<std::string>& stop_words) {
if (stop_words.find(word) == stop_words.end()) {
words.push_back(word);
}
}
std::vector<std::string> id_to_words(const std::string& astr) {
return id_to_words(astr, {});
}
std::vector<std::string> id_to_words(const std::string& astr, std::set<std::string> stop_words) {
// TODO(fxb/FIDL-573): Add support for mixed case with underscores, as in
// the example: const int kAndroid8_0_0 = 24; // Android 8.0.0
std::string str = strip_konstant_k(astr);
std::vector<std::string> words;
std::string word;
bool last_char_was_upper_or_begin = true;
for (size_t i = 0; i < str.size(); i++) {
char ch = str[i];
if (ch == '_' || ch == '-' || ch == '.') {
if (word.size() > 0) {
add_word(word, words, stop_words);
word.clear();
}
last_char_was_upper_or_begin = true;
} else {
bool next_char_is_lower = ((i + 1) < str.size()) &&
islower(str[i + 1]);
if (isupper(ch) &&
(!last_char_was_upper_or_begin || next_char_is_lower)) {
if (word.size() > 0) {
add_word(word, words, stop_words);
word.clear();
}
}
word.push_back(static_cast<char>(tolower(ch)));
last_char_was_upper_or_begin = isupper(ch);
}
}
if (word.size() > 0) {
add_word(word, words, stop_words);
}
return words;
}
std::string to_lower_no_separator_case(const std::string& astr) {
std::string str = strip_konstant_k(astr);
std::string newid;
for (const auto& word : id_to_words(str)) {
newid.append(word);
}
return newid;
}
std::string to_lower_snake_case(const std::string& astr) {
std::string str = strip_konstant_k(astr);
std::string newid;
for (const auto& word : id_to_words(str)) {
if (newid.size() > 0) {
newid.push_back('_');
}
newid.append(word);
}
return newid;
}
std::string to_upper_snake_case(const std::string& astr) {
std::string str = strip_konstant_k(astr);
auto newid = to_lower_snake_case(str);
std::transform(newid.begin(), newid.end(), newid.begin(), ::toupper);
return newid;
}
std::string to_lower_camel_case(const std::string& astr) {
std::string str = strip_konstant_k(astr);
std::string newid;
for (const auto& word : id_to_words(str)) {
if (newid.size() == 0) {
newid.append(word);
} else {
newid.push_back(static_cast<char>(toupper(word[0])));
newid.append(word.substr(1));
}
}
return newid;
}
std::string to_upper_camel_case(const std::string& astr) {
std::string str = strip_konstant_k(astr);
std::string newid;
for (const auto& word : id_to_words(str)) {
newid.push_back(static_cast<char>(toupper(word[0])));
newid.append(word.substr(1));
}
return newid;
}
std::string to_konstant_case(const std::string& str) {
return "k" + to_upper_camel_case(str);
}
void PrintFinding(std::ostream& os, const Finding& finding) {
os << finding.message();
if (finding.suggestion().has_value()) {
auto& suggestion = finding.suggestion();
os << "; " << suggestion->description();
if (suggestion->replacement().has_value()) {
os << "\nDid you mean:\n "
<< *suggestion->replacement();
}
}
}
void WriteFindingsToErrorReporter(const Findings& findings,
ErrorReporter* error_reporter) {
for (auto& finding : findings) {
std::stringstream ss;
PrintFinding(ss, finding);
error_reporter->ReportWarningWithSquiggle(finding.source_location(),
ss.str());
}
}
} // namespace utils
} // namespace fidl