• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
47 namespace google {
48 namespace protobuf {
49 namespace compiler {
50 namespace javamicro {
51 
52 namespace {
53 
54 // Recursively searches the given message to see if it contains any extensions.
UsesExtensions(const Message & message)55 bool 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   std::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 
FileGenerator(const FileDescriptor * file,const Params & params)87 FileGenerator::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 
~FileGenerator()93 FileGenerator::~FileGenerator() {}
94 
Validate(string * error)95 bool 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     std::cerr << "INFO: " << file_->name() << ":" << std::endl;
122     std::cerr << "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." << std::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 
Generate(io::Printer * printer)153 void 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 
195 template<typename GeneratorClass, typename DescriptorClass>
GenerateSibling(const string & package_dir,const string & java_package,const DescriptorClass * descriptor,OutputDirectory * output_directory,std::vector<string> * file_list,const Params & params)196 static void GenerateSibling(const string& package_dir,
197                             const string& java_package,
198                             const DescriptorClass* descriptor,
199                             OutputDirectory* output_directory,
200                             std::vector<string>* file_list,
201                             const Params& params) {
202   string filename = package_dir + descriptor->name() + ".java";
203   file_list->push_back(filename);
204 
205   std::unique_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 
GenerateSiblings(const string & package_dir,OutputDirectory * output_directory,std::vector<string> * file_list)222 void FileGenerator::GenerateSiblings(const string& package_dir,
223                                      OutputDirectory* output_directory,
224                                      std::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