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 <iostream> 36 37#include <google/protobuf/compiler/javamicro/javamicro_file.h> 38#include <google/protobuf/compiler/javamicro/javamicro_enum.h> 39#include <google/protobuf/compiler/javamicro/javamicro_helpers.h> 40#include <google/protobuf/compiler/javamicro/javamicro_message.h> 41#include <google/protobuf/compiler/code_generator.h> 42#include <google/protobuf/io/printer.h> 43#include <google/protobuf/io/zero_copy_stream.h> 44#include <google/protobuf/descriptor.pb.h> 45#include <google/protobuf/stubs/strutil.h> 46 47namespace google { 48namespace protobuf { 49namespace compiler { 50namespace javamicro { 51 52namespace { 53 54// Recursively searches the given message to see if it contains any extensions. 55bool UsesExtensions(const Message& message) { 56 const Reflection* reflection = message.GetReflection(); 57 58 // We conservatively assume that unknown fields are extensions. 59 if (reflection->GetUnknownFields(message).field_count() > 0) return true; 60 61 vector<const FieldDescriptor*> fields; 62 reflection->ListFields(message, &fields); 63 64 for (int i = 0; i < fields.size(); i++) { 65 if (fields[i]->is_extension()) return true; 66 67 if (fields[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { 68 if (fields[i]->is_repeated()) { 69 int size = reflection->FieldSize(message, fields[i]); 70 for (int j = 0; j < size; j++) { 71 const Message& sub_message = 72 reflection->GetRepeatedMessage(message, fields[i], j); 73 if (UsesExtensions(sub_message)) return true; 74 } 75 } else { 76 const Message& sub_message = reflection->GetMessage(message, fields[i]); 77 if (UsesExtensions(sub_message)) return true; 78 } 79 } 80 } 81 82 return false; 83} 84 85} // namespace 86 87FileGenerator::FileGenerator(const FileDescriptor* file, const Params& params) 88 : file_(file), 89 params_(params), 90 java_package_(FileJavaPackage(params, file)), 91 classname_(FileClassName(params, file)) {} 92 93FileGenerator::~FileGenerator() {} 94 95bool FileGenerator::Validate(string* error) { 96 // Check for extensions 97 FileDescriptorProto file_proto; 98 file_->CopyTo(&file_proto); 99 if (UsesExtensions(file_proto)) { 100 error->assign(file_->name()); 101 error->append( 102 ": Java MICRO_RUNTIME does not support extensions\""); 103 return false; 104 } 105 106 if (file_->service_count() != 0) { 107 error->assign(file_->name()); 108 error->append( 109 ": Java MICRO_RUNTIME does not support services\""); 110 return false; 111 } 112 113 if (!IsOuterClassNeeded(params_, file_)) { 114 return true; 115 } 116 117 // Check whether legacy javamicro generator would omit the outer class. 118 if (!params_.has_java_outer_classname(file_->name()) 119 && file_->message_type_count() == 1 120 && file_->enum_type_count() == 0 && file_->extension_count() == 0) { 121 cout << "INFO: " << file_->name() << ":" << endl; 122 cout << "Javamicro generator has changed to align with java generator. " 123 "An outer class will be created for this file and the single message " 124 "in the file will become a nested class. Use java_multiple_files to " 125 "skip generating the outer class, or set an explicit " 126 "java_outer_classname to suppress this message." << endl; 127 } 128 129 // Check that no class name matches the file's class name. This is a common 130 // problem that leads to Java compile errors that can be hard to understand. 131 // It's especially bad when using the java_multiple_files, since we would 132 // end up overwriting the outer class with one of the inner ones. 133 bool found_conflict = false; 134 for (int i = 0; !found_conflict && i < file_->message_type_count(); i++) { 135 if (file_->message_type(i)->name() == classname_) { 136 found_conflict = true; 137 } 138 } 139 if (found_conflict) { 140 error->assign(file_->name()); 141 error->append( 142 ": Cannot generate Java output because the file's outer class name, \""); 143 error->append(classname_); 144 error->append( 145 "\", matches the name of one of the types declared inside it. " 146 "Please either rename the type or use the java_outer_classname " 147 "option to specify a different outer class name for the .proto file."); 148 return false; 149 } 150 return true; 151} 152 153void FileGenerator::Generate(io::Printer* printer) { 154 // We don't import anything because we refer to all classes by their 155 // fully-qualified names in the generated source. 156 printer->Print( 157 "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" 158 "\n"); 159 if (!java_package_.empty()) { 160 printer->Print( 161 "package $package$;\n" 162 "\n", 163 "package", java_package_); 164 } 165 166 printer->Print( 167 "public final class $classname$ {\n" 168 " private $classname$() {}\n", 169 "classname", classname_); 170 printer->Indent(); 171 172 // ----------------------------------------------------------------- 173 174 for (int i = 0; i < file_->enum_type_count(); i++) { 175 EnumGenerator(file_->enum_type(i), params_).Generate(printer); 176 } 177 178 if (!params_.java_multiple_files(file_->name())) { 179 for (int i = 0; i < file_->message_type_count(); i++) { 180 MessageGenerator(file_->message_type(i), params_).Generate(printer); 181 } 182 } 183 184 // Static variables. 185 for (int i = 0; i < file_->message_type_count(); i++) { 186 // TODO(kenton): Reuse MessageGenerator objects? 187 MessageGenerator(file_->message_type(i), params_).GenerateStaticVariables(printer); 188 } 189 190 printer->Outdent(); 191 printer->Print( 192 "}\n"); 193} 194 195template<typename GeneratorClass, typename DescriptorClass> 196static void GenerateSibling(const string& package_dir, 197 const string& java_package, 198 const DescriptorClass* descriptor, 199 OutputDirectory* output_directory, 200 vector<string>* file_list, 201 const Params& params) { 202 string filename = package_dir + descriptor->name() + ".java"; 203 file_list->push_back(filename); 204 205 scoped_ptr<io::ZeroCopyOutputStream> output( 206 output_directory->Open(filename)); 207 io::Printer printer(output.get(), '$'); 208 209 printer.Print( 210 "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" 211 "\n"); 212 if (!java_package.empty()) { 213 printer.Print( 214 "package $package$;\n" 215 "\n", 216 "package", java_package); 217 } 218 219 GeneratorClass(descriptor, params).Generate(&printer); 220} 221 222void FileGenerator::GenerateSiblings(const string& package_dir, 223 OutputDirectory* output_directory, 224 vector<string>* file_list) { 225 if (params_.java_multiple_files(file_->name())) { 226 for (int i = 0; i < file_->message_type_count(); i++) { 227 GenerateSibling<MessageGenerator>(package_dir, java_package_, 228 file_->message_type(i), 229 output_directory, file_list, params_); 230 } 231 } 232} 233 234} // namespace javamicro 235} // namespace compiler 236} // namespace protobuf 237} // namespace google 238