• 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 #include <google/protobuf/compiler/java/java_context.h>
32 
33 #include <google/protobuf/compiler/java/java_field.h>
34 #include <google/protobuf/compiler/java/java_helpers.h>
35 #include <google/protobuf/compiler/java/java_name_resolver.h>
36 #include <google/protobuf/descriptor.h>
37 #include <google/protobuf/stubs/strutil.h>
38 #include <google/protobuf/stubs/map_util.h>
39 
40 namespace google {
41 namespace protobuf {
42 namespace compiler {
43 namespace java {
44 
Context(const FileDescriptor * file,const Options & options)45 Context::Context(const FileDescriptor* file, const Options& options)
46     : name_resolver_(new ClassNameResolver), options_(options) {
47   InitializeFieldGeneratorInfo(file);
48 }
49 
~Context()50 Context::~Context() {}
51 
GetNameResolver() const52 ClassNameResolver* Context::GetNameResolver() const {
53   return name_resolver_.get();
54 }
55 
56 namespace {
57 // Whether two fields have conflicting accessors (assuming name1 and name2
58 // are different). name1 and name2 are field1 and field2's camel-case name
59 // respectively.
IsConflicting(const FieldDescriptor * field1,const std::string & name1,const FieldDescriptor * field2,const std::string & name2,std::string * info)60 bool IsConflicting(const FieldDescriptor* field1, const std::string& name1,
61                    const FieldDescriptor* field2, const std::string& name2,
62                    std::string* info) {
63   if (field1->is_repeated()) {
64     if (field2->is_repeated()) {
65       // Both fields are repeated.
66       return false;
67     } else {
68       // field1 is repeated, and field2 is not.
69       if (name1 + "Count" == name2) {
70         *info = "both repeated field \"" + field1->name() + "\" and singular " +
71                 "field \"" + field2->name() + "\" generate the method \"" +
72                 "get" + name1 + "Count()\"";
73         return true;
74       }
75       if (name1 + "List" == name2) {
76         *info = "both repeated field \"" + field1->name() + "\" and singular " +
77                 "field \"" + field2->name() + "\" generate the method \"" +
78                 "get" + name1 + "List()\"";
79         return true;
80       }
81       // Well, there are obviously many more conflicting cases, but it probably
82       // doesn't worth the effort to exhaust all of them because they rarely
83       // happen and as we are continuing adding new methods/changing existing
84       // methods the number of different conflicting cases will keep growing.
85       // We can just add more cases here when they are found in the real world.
86       return false;
87     }
88   } else {
89     if (field2->is_repeated()) {
90       return IsConflicting(field2, name2, field1, name1, info);
91     } else {
92       // None of the two fields are repeated.
93       return false;
94     }
95   }
96 }
97 }  // namespace
98 
InitializeFieldGeneratorInfo(const FileDescriptor * file)99 void Context::InitializeFieldGeneratorInfo(const FileDescriptor* file) {
100   for (int i = 0; i < file->message_type_count(); ++i) {
101     InitializeFieldGeneratorInfoForMessage(file->message_type(i));
102   }
103 }
104 
InitializeFieldGeneratorInfoForMessage(const Descriptor * message)105 void Context::InitializeFieldGeneratorInfoForMessage(
106     const Descriptor* message) {
107   for (int i = 0; i < message->nested_type_count(); ++i) {
108     InitializeFieldGeneratorInfoForMessage(message->nested_type(i));
109   }
110   std::vector<const FieldDescriptor*> fields;
111   for (int i = 0; i < message->field_count(); ++i) {
112     fields.push_back(message->field(i));
113   }
114   InitializeFieldGeneratorInfoForFields(fields);
115 
116   for (int i = 0; i < message->oneof_decl_count(); ++i) {
117     const OneofDescriptor* oneof = message->oneof_decl(i);
118     OneofGeneratorInfo info;
119     info.name = UnderscoresToCamelCase(oneof->name(), false);
120     info.capitalized_name = UnderscoresToCamelCase(oneof->name(), true);
121     oneof_generator_info_map_[oneof] = info;
122   }
123 }
124 
InitializeFieldGeneratorInfoForFields(const std::vector<const FieldDescriptor * > & fields)125 void Context::InitializeFieldGeneratorInfoForFields(
126     const std::vector<const FieldDescriptor*>& fields) {
127   // Find out all fields that conflict with some other field in the same
128   // message.
129   std::vector<bool> is_conflict(fields.size());
130   std::vector<std::string> conflict_reason(fields.size());
131   for (int i = 0; i < fields.size(); ++i) {
132     const FieldDescriptor* field = fields[i];
133     const std::string& name = UnderscoresToCapitalizedCamelCase(field);
134     for (int j = i + 1; j < fields.size(); ++j) {
135       const FieldDescriptor* other = fields[j];
136       const std::string& other_name = UnderscoresToCapitalizedCamelCase(other);
137       if (name == other_name) {
138         is_conflict[i] = is_conflict[j] = true;
139         conflict_reason[i] = conflict_reason[j] =
140             "capitalized name of field \"" + field->name() +
141             "\" conflicts with field \"" + other->name() + "\"";
142       } else if (IsConflicting(field, name, other, other_name,
143                                &conflict_reason[j])) {
144         is_conflict[i] = is_conflict[j] = true;
145         conflict_reason[i] = conflict_reason[j];
146       }
147     }
148     if (is_conflict[i]) {
149       GOOGLE_LOG(WARNING) << "field \"" << field->full_name() << "\" is conflicting "
150                    << "with another field: " << conflict_reason[i];
151     }
152   }
153   for (int i = 0; i < fields.size(); ++i) {
154     const FieldDescriptor* field = fields[i];
155     FieldGeneratorInfo info;
156     info.name = CamelCaseFieldName(field);
157     info.capitalized_name = UnderscoresToCapitalizedCamelCase(field);
158     // For fields conflicting with some other fields, we append the field
159     // number to their field names in generated code to avoid conflicts.
160     if (is_conflict[i]) {
161       info.name += StrCat(field->number());
162       info.capitalized_name += StrCat(field->number());
163       info.disambiguated_reason = conflict_reason[i];
164     }
165     field_generator_info_map_[field] = info;
166   }
167 }
168 
GetFieldGeneratorInfo(const FieldDescriptor * field) const169 const FieldGeneratorInfo* Context::GetFieldGeneratorInfo(
170     const FieldDescriptor* field) const {
171   const FieldGeneratorInfo* result =
172       FindOrNull(field_generator_info_map_, field);
173   if (result == NULL) {
174     GOOGLE_LOG(FATAL) << "Can not find FieldGeneratorInfo for field: "
175                << field->full_name();
176   }
177   return result;
178 }
179 
GetOneofGeneratorInfo(const OneofDescriptor * oneof) const180 const OneofGeneratorInfo* Context::GetOneofGeneratorInfo(
181     const OneofDescriptor* oneof) const {
182   const OneofGeneratorInfo* result =
183       FindOrNull(oneof_generator_info_map_, oneof);
184   if (result == NULL) {
185     GOOGLE_LOG(FATAL) << "Can not find OneofGeneratorInfo for oneof: "
186                << oneof->name();
187   }
188   return result;
189 }
190 
191 // Does this message class have generated parsing, serialization, and other
192 // standard methods for which reflection-based fallback implementations exist?
HasGeneratedMethods(const Descriptor * descriptor) const193 bool Context::HasGeneratedMethods(const Descriptor* descriptor) const {
194   return options_.enforce_lite ||
195          descriptor->file()->options().optimize_for() != FileOptions::CODE_SIZE;
196 }
197 
198 }  // namespace java
199 }  // namespace compiler
200 }  // namespace protobuf
201 }  // namespace google
202