• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 #include "google/protobuf/compiler/java/context.h"
9 
10 #include <string>
11 
12 #include "absl/log/absl_log.h"
13 #include "absl/strings/str_cat.h"
14 #include "absl/strings/string_view.h"
15 #include "absl/strings/strip.h"
16 #include "google/protobuf/compiler/java/field_common.h"
17 #include "google/protobuf/compiler/java/helpers.h"
18 #include "google/protobuf/compiler/java/name_resolver.h"
19 #include "google/protobuf/descriptor.h"
20 
21 namespace google {
22 namespace protobuf {
23 namespace compiler {
24 namespace java {
25 
Context(const FileDescriptor * file,const Options & options)26 Context::Context(const FileDescriptor* file, const Options& options)
27     : name_resolver_(new ClassNameResolver(options)), options_(options) {
28   InitializeFieldGeneratorInfo(file);
29 }
30 
~Context()31 Context::~Context() {}
32 
GetNameResolver() const33 ClassNameResolver* Context::GetNameResolver() const {
34   return name_resolver_.get();
35 }
36 
37 namespace {
EqualWithSuffix(absl::string_view name1,absl::string_view suffix,absl::string_view name2)38 bool EqualWithSuffix(absl::string_view name1, absl::string_view suffix,
39                      absl::string_view name2) {
40   if (!absl::ConsumeSuffix(&name2, suffix)) return false;
41   return name1 == name2;
42 }
43 
44 // Whether two fields have conflicting accessors (assuming name1 and name2
45 // are different). name1 and name2 are field1 and field2's camel-case name
46 // respectively.
IsConflicting(const FieldDescriptor * field1,absl::string_view name1,const FieldDescriptor * field2,absl::string_view name2,std::string * info)47 bool IsConflicting(const FieldDescriptor* field1, absl::string_view name1,
48                    const FieldDescriptor* field2, absl::string_view name2,
49                    std::string* info) {
50   if (field1->is_repeated()) {
51     if (field2->is_repeated()) {
52       // Both fields are repeated.
53       return false;
54     } else {
55       // field1 is repeated, and field2 is not.
56       if (EqualWithSuffix(name1, "Count", name2)) {
57         *info = absl::StrCat("both repeated field \"", field1->name(),
58                              "\" and singular ", "field \"", field2->name(),
59                              "\" generate the method \"", "get", name1,
60                              "Count()\"");
61         return true;
62       }
63       if (EqualWithSuffix(name1, "List", name2)) {
64         *info =
65             absl::StrCat("both repeated field \"", field1->name(),
66                          "\" and singular ", "field \"", field2->name(),
67                          "\" generate the method \"", "get", name1, "List()\"");
68         return true;
69       }
70       // Well, there are obviously many more conflicting cases, but it probably
71       // doesn't worth the effort to exhaust all of them because they rarely
72       // happen and as we are continuing adding new methods/changing existing
73       // methods the number of different conflicting cases will keep growing.
74       // We can just add more cases here when they are found in the real world.
75       return false;
76     }
77   } else {
78     if (field2->is_repeated()) {
79       return IsConflicting(field2, name2, field1, name1, info);
80     } else {
81       // None of the two fields are repeated.
82       return false;
83     }
84   }
85 }
86 }  // namespace
87 
InitializeFieldGeneratorInfo(const FileDescriptor * file)88 void Context::InitializeFieldGeneratorInfo(const FileDescriptor* file) {
89   for (int i = 0; i < file->message_type_count(); ++i) {
90     InitializeFieldGeneratorInfoForMessage(file->message_type(i));
91   }
92 }
93 
InitializeFieldGeneratorInfoForMessage(const Descriptor * message)94 void Context::InitializeFieldGeneratorInfoForMessage(
95     const Descriptor* message) {
96   for (int i = 0; i < message->nested_type_count(); ++i) {
97     InitializeFieldGeneratorInfoForMessage(message->nested_type(i));
98   }
99   std::vector<const FieldDescriptor*> fields;
100   fields.reserve(message->field_count());
101   for (int i = 0; i < message->field_count(); ++i) {
102     fields.push_back(message->field(i));
103   }
104   InitializeFieldGeneratorInfoForFields(fields);
105 
106   for (int i = 0; i < message->oneof_decl_count(); ++i) {
107     const OneofDescriptor* oneof = message->oneof_decl(i);
108     OneofGeneratorInfo info;
109     info.name = UnderscoresToCamelCase(oneof->name(), false);
110     info.capitalized_name = UnderscoresToCamelCase(oneof->name(), true);
111     oneof_generator_info_map_[oneof] = info;
112   }
113 }
114 
InitializeFieldGeneratorInfoForFields(const std::vector<const FieldDescriptor * > & fields)115 void Context::InitializeFieldGeneratorInfoForFields(
116     const std::vector<const FieldDescriptor*>& fields) {
117   // Find out all fields that conflict with some other field in the same
118   // message.
119   std::vector<bool> is_conflict(fields.size());
120   std::vector<std::string> conflict_reason(fields.size());
121   for (int i = 0; i < fields.size(); ++i) {
122     const FieldDescriptor* field = fields[i];
123     const std::string& name = CapitalizedFieldName(field);
124     for (int j = i + 1; j < fields.size(); ++j) {
125       const FieldDescriptor* other = fields[j];
126       const std::string& other_name = CapitalizedFieldName(other);
127       if (name == other_name) {
128         is_conflict[i] = is_conflict[j] = true;
129         conflict_reason[i] = conflict_reason[j] =
130             absl::StrCat("capitalized name of field \"", field->name(),
131                          "\" conflicts with field \"", other->name(), "\"");
132       } else if (IsConflicting(field, name, other, other_name,
133                                &conflict_reason[j])) {
134         is_conflict[i] = is_conflict[j] = true;
135         conflict_reason[i] = conflict_reason[j];
136       }
137     }
138     if (is_conflict[i]) {
139       ABSL_LOG(WARNING) << "field \"" << field->full_name()
140                         << "\" is conflicting "
141                         << "with another field: " << conflict_reason[i];
142     }
143   }
144   for (int i = 0; i < fields.size(); ++i) {
145     const FieldDescriptor* field = fields[i];
146     FieldGeneratorInfo info;
147     info.name = CamelCaseFieldName(field);
148     info.capitalized_name = CapitalizedFieldName(field);
149     // For fields conflicting with some other fields, we append the field
150     // number to their field names in generated code to avoid conflicts.
151     if (is_conflict[i]) {
152       absl::StrAppend(&info.name, field->number());
153       absl::StrAppend(&info.capitalized_name, field->number());
154       info.disambiguated_reason = conflict_reason[i];
155     }
156     info.options = options_;
157     field_generator_info_map_[field] = info;
158   }
159 }
160 
GetFieldGeneratorInfo(const FieldDescriptor * field) const161 const FieldGeneratorInfo* Context::GetFieldGeneratorInfo(
162     const FieldDescriptor* field) const {
163   auto it = field_generator_info_map_.find(field);
164   if (it == field_generator_info_map_.end()) {
165     ABSL_LOG(FATAL) << "Can not find FieldGeneratorInfo for field: "
166                     << field->full_name();
167   }
168   return &it->second;
169 }
170 
GetOneofGeneratorInfo(const OneofDescriptor * oneof) const171 const OneofGeneratorInfo* Context::GetOneofGeneratorInfo(
172     const OneofDescriptor* oneof) const {
173   auto it = oneof_generator_info_map_.find(oneof);
174   if (it == oneof_generator_info_map_.end()) {
175     ABSL_LOG(FATAL) << "Can not find OneofGeneratorInfo for oneof: "
176                     << oneof->name();
177   }
178   return &it->second;
179 }
180 
181 // Does this message class have generated parsing, serialization, and other
182 // standard methods for which reflection-based fallback implementations exist?
HasGeneratedMethods(const Descriptor * descriptor) const183 bool Context::HasGeneratedMethods(const Descriptor* descriptor) const {
184   return options_.enforce_lite ||
185          descriptor->file()->options().optimize_for() != FileOptions::CODE_SIZE;
186 }
187 
188 }  // namespace java
189 }  // namespace compiler
190 }  // namespace protobuf
191 }  // namespace google
192