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