generator_helpers.h 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /*
  2. *
  3. * Copyright 2015 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. #ifndef GRPC_INTERNAL_COMPILER_GENERATOR_HELPERS_H
  19. #define GRPC_INTERNAL_COMPILER_GENERATOR_HELPERS_H
  20. #include <iostream>
  21. #include <map>
  22. #include <sstream>
  23. #include <string>
  24. #include <vector>
  25. #include "src/compiler/config.h"
  26. namespace grpc_generator {
  27. inline bool StripSuffix(grpc::string* filename, const grpc::string& suffix) {
  28. if (filename->length() >= suffix.length()) {
  29. size_t suffix_pos = filename->length() - suffix.length();
  30. if (filename->compare(suffix_pos, grpc::string::npos, suffix) == 0) {
  31. filename->resize(filename->size() - suffix.size());
  32. return true;
  33. }
  34. }
  35. return false;
  36. }
  37. inline bool StripPrefix(grpc::string* name, const grpc::string& prefix) {
  38. if (name->length() >= prefix.length()) {
  39. if (name->substr(0, prefix.size()) == prefix) {
  40. *name = name->substr(prefix.size());
  41. return true;
  42. }
  43. }
  44. return false;
  45. }
  46. inline grpc::string StripProto(grpc::string filename) {
  47. if (!StripSuffix(&filename, ".protodevel")) {
  48. StripSuffix(&filename, ".proto");
  49. }
  50. return filename;
  51. }
  52. inline grpc::string StringReplace(grpc::string str, const grpc::string& from,
  53. const grpc::string& to, bool replace_all) {
  54. size_t pos = 0;
  55. do {
  56. pos = str.find(from, pos);
  57. if (pos == grpc::string::npos) {
  58. break;
  59. }
  60. str.replace(pos, from.length(), to);
  61. pos += to.length();
  62. } while (replace_all);
  63. return str;
  64. }
  65. inline grpc::string StringReplace(grpc::string str, const grpc::string& from,
  66. const grpc::string& to) {
  67. return StringReplace(str, from, to, true);
  68. }
  69. inline std::vector<grpc::string> tokenize(const grpc::string& input,
  70. const grpc::string& delimiters) {
  71. std::vector<grpc::string> tokens;
  72. size_t pos, last_pos = 0;
  73. for (;;) {
  74. bool done = false;
  75. pos = input.find_first_of(delimiters, last_pos);
  76. if (pos == grpc::string::npos) {
  77. done = true;
  78. pos = input.length();
  79. }
  80. tokens.push_back(input.substr(last_pos, pos - last_pos));
  81. if (done) return tokens;
  82. last_pos = pos + 1;
  83. }
  84. }
  85. inline grpc::string CapitalizeFirstLetter(grpc::string s) {
  86. if (s.empty()) {
  87. return s;
  88. }
  89. s[0] = ::toupper(s[0]);
  90. return s;
  91. }
  92. inline grpc::string LowercaseFirstLetter(grpc::string s) {
  93. if (s.empty()) {
  94. return s;
  95. }
  96. s[0] = ::tolower(s[0]);
  97. return s;
  98. }
  99. inline grpc::string LowerUnderscoreToUpperCamel(grpc::string str) {
  100. std::vector<grpc::string> tokens = tokenize(str, "_");
  101. grpc::string result = "";
  102. for (unsigned int i = 0; i < tokens.size(); i++) {
  103. result += CapitalizeFirstLetter(tokens[i]);
  104. }
  105. return result;
  106. }
  107. inline grpc::string FileNameInUpperCamel(
  108. const grpc::protobuf::FileDescriptor* file, bool include_package_path) {
  109. std::vector<grpc::string> tokens = tokenize(StripProto(file->name()), "/");
  110. grpc::string result = "";
  111. if (include_package_path) {
  112. for (unsigned int i = 0; i < tokens.size() - 1; i++) {
  113. result += tokens[i] + "/";
  114. }
  115. }
  116. result += LowerUnderscoreToUpperCamel(tokens.back());
  117. return result;
  118. }
  119. inline grpc::string FileNameInUpperCamel(
  120. const grpc::protobuf::FileDescriptor* file) {
  121. return FileNameInUpperCamel(file, true);
  122. }
  123. enum MethodType {
  124. METHODTYPE_NO_STREAMING,
  125. METHODTYPE_CLIENT_STREAMING,
  126. METHODTYPE_SERVER_STREAMING,
  127. METHODTYPE_BIDI_STREAMING
  128. };
  129. inline MethodType GetMethodType(
  130. const grpc::protobuf::MethodDescriptor* method) {
  131. if (method->client_streaming()) {
  132. if (method->server_streaming()) {
  133. return METHODTYPE_BIDI_STREAMING;
  134. } else {
  135. return METHODTYPE_CLIENT_STREAMING;
  136. }
  137. } else {
  138. if (method->server_streaming()) {
  139. return METHODTYPE_SERVER_STREAMING;
  140. } else {
  141. return METHODTYPE_NO_STREAMING;
  142. }
  143. }
  144. }
  145. inline void Split(const grpc::string& s, char delim,
  146. std::vector<grpc::string>* append_to) {
  147. std::istringstream iss(s);
  148. grpc::string piece;
  149. while (std::getline(iss, piece)) {
  150. append_to->push_back(piece);
  151. }
  152. }
  153. enum CommentType {
  154. COMMENTTYPE_LEADING,
  155. COMMENTTYPE_TRAILING,
  156. COMMENTTYPE_LEADING_DETACHED
  157. };
  158. // Get all the raw comments and append each line without newline to out.
  159. template <typename DescriptorType>
  160. inline void GetComment(const DescriptorType* desc, CommentType type,
  161. std::vector<grpc::string>* out) {
  162. grpc::protobuf::SourceLocation location;
  163. if (!desc->GetSourceLocation(&location)) {
  164. return;
  165. }
  166. if (type == COMMENTTYPE_LEADING || type == COMMENTTYPE_TRAILING) {
  167. const grpc::string& comments = type == COMMENTTYPE_LEADING
  168. ? location.leading_comments
  169. : location.trailing_comments;
  170. Split(comments, '\n', out);
  171. } else if (type == COMMENTTYPE_LEADING_DETACHED) {
  172. for (unsigned int i = 0; i < location.leading_detached_comments.size();
  173. i++) {
  174. Split(location.leading_detached_comments[i], '\n', out);
  175. out->push_back("");
  176. }
  177. } else {
  178. std::cerr << "Unknown comment type " << type << std::endl;
  179. abort();
  180. }
  181. }
  182. // Each raw comment line without newline is appended to out.
  183. // For file level leading and detached leading comments, we return comments
  184. // above syntax line. Return nothing for trailing comments.
  185. template <>
  186. inline void GetComment(const grpc::protobuf::FileDescriptor* desc,
  187. CommentType type, std::vector<grpc::string>* out) {
  188. if (type == COMMENTTYPE_TRAILING) {
  189. return;
  190. }
  191. grpc::protobuf::SourceLocation location;
  192. std::vector<int> path;
  193. path.push_back(grpc::protobuf::FileDescriptorProto::kSyntaxFieldNumber);
  194. if (!desc->GetSourceLocation(path, &location)) {
  195. return;
  196. }
  197. if (type == COMMENTTYPE_LEADING) {
  198. Split(location.leading_comments, '\n', out);
  199. } else if (type == COMMENTTYPE_LEADING_DETACHED) {
  200. for (unsigned int i = 0; i < location.leading_detached_comments.size();
  201. i++) {
  202. Split(location.leading_detached_comments[i], '\n', out);
  203. out->push_back("");
  204. }
  205. } else {
  206. std::cerr << "Unknown comment type " << type << std::endl;
  207. abort();
  208. }
  209. }
  210. // Add prefix and newline to each comment line and concatenate them together.
  211. // Make sure there is a space after the prefix unless the line is empty.
  212. inline grpc::string GenerateCommentsWithPrefix(
  213. const std::vector<grpc::string>& in, const grpc::string& prefix) {
  214. std::ostringstream oss;
  215. for (auto it = in.begin(); it != in.end(); it++) {
  216. const grpc::string& elem = *it;
  217. if (elem.empty()) {
  218. oss << prefix << "\n";
  219. } else if (elem[0] == ' ') {
  220. oss << prefix << elem << "\n";
  221. } else {
  222. oss << prefix << " " << elem << "\n";
  223. }
  224. }
  225. return oss.str();
  226. }
  227. template <typename DescriptorType>
  228. inline grpc::string GetPrefixedComments(const DescriptorType* desc,
  229. bool leading,
  230. const grpc::string& prefix) {
  231. std::vector<grpc::string> out;
  232. if (leading) {
  233. grpc_generator::GetComment(
  234. desc, grpc_generator::COMMENTTYPE_LEADING_DETACHED, &out);
  235. std::vector<grpc::string> leading;
  236. grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_LEADING,
  237. &leading);
  238. out.insert(out.end(), leading.begin(), leading.end());
  239. } else {
  240. grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_TRAILING,
  241. &out);
  242. }
  243. return GenerateCommentsWithPrefix(out, prefix);
  244. }
  245. } // namespace grpc_generator
  246. #endif // GRPC_INTERNAL_COMPILER_GENERATOR_HELPERS_H