1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.  All rights reserved.
3// http://code.google.com/p/protobuf/
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/stubs/strutil.h>
39#include <google/protobuf/io/printer.h>
40#include <google/protobuf/descriptor.pb.h>
41
42namespace google {
43namespace protobuf {
44namespace compiler {
45namespace cpp {
46
47namespace {
48
49// Returns the fully-qualified class name of the message that this field
50// extends. This function is used in the Google-internal code to handle some
51// legacy cases.
52string ExtendeeClassName(const FieldDescriptor* descriptor) {
53  const Descriptor* extendee = descriptor->containing_type();
54  return ClassName(extendee, true);
55}
56
57}  // anonymous namespace
58
59ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor,
60                                       const string& dllexport_decl)
61  : descriptor_(descriptor),
62    dllexport_decl_(dllexport_decl) {
63  // Construct type_traits_.
64  if (descriptor_->is_repeated()) {
65    type_traits_ = "Repeated";
66  }
67
68  switch (descriptor_->cpp_type()) {
69    case FieldDescriptor::CPPTYPE_ENUM:
70      type_traits_.append("EnumTypeTraits< ");
71      type_traits_.append(ClassName(descriptor_->enum_type(), true));
72      type_traits_.append(", ");
73      type_traits_.append(ClassName(descriptor_->enum_type(), true));
74      type_traits_.append("_IsValid>");
75      break;
76    case FieldDescriptor::CPPTYPE_STRING:
77      type_traits_.append("StringTypeTraits");
78      break;
79    case FieldDescriptor::CPPTYPE_MESSAGE:
80      type_traits_.append("MessageTypeTraits< ");
81      type_traits_.append(ClassName(descriptor_->message_type(), true));
82      type_traits_.append(" >");
83      break;
84    default:
85      type_traits_.append("PrimitiveTypeTraits< ");
86      type_traits_.append(PrimitiveTypeName(descriptor_->cpp_type()));
87      type_traits_.append(" >");
88      break;
89  }
90}
91
92ExtensionGenerator::~ExtensionGenerator() {}
93
94void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) {
95  map<string, string> vars;
96  vars["extendee"     ] = ExtendeeClassName(descriptor_);
97  vars["number"       ] = SimpleItoa(descriptor_->number());
98  vars["type_traits"  ] = type_traits_;
99  vars["name"         ] = descriptor_->name();
100  vars["field_type"   ] = SimpleItoa(static_cast<int>(descriptor_->type()));
101  vars["packed"       ] = descriptor_->options().packed() ? "true" : "false";
102  vars["constant_name"] = FieldConstantName(descriptor_);
103
104  // If this is a class member, it needs to be declared "static".  Otherwise,
105  // it needs to be "extern".  In the latter case, it also needs the DLL
106  // export/import specifier.
107  if (descriptor_->extension_scope() == NULL) {
108    vars["qualifier"] = "extern";
109    if (!dllexport_decl_.empty()) {
110      vars["qualifier"] = dllexport_decl_ + " " + vars["qualifier"];
111    }
112  } else {
113    vars["qualifier"] = "static";
114  }
115
116  printer->Print(vars,
117    "static const int $constant_name$ = $number$;\n"
118    "$qualifier$ ::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n"
119    "    ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n"
120    "  $name$;\n"
121    );
122
123}
124
125void ExtensionGenerator::GenerateDefinition(io::Printer* printer) {
126  // If this is a class member, it needs to be declared in its class scope.
127  string scope = (descriptor_->extension_scope() == NULL) ? "" :
128    ClassName(descriptor_->extension_scope(), false) + "::";
129  string name = scope + descriptor_->name();
130
131  map<string, string> vars;
132  vars["extendee"     ] = ExtendeeClassName(descriptor_);
133  vars["type_traits"  ] = type_traits_;
134  vars["name"         ] = name;
135  vars["constant_name"] = FieldConstantName(descriptor_);
136  vars["default"      ] = DefaultValue(descriptor_);
137  vars["field_type"   ] = SimpleItoa(static_cast<int>(descriptor_->type()));
138  vars["packed"       ] = descriptor_->options().packed() ? "true" : "false";
139  vars["scope"        ] = scope;
140
141  if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
142    // We need to declare a global string which will contain the default value.
143    // We cannot declare it at class scope because that would require exposing
144    // it in the header which would be annoying for other reasons.  So we
145    // replace :: with _ in the name and declare it as a global.
146    string global_name = StringReplace(name, "::", "_", true);
147    vars["global_name"] = global_name;
148    printer->Print(vars,
149      "const ::std::string $global_name$_default($default$);\n");
150
151    // Update the default to refer to the string global.
152    vars["default"] = global_name + "_default";
153  }
154
155  // Likewise, class members need to declare the field constant variable.
156  if (descriptor_->extension_scope() != NULL) {
157    printer->Print(vars,
158      "#ifndef _MSC_VER\n"
159      "const int $scope$$constant_name$;\n"
160      "#endif\n");
161  }
162
163  printer->Print(vars,
164    "::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n"
165    "    ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n"
166    "  $name$($constant_name$, $default$);\n");
167}
168
169void ExtensionGenerator::GenerateRegistration(io::Printer* printer) {
170  map<string, string> vars;
171  vars["extendee"   ] = ExtendeeClassName(descriptor_);
172  vars["number"     ] = SimpleItoa(descriptor_->number());
173  vars["field_type" ] = SimpleItoa(static_cast<int>(descriptor_->type()));
174  vars["is_repeated"] = descriptor_->is_repeated() ? "true" : "false";
175  vars["is_packed"  ] = (descriptor_->is_repeated() &&
176                         descriptor_->options().packed())
177                        ? "true" : "false";
178
179  switch (descriptor_->cpp_type()) {
180    case FieldDescriptor::CPPTYPE_ENUM:
181      printer->Print(vars,
182        "::google::protobuf::internal::ExtensionSet::RegisterEnumExtension(\n"
183        "  &$extendee$::default_instance(),\n"
184        "  $number$, $field_type$, $is_repeated$, $is_packed$,\n");
185      printer->Print(
186        "  &$type$_IsValid);\n",
187        "type", ClassName(descriptor_->enum_type(), true));
188      break;
189    case FieldDescriptor::CPPTYPE_MESSAGE:
190      printer->Print(vars,
191        "::google::protobuf::internal::ExtensionSet::RegisterMessageExtension(\n"
192        "  &$extendee$::default_instance(),\n"
193        "  $number$, $field_type$, $is_repeated$, $is_packed$,\n");
194      printer->Print(
195        "  &$type$::default_instance());\n",
196        "type", ClassName(descriptor_->message_type(), true));
197      break;
198    default:
199      printer->Print(vars,
200        "::google::protobuf::internal::ExtensionSet::RegisterExtension(\n"
201        "  &$extendee$::default_instance(),\n"
202        "  $number$, $field_type$, $is_repeated$, $is_packed$);\n");
203      break;
204  }
205}
206
207}  // namespace cpp
208}  // namespace compiler
209}  // namespace protobuf
210}  // namespace google
211