Home | History | Annotate | Download | only in java
      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 Context::Context(const FileDescriptor* file)
     46     : name_resolver_(new ClassNameResolver) {
     47   InitializeFieldGeneratorInfo(file);
     48 }
     49 
     50 Context::~Context() {
     51 }
     52 
     53 ClassNameResolver* Context::GetNameResolver() {
     54   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 bool 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 
    100 void 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 
    106 void 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 
    126 void 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 
    170 const 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 
    181 const 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