• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 // Author: kenton@google.com (Kenton Varda)
32 //  Based on original Protocol Buffers design by
33 //  Sanjay Ghemawat, Jeff Dean, and others.
34 
35 #include <google/protobuf/compiler/cpp/cpp_extension.h>
36 #include <map>
37 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
38 #include <google/protobuf/descriptor.pb.h>
39 #include <google/protobuf/io/printer.h>
40 #include <google/protobuf/stubs/strutil.h>
41 
42 
43 
44 namespace google {
45 namespace protobuf {
46 namespace compiler {
47 namespace cpp {
48 
49 namespace {
50 
51 // Returns the fully-qualified class name of the message that this field
52 // extends. This function is used in the Google-internal code to handle some
53 // legacy cases.
ExtendeeClassName(const FieldDescriptor * descriptor)54 std::string ExtendeeClassName(const FieldDescriptor* descriptor) {
55   const Descriptor* extendee = descriptor->containing_type();
56   return ClassName(extendee, true);
57 }
58 
59 }  // anonymous namespace
60 
ExtensionGenerator(const FieldDescriptor * descriptor,const Options & options)61 ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor,
62                                        const Options& options)
63     : descriptor_(descriptor), options_(options) {
64   // Construct type_traits_.
65   if (descriptor_->is_repeated()) {
66     type_traits_ = "Repeated";
67   }
68 
69   switch (descriptor_->cpp_type()) {
70     case FieldDescriptor::CPPTYPE_ENUM:
71       type_traits_.append("EnumTypeTraits< ");
72       type_traits_.append(ClassName(descriptor_->enum_type(), true));
73       type_traits_.append(", ");
74       type_traits_.append(ClassName(descriptor_->enum_type(), true));
75       type_traits_.append("_IsValid>");
76       break;
77     case FieldDescriptor::CPPTYPE_STRING:
78       type_traits_.append("StringTypeTraits");
79       break;
80     case FieldDescriptor::CPPTYPE_MESSAGE:
81       type_traits_.append("MessageTypeTraits< ");
82       type_traits_.append(ClassName(descriptor_->message_type(), true));
83       type_traits_.append(" >");
84       break;
85     default:
86       type_traits_.append("PrimitiveTypeTraits< ");
87       type_traits_.append(PrimitiveTypeName(options_, descriptor_->cpp_type()));
88       type_traits_.append(" >");
89       break;
90   }
91   SetCommonVars(options, &variables_);
92   variables_["extendee"] = ExtendeeClassName(descriptor_);
93   variables_["type_traits"] = type_traits_;
94   std::string name = descriptor_->name();
95   variables_["name"] = ResolveKeyword(name);
96   variables_["constant_name"] = FieldConstantName(descriptor_);
97   variables_["field_type"] =
98       StrCat(static_cast<int>(descriptor_->type()));
99   variables_["packed"] = descriptor_->options().packed() ? "true" : "false";
100 
101   std::string scope =
102       IsScoped() ? ClassName(descriptor_->extension_scope(), false) + "::" : "";
103   variables_["scope"] = scope;
104   std::string scoped_name = scope + ResolveKeyword(name);
105   variables_["scoped_name"] = scoped_name;
106   variables_["number"] = StrCat(descriptor_->number());
107 }
108 
~ExtensionGenerator()109 ExtensionGenerator::~ExtensionGenerator() {}
110 
IsScoped() const111 bool ExtensionGenerator::IsScoped() const {
112   return descriptor_->extension_scope() != nullptr;
113 }
114 
GenerateDeclaration(io::Printer * printer) const115 void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) const {
116   Formatter format(printer, variables_);
117 
118   // If this is a class member, it needs to be declared "static".  Otherwise,
119   // it needs to be "extern".  In the latter case, it also needs the DLL
120   // export/import specifier.
121   std::string qualifier;
122   if (!IsScoped()) {
123     qualifier = "extern";
124     if (!options_.dllexport_decl.empty()) {
125       qualifier = options_.dllexport_decl + " " + qualifier;
126     }
127   } else {
128     qualifier = "static";
129   }
130 
131   format(
132       "static const int $constant_name$ = $number$;\n"
133       "$1$ ::$proto_ns$::internal::ExtensionIdentifier< $extendee$,\n"
134       "    ::$proto_ns$::internal::$type_traits$, $field_type$, $packed$ >\n"
135       "  ${2$$name$$}$;\n",
136       qualifier, descriptor_);
137 }
138 
GenerateDefinition(io::Printer * printer)139 void ExtensionGenerator::GenerateDefinition(io::Printer* printer) {
140   // If we are building for lite with implicit weak fields, we want to skip over
141   // any custom options (i.e. extensions of messages from descriptor.proto).
142   // This prevents the creation of any unnecessary linker references to the
143   // descriptor messages.
144   if (options_.lite_implicit_weak_fields &&
145       descriptor_->containing_type()->file()->name() ==
146           "net/proto2/proto/descriptor.proto") {
147     return;
148   }
149 
150   Formatter format(printer, variables_);
151   std::string default_str;
152   // If this is a class member, it needs to be declared in its class scope.
153   if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
154     // We need to declare a global string which will contain the default value.
155     // We cannot declare it at class scope because that would require exposing
156     // it in the header which would be annoying for other reasons.  So we
157     // replace :: with _ in the name and declare it as a global.
158     default_str =
159         StringReplace(variables_["scoped_name"], "::", "_", true) + "_default";
160     format("const std::string $1$($2$);\n", default_str,
161            DefaultValue(options_, descriptor_));
162   } else {
163     default_str = DefaultValue(options_, descriptor_);
164   }
165 
166   // Likewise, class members need to declare the field constant variable.
167   if (IsScoped()) {
168     format(
169         "#if !defined(_MSC_VER) || _MSC_VER >= 1900\n"
170         "const int $scope$$constant_name$;\n"
171         "#endif\n");
172   }
173 
174   format(
175       "::$proto_ns$::internal::ExtensionIdentifier< $extendee$,\n"
176       "    ::$proto_ns$::internal::$type_traits$, $field_type$, $packed$ >\n"
177       "  $scoped_name$($constant_name$, $1$);\n",
178       default_str);
179 }
180 
181 }  // namespace cpp
182 }  // namespace compiler
183 }  // namespace protobuf
184 }  // namespace google
185