1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "generator/internal/service_code_generator.h"
16 #include "google/cloud/internal/absl_str_cat_quiet.h"
17 #include "google/cloud/internal/absl_str_replace_quiet.h"
18 #include "google/cloud/log.h"
19 #include "absl/memory/memory.h"
20 #include "absl/strings/str_split.h"
21 #include "absl/strings/strip.h"
22 #include "generator/internal/codegen_utils.h"
23 #include "generator/internal/printer.h"
24 #include <google/api/client.pb.h>
25 #include <google/protobuf/descriptor.h>
26
27 namespace google {
28 namespace cloud {
29 namespace generator_internal {
30
ServiceCodeGenerator(std::string const & header_path_key,std::string const & cc_path_key,google::protobuf::ServiceDescriptor const * service_descriptor,VarsDictionary service_vars,std::map<std::string,VarsDictionary> service_method_vars,google::protobuf::compiler::GeneratorContext * context)31 ServiceCodeGenerator::ServiceCodeGenerator(
32 std::string const& header_path_key, std::string const& cc_path_key,
33 google::protobuf::ServiceDescriptor const* service_descriptor,
34 VarsDictionary service_vars,
35 std::map<std::string, VarsDictionary> service_method_vars,
36 google::protobuf::compiler::GeneratorContext* context)
37 : service_descriptor_(service_descriptor),
38 service_vars_(std::move(service_vars)),
39 service_method_vars_(std::move(service_method_vars)),
40 header_(context, service_vars_[header_path_key]),
41 cc_(context, service_vars_[cc_path_key]) {
42 assert(service_descriptor != nullptr);
43 assert(context != nullptr);
44 SetVars(service_vars_[header_path_key]);
45 for (int i = 0; i < service_descriptor_->method_count(); ++i) {
46 methods_.emplace_back(*service_descriptor_->method(i));
47 }
48 }
49
ServiceCodeGenerator(std::string const & header_path_key,google::protobuf::ServiceDescriptor const * service_descriptor,VarsDictionary service_vars,std::map<std::string,VarsDictionary> service_method_vars,google::protobuf::compiler::GeneratorContext * context)50 ServiceCodeGenerator::ServiceCodeGenerator(
51 std::string const& header_path_key,
52 google::protobuf::ServiceDescriptor const* service_descriptor,
53 VarsDictionary service_vars,
54 std::map<std::string, VarsDictionary> service_method_vars,
55 google::protobuf::compiler::GeneratorContext* context)
56 : service_descriptor_(service_descriptor),
57 service_vars_(std::move(service_vars)),
58 service_method_vars_(std::move(service_method_vars)),
59 header_(context, service_vars_[header_path_key]) {
60 assert(service_descriptor != nullptr);
61 assert(context != nullptr);
62 SetVars(service_vars_[header_path_key]);
63 for (int i = 0; i < service_descriptor_->method_count(); ++i) {
64 methods_.emplace_back(*service_descriptor_->method(i));
65 }
66 }
67
vars() const68 VarsDictionary const& ServiceCodeGenerator::vars() const {
69 return service_vars_;
70 }
71
vars(std::string const & key) const72 std::string ServiceCodeGenerator::vars(std::string const& key) const {
73 auto iter = service_vars_.find(key);
74 if (iter == service_vars_.end()) {
75 GCP_LOG(FATAL) << key << " not found in service_vars_\n";
76 }
77 return iter->second;
78 }
79
80 std::vector<
81 std::reference_wrapper<google::protobuf::MethodDescriptor const>> const&
methods() const82 ServiceCodeGenerator::methods() const {
83 return methods_;
84 }
85
MergeServiceAndMethodVars(google::protobuf::MethodDescriptor const & method) const86 VarsDictionary ServiceCodeGenerator::MergeServiceAndMethodVars(
87 google::protobuf::MethodDescriptor const& method) const {
88 auto vars = service_vars_;
89 vars.insert(service_method_vars_.at(method.full_name()).begin(),
90 service_method_vars_.at(method.full_name()).end());
91 return vars;
92 }
93
HeaderLocalIncludes(std::vector<std::string> const & local_includes)94 void ServiceCodeGenerator::HeaderLocalIncludes(
95 std::vector<std::string> const& local_includes) {
96 GenerateLocalIncludes(header_, local_includes);
97 }
98
CcLocalIncludes(std::vector<std::string> const & local_includes)99 void ServiceCodeGenerator::CcLocalIncludes(
100 std::vector<std::string> const& local_includes) {
101 GenerateLocalIncludes(cc_, local_includes, FileType::kCcFile);
102 }
103
HeaderSystemIncludes(std::vector<std::string> const & system_includes)104 void ServiceCodeGenerator::HeaderSystemIncludes(
105 std::vector<std::string> const& system_includes) {
106 GenerateSystemIncludes(header_, system_includes);
107 }
108
CcSystemIncludes(std::vector<std::string> const & system_includes)109 void ServiceCodeGenerator::CcSystemIncludes(
110 std::vector<std::string> const& system_includes) {
111 GenerateSystemIncludes(cc_, system_includes);
112 }
113
HeaderOpenNamespaces(NamespaceType ns_type)114 Status ServiceCodeGenerator::HeaderOpenNamespaces(NamespaceType ns_type) {
115 return OpenNamespaces(header_, ns_type);
116 }
117
HeaderCloseNamespaces()118 void ServiceCodeGenerator::HeaderCloseNamespaces() { CloseNamespaces(header_); }
119
CcOpenNamespaces(NamespaceType ns_type)120 Status ServiceCodeGenerator::CcOpenNamespaces(NamespaceType ns_type) {
121 return OpenNamespaces(cc_, ns_type);
122 }
123
CcCloseNamespaces()124 void ServiceCodeGenerator::CcCloseNamespaces() { CloseNamespaces(cc_); }
125
HeaderPrint(std::string const & text)126 void ServiceCodeGenerator::HeaderPrint(std::string const& text) {
127 header_.Print(service_vars_, text);
128 }
129
HeaderPrintMethod(google::protobuf::MethodDescriptor const & method,std::vector<MethodPattern> const & patterns,char const * file,int line)130 Status ServiceCodeGenerator::HeaderPrintMethod(
131 google::protobuf::MethodDescriptor const& method,
132 std::vector<MethodPattern> const& patterns, char const* file, int line) {
133 return PrintMethod(method, header_, MergeServiceAndMethodVars(method),
134 patterns, file, line);
135 }
136
CcPrint(std::string const & text)137 void ServiceCodeGenerator::CcPrint(std::string const& text) {
138 cc_.Print(service_vars_, text);
139 }
140
CcPrintMethod(google::protobuf::MethodDescriptor const & method,std::vector<MethodPattern> const & patterns,char const * file,int line)141 Status ServiceCodeGenerator::CcPrintMethod(
142 google::protobuf::MethodDescriptor const& method,
143 std::vector<MethodPattern> const& patterns, char const* file, int line) {
144 return PrintMethod(method, cc_, MergeServiceAndMethodVars(method), patterns,
145 file, line);
146 }
147
GenerateLocalIncludes(Printer & p,std::vector<std::string> local_includes,FileType file_type)148 void ServiceCodeGenerator::GenerateLocalIncludes(
149 Printer& p, std::vector<std::string> local_includes, FileType file_type) {
150 if (file_type == FileType::kCcFile) {
151 std::sort(local_includes.begin() + 1, local_includes.end());
152 } else {
153 std::sort(local_includes.begin(), local_includes.end());
154 }
155 for (auto const& include : local_includes) {
156 p.Print(LocalInclude(include));
157 }
158 }
159
GenerateSystemIncludes(Printer & p,std::vector<std::string> system_includes)160 void ServiceCodeGenerator::GenerateSystemIncludes(
161 Printer& p, std::vector<std::string> system_includes) {
162 std::sort(system_includes.begin(), system_includes.end());
163 for (auto const& include : system_includes) {
164 p.Print(SystemInclude(include));
165 }
166 }
167
OpenNamespaces(Printer & p,NamespaceType ns_type)168 Status ServiceCodeGenerator::OpenNamespaces(Printer& p, NamespaceType ns_type) {
169 auto result = service_vars_.find("product_path");
170 if (result == service_vars_.end()) {
171 return Status(StatusCode::kInternal, "product_path not found in vars");
172 }
173 namespaces_ = BuildNamespaces(service_vars_["product_path"], ns_type);
174 for (auto const& nspace : namespaces_) {
175 if (nspace == "GOOGLE_CLOUD_CPP_NS") {
176 p.Print("inline namespace $namespace$ {\n", "namespace", nspace);
177 } else {
178 p.Print("namespace $namespace$ {\n", "namespace", nspace);
179 }
180 }
181 p.Print("\n");
182 return {};
183 }
184
CloseNamespaces(Printer & p)185 void ServiceCodeGenerator::CloseNamespaces(Printer& p) {
186 for (auto iter = namespaces_.rbegin(); iter != namespaces_.rend(); ++iter) {
187 p.Print("} // namespace $namespace$\n", "namespace", *iter);
188 }
189 p.Print("\n");
190 }
191
Generate()192 Status ServiceCodeGenerator::Generate() {
193 auto result = GenerateHeader();
194 if (!result.ok()) return result;
195 return GenerateCc();
196 }
197
SetVars(absl::string_view header_path)198 void ServiceCodeGenerator::SetVars(absl::string_view header_path) {
199 service_vars_["header_include_guard"] = absl::StrCat(
200 "GOOGLE_CLOUD_CPP_", absl::AsciiStrToUpper(absl::StrReplaceAll(
201 header_path, {{"/", "_"}, {".", "_"}})));
202 }
203
204 } // namespace generator_internal
205 } // namespace cloud
206 } // namespace google
207