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