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 40namespace google { 41namespace protobuf { 42namespace compiler { 43namespace java { 44 45Context::Context(const FileDescriptor* file) 46 : name_resolver_(new ClassNameResolver) { 47 InitializeFieldGeneratorInfo(file); 48} 49 50Context::~Context() { 51} 52 53ClassNameResolver* Context::GetNameResolver() { 54 return name_resolver_.get(); 55} 56 57namespace { 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. 61bool IsConflicting(const FieldDescriptor* field1, const string& name1, 62 const FieldDescriptor* field2, const string& name2, 63 string* info) { 64 if (field1->is_repeated()) { 65 if (field2->is_repeated()) { 66 // Both fields are repeated. 67 return false; 68 } else { 69 // field1 is repeated, and field2 is not. 70 if (name1 + "Count" == name2) { 71 *info = "both repeated field \"" + field1->name() + "\" and singular " + 72 "field \"" + field2->name() + "\" generates the method \"" + 73 "get" + name1 + "Count()\""; 74 return true; 75 } 76 if (name1 + "List" == name2) { 77 *info = "both repeated field \"" + field1->name() + "\" and singular " + 78 "field \"" + field2->name() + "\" generates the method \"" + 79 "get" + name1 + "List()\""; 80 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 if (field2->is_repeated()) { 91 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 100void Context::InitializeFieldGeneratorInfo(const FileDescriptor* file) { 101 for (int i = 0; i < file->message_type_count(); ++i) { 102 InitializeFieldGeneratorInfoForMessage(file->message_type(i)); 103 } 104} 105 106void Context::InitializeFieldGeneratorInfoForMessage( 107 const Descriptor* message) { 108 for (int i = 0; i < message->nested_type_count(); ++i) { 109 InitializeFieldGeneratorInfoForMessage(message->nested_type(i)); 110 } 111 vector<const FieldDescriptor*> fields; 112 for (int i = 0; i < message->field_count(); ++i) { 113 fields.push_back(message->field(i)); 114 } 115 InitializeFieldGeneratorInfoForFields(fields); 116 117 for (int i = 0; i < message->oneof_decl_count(); ++i) { 118 const OneofDescriptor* oneof = message->oneof_decl(i); 119 OneofGeneratorInfo info; 120 info.name = UnderscoresToCamelCase(oneof->name(), false); 121 info.capitalized_name = UnderscoresToCamelCase(oneof->name(), true); 122 oneof_generator_info_map_[oneof] = info; 123 } 124} 125 126void Context::InitializeFieldGeneratorInfoForFields( 127 const vector<const FieldDescriptor*>& fields) { 128 // Find out all fields that conflict with some other field in the same 129 // message. 130 vector<bool> is_conflict(fields.size()); 131 vector<string> conflict_reason(fields.size()); 132 for (int i = 0; i < fields.size(); ++i) { 133 const FieldDescriptor* field = fields[i]; 134 const string& name = UnderscoresToCapitalizedCamelCase(field); 135 for (int j = i + 1; j < fields.size(); ++j) { 136 const FieldDescriptor* other = fields[j]; 137 const string& other_name = UnderscoresToCapitalizedCamelCase(other); 138 if (name == other_name) { 139 is_conflict[i] = is_conflict[j] = true; 140 conflict_reason[i] = conflict_reason[j] = 141 "capitalized name of field \"" + field->name() + 142 "\" conflicts with field \"" + other->name() + "\""; 143 } else if (IsConflicting(field, name, other, other_name, 144 &conflict_reason[j])) { 145 is_conflict[i] = is_conflict[j] = true; 146 conflict_reason[i] = conflict_reason[j]; 147 } 148 } 149 if (is_conflict[i]) { 150 GOOGLE_LOG(WARNING) << "field \"" << field->full_name() << "\" is conflicting " 151 << "with another field: " << conflict_reason[i]; 152 } 153 } 154 for (int i = 0; i < fields.size(); ++i) { 155 const FieldDescriptor* field = fields[i]; 156 FieldGeneratorInfo info; 157 info.name = UnderscoresToCamelCase(field); 158 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 if (is_conflict[i]) { 162 info.name += SimpleItoa(field->number()); 163 info.capitalized_name += SimpleItoa(field->number()); 164 info.disambiguated_reason = conflict_reason[i]; 165 } 166 field_generator_info_map_[field] = info; 167 } 168} 169 170const FieldGeneratorInfo* Context::GetFieldGeneratorInfo( 171 const FieldDescriptor* field) const { 172 const FieldGeneratorInfo* result = 173 FindOrNull(field_generator_info_map_, field); 174 if (result == NULL) { 175 GOOGLE_LOG(FATAL) << "Can not find FieldGeneratorInfo for field: " 176 << field->full_name(); 177 } 178 return result; 179} 180 181const OneofGeneratorInfo* Context::GetOneofGeneratorInfo( 182 const OneofDescriptor* oneof) const { 183 const OneofGeneratorInfo* result = 184 FindOrNull(oneof_generator_info_map_, oneof); 185 if (result == NULL) { 186 GOOGLE_LOG(FATAL) << "Can not find OneofGeneratorInfo for oneof: " 187 << oneof->name(); 188 } 189 return result; 190} 191 192} // namespace java 193} // namespace compiler 194} // namespace protobuf 195} // namespace google 196