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_name_resolver.h>
32 :
33 : #include <map>
34 : #include <string>
35 :
36 : #include <google/protobuf/compiler/java/java_helpers.h>
37 : #include <google/protobuf/stubs/substitute.h>
38 :
39 : namespace google {
40 : namespace protobuf {
41 : namespace compiler {
42 : namespace java {
43 :
44 : namespace {
45 : // A suffix that will be appended to the file's outer class name if the name
46 : // conflicts with some other types defined in the file.
47 : const char* kOuterClassNameSuffix = "OuterClass";
48 :
49 : // Strip package name from a descriptor's full name.
50 : // For example:
51 : // Full name : foo.Bar.Baz
52 : // Package name: foo
53 : // After strip : Bar.Baz
54 0 : string StripPackageName(const string& full_name,
55 0 : const FileDescriptor* file) {
56 0 : if (file->package().empty()) {
57 0 : return full_name;
58 : } else {
59 : // Strip package name
60 0 : return full_name.substr(file->package().size() + 1);
61 : }
62 : }
63 :
64 : // Get the name of a message's Java class without package name prefix.
65 0 : string ClassNameWithoutPackage(const Descriptor* descriptor,
66 : bool immutable) {
67 0 : return StripPackageName(descriptor->full_name(),
68 0 : descriptor->file());
69 : }
70 :
71 : // Get the name of an enum's Java class without package name prefix.
72 0 : string ClassNameWithoutPackage(const EnumDescriptor* descriptor,
73 : bool immutable) {
74 : // Doesn't append "Mutable" for enum type's name.
75 0 : const Descriptor* message_descriptor = descriptor->containing_type();
76 0 : if (message_descriptor == NULL) {
77 0 : return descriptor->name();
78 : } else {
79 0 : return ClassNameWithoutPackage(message_descriptor, immutable) +
80 0 : "." + descriptor->name();
81 : }
82 : }
83 :
84 : // Get the name of a service's Java class without package name prefix.
85 0 : string ClassNameWithoutPackage(const ServiceDescriptor* descriptor,
86 : bool immutable) {
87 0 : string full_name = StripPackageName(descriptor->full_name(),
88 0 : descriptor->file());
89 : // We don't allow nested service definitions.
90 0 : GOOGLE_CHECK(full_name.find('.') == string::npos);
91 0 : return full_name;
92 : }
93 :
94 : // Check whether a given message or its nested types has the given class name.
95 0 : bool MessageHasConflictingClassName(const Descriptor* message,
96 : const string& classname) {
97 0 : if (message->name() == classname) return true;
98 0 : for (int i = 0; i < message->nested_type_count(); ++i) {
99 0 : if (MessageHasConflictingClassName(message->nested_type(i), classname)) {
100 : return true;
101 : }
102 : }
103 0 : for (int i = 0; i < message->enum_type_count(); ++i) {
104 0 : if (message->enum_type(i)->name() == classname) {
105 : return true;
106 : }
107 : }
108 : return false;
109 : }
110 :
111 : } // namespace
112 :
113 0 : ClassNameResolver::ClassNameResolver() {
114 0 : }
115 :
116 0 : ClassNameResolver::~ClassNameResolver() {
117 0 : }
118 :
119 0 : string ClassNameResolver::GetFileDefaultImmutableClassName(
120 0 : const FileDescriptor* file) {
121 : string basename;
122 0 : string::size_type last_slash = file->name().find_last_of('/');
123 0 : if (last_slash == string::npos) {
124 0 : basename = file->name();
125 : } else {
126 0 : basename = file->name().substr(last_slash + 1);
127 : }
128 0 : return UnderscoresToCamelCase(StripProto(basename), true);
129 : }
130 :
131 0 : string ClassNameResolver::GetFileImmutableClassName(
132 : const FileDescriptor* file) {
133 0 : string& class_name = file_immutable_outer_class_names_[file];
134 0 : if (class_name.empty()) {
135 0 : if (file->options().has_java_outer_classname()) {
136 0 : class_name = file->options().java_outer_classname();
137 : } else {
138 0 : class_name = GetFileDefaultImmutableClassName(file);
139 0 : if (HasConflictingClassName(file, class_name)) {
140 0 : class_name += kOuterClassNameSuffix;
141 : }
142 : }
143 : }
144 0 : return class_name;
145 : }
146 :
147 0 : string ClassNameResolver::GetFileClassName(const FileDescriptor* file,
148 : bool immutable) {
149 0 : if (immutable) {
150 0 : return GetFileImmutableClassName(file);
151 : } else {
152 0 : return "Mutable" + GetFileImmutableClassName(file);
153 : }
154 : }
155 :
156 : // Check whether there is any type defined in the proto file that has
157 : // the given class name.
158 0 : bool ClassNameResolver::HasConflictingClassName(
159 0 : const FileDescriptor* file, const string& classname) {
160 0 : for (int i = 0; i < file->enum_type_count(); i++) {
161 0 : if (file->enum_type(i)->name() == classname) {
162 : return true;
163 : }
164 : }
165 0 : for (int i = 0; i < file->service_count(); i++) {
166 0 : if (file->service(i)->name() == classname) {
167 : return true;
168 : }
169 : }
170 0 : for (int i = 0; i < file->message_type_count(); i++) {
171 0 : if (MessageHasConflictingClassName(file->message_type(i), classname)) {
172 : return true;
173 : }
174 : }
175 : return false;
176 : }
177 :
178 0 : string ClassNameResolver::GetDescriptorClassName(
179 : const FileDescriptor* descriptor) {
180 0 : return GetFileImmutableClassName(descriptor);
181 : }
182 :
183 0 : string ClassNameResolver::GetClassName(const FileDescriptor* descriptor,
184 : bool immutable) {
185 0 : string result = FileJavaPackage(descriptor, immutable);
186 0 : if (!result.empty()) result += '.';
187 0 : result += GetFileClassName(descriptor, immutable);
188 0 : return result;
189 : }
190 :
191 : // Get the full name of a Java class by prepending the Java package name
192 : // or outer class name.
193 0 : string ClassNameResolver::GetClassFullName(const string& name_without_package,
194 : const FileDescriptor* file,
195 : bool immutable,
196 : bool multiple_files) {
197 : string result;
198 0 : if (multiple_files) {
199 0 : result = FileJavaPackage(file, immutable);
200 : } else {
201 0 : result = GetClassName(file, immutable);
202 : }
203 0 : if (!result.empty()) {
204 : result += '.';
205 : }
206 : result += name_without_package;
207 0 : return result;
208 : }
209 :
210 0 : string ClassNameResolver::GetClassName(const Descriptor* descriptor,
211 : bool immutable) {
212 : return GetClassFullName(ClassNameWithoutPackage(descriptor, immutable),
213 : descriptor->file(), immutable,
214 0 : MultipleJavaFiles(descriptor->file(), immutable));
215 : }
216 :
217 0 : string ClassNameResolver::GetClassName(const EnumDescriptor* descriptor,
218 : bool immutable) {
219 : return GetClassFullName(ClassNameWithoutPackage(descriptor, immutable),
220 : descriptor->file(), immutable,
221 0 : MultipleJavaFiles(descriptor->file(), immutable));
222 : }
223 :
224 0 : string ClassNameResolver::GetClassName(const ServiceDescriptor* descriptor,
225 : bool immutable) {
226 : return GetClassFullName(ClassNameWithoutPackage(descriptor, immutable),
227 : descriptor->file(), immutable,
228 0 : MultipleJavaFiles(descriptor->file(), immutable));
229 : }
230 :
231 : // Get the Java Class style full name of a message.
232 0 : string ClassNameResolver::GetJavaClassFullName(
233 : const string& name_without_package,
234 : const FileDescriptor* file,
235 : bool immutable) {
236 : string result;
237 0 : if (MultipleJavaFiles(file, immutable)) {
238 0 : result = FileJavaPackage(file, immutable);
239 0 : if (!result.empty()) result += '.';
240 : } else {
241 0 : result = GetClassName(file, immutable);
242 0 : if (!result.empty()) result += '$';
243 : }
244 0 : result += StringReplace(name_without_package, ".", "$", true);
245 0 : return result;
246 : }
247 :
248 0 : string ClassNameResolver::GetExtensionIdentifierName(
249 0 : const FieldDescriptor* descriptor, bool immutable) {
250 0 : return GetClassName(descriptor->containing_type(), immutable) + "." +
251 0 : descriptor->name();
252 : }
253 :
254 :
255 0 : string ClassNameResolver::GetJavaImmutableClassName(
256 0 : const Descriptor* descriptor) {
257 : return GetJavaClassFullName(
258 : ClassNameWithoutPackage(descriptor, true),
259 0 : descriptor->file(), true);
260 : }
261 :
262 :
263 : } // namespace java
264 : } // namespace compiler
265 : } // namespace protobuf
266 : } // namespace google
|