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/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 Options& options) 61 : descriptor_(descriptor), 62 options_(options) { 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 (!options_.dllexport_decl.empty()) { 110 vars["qualifier"] = options_.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