OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "Renamer.h" |
| 6 |
| 7 #include <assert.h> |
| 8 |
| 9 #include "clang/Basic/CharInfo.h" |
| 10 #include "llvm/ADT/SmallVector.h" |
| 11 |
| 12 namespace { |
| 13 |
| 14 enum class Case { |
| 15 NEITHER, |
| 16 LOWER, |
| 17 UPPER, |
| 18 }; |
| 19 |
| 20 using WordList = llvm::SmallVector<llvm::StringRef, 6>; |
| 21 |
| 22 Case DetermineCase(char c) { |
| 23 if (clang::isUppercase(c)) |
| 24 return Case::UPPER; |
| 25 if (clang::isLowercase(c)) |
| 26 return Case::LOWER; |
| 27 return Case::NEITHER; |
| 28 } |
| 29 |
| 30 // True if the input only contains letters of one case. |
| 31 bool CanSplitWithUnderscores(llvm::StringRef input) { |
| 32 Case expected_case = Case::NEITHER; |
| 33 for (size_t i = 0; i < input.size(); ++i) { |
| 34 Case current_case = DetermineCase(input[i]); |
| 35 if (expected_case == Case::NEITHER) { |
| 36 expected_case = current_case; |
| 37 continue; |
| 38 } |
| 39 if (current_case == Case::NEITHER) |
| 40 continue; |
| 41 if (expected_case != current_case) |
| 42 return false; |
| 43 } |
| 44 return true; |
| 45 } |
| 46 |
| 47 WordList SplitWithUnderscores(llvm::StringRef input) { |
| 48 WordList output; |
| 49 input.split(output, "_", -1, false /*KeepEmpty*/); |
| 50 return output; |
| 51 } |
| 52 |
| 53 // Most identifiers in Blink use CamelCase, but some (incorrectly) mix in |
| 54 // underscores. In that case, split into words, using uppercase letters and |
| 55 // underscores signal the start of the next word, while trying to handle |
| 56 // acronyms. |
| 57 WordList SplitWithHeuristics(llvm::StringRef input) { |
| 58 WordList output; |
| 59 for (size_t i = 0; i < input.size();) { |
| 60 size_t start = i; |
| 61 size_t end = input.size(); |
| 62 Case previous_case = DetermineCase(input[start]); |
| 63 bool in_acronym = false; |
| 64 |
| 65 // Find the next "meaningful" uppercase letter or underscore. |
| 66 for (++i; i < input.size(); ++i) { |
| 67 // Underscore case: assume underscores always separate two words. |
| 68 if (input[i] == '_') { |
| 69 end = i; |
| 70 ++i; // Skip the underscore. |
| 71 break; |
| 72 } |
| 73 |
| 74 Case current_case = DetermineCase(input[i]); |
| 75 // Non-acronym case: the next uppercase letter is the beginning of the |
| 76 // next word. |
| 77 if (previous_case != Case::UPPER && current_case == Case::UPPER) { |
| 78 end = i; |
| 79 break; |
| 80 } |
| 81 // End of ACRONYM case: |
| 82 if (in_acronym && previous_case == Case::UPPER && |
| 83 current_case == Case::LOWER) { |
| 84 --i; // Already iterated into the next word, so backtrack. |
| 85 end = i; |
| 86 break; |
| 87 } |
| 88 // Seeing a non-uppercase letter after an uppercase letter means this is |
| 89 // probably part of an acronym. |
| 90 if (previous_case == Case::UPPER && current_case != Case::LOWER) { |
| 91 in_acronym = true; |
| 92 // Intentionally fallthrough, so casing state is updated. |
| 93 } |
| 94 |
| 95 previous_case = current_case; |
| 96 } |
| 97 // TODO(dcheng): Special acronym handling here. |
| 98 output.emplace_back(input.substr(start, end - start)); |
| 99 } |
| 100 return output; |
| 101 } |
| 102 |
| 103 WordList SplitIdentifier(llvm::StringRef input) { |
| 104 assert(input.size() > 0); |
| 105 |
| 106 if (CanSplitWithUnderscores(input)) |
| 107 return SplitWithUnderscores(input); |
| 108 |
| 109 return SplitWithHeuristics(input); |
| 110 } |
| 111 |
| 112 } // namespace |
| 113 |
| 114 std::string IdentifierToCamelCase(llvm::StringRef input) { |
| 115 WordList words = SplitIdentifier(input); |
| 116 std::string output; |
| 117 for (const auto& word : words) { |
| 118 output += clang::toUppercase(word[0]); |
| 119 for (size_t i = 1; i < word.size(); ++i) |
| 120 output += clang::toLowercase(word[i]); |
| 121 } |
| 122 return output; |
| 123 } |
| 124 |
| 125 std::string IdentifierToUnderscoreCase(llvm::StringRef input) { |
| 126 WordList words = SplitIdentifier(input); |
| 127 std::string output; |
| 128 for (const auto& word : words) { |
| 129 if (!output.empty()) |
| 130 output += '_'; |
| 131 for (size_t i = 0; i < word.size(); ++i) |
| 132 output += clang::toLowercase(word[i]); |
| 133 } |
| 134 return output; |
| 135 } |
| 136 |
| 137 std::string identifierToShoutyCase(llvm::StringRef input) { |
| 138 WordList words = SplitIdentifier(input); |
| 139 std::string output; |
| 140 for (const auto& word : words) { |
| 141 if (!output.empty()) |
| 142 output += '_'; |
| 143 for (size_t i = 0; i < word.size(); ++i) |
| 144 output += clang::toUppercase(word[i]); |
| 145 } |
| 146 return output; |
| 147 } |
OLD | NEW |