Open up visibility for some compiler internals (#10608)
* Expose language-specific naming utilities in Bazel for downstream code generators * Expose language generators without exposing implementation details * Update cmake configs * Revert "Expose language generators without exposing implementation details" This reverts commit b073d9b4ebf28b825a6340ea0dfc60f1e43ae4c1. * Give gRPC privileged access to our python generator * Naming cleanup * Add linkage for public names.h helpers * Fixing build/merge issues * Fix extension docstringpull/10662/head
parent
d58d471117
commit
01fe22219a
32 changed files with 1255 additions and 801 deletions
@ -0,0 +1,225 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include "google/protobuf/compiler/csharp/names.h" |
||||
|
||||
#include <string> |
||||
|
||||
#include "absl/strings/str_replace.h" |
||||
#include "google/protobuf/compiler/csharp/names.h" |
||||
#include "google/protobuf/descriptor.pb.h" |
||||
|
||||
// Must be last.
|
||||
#include "google/protobuf/port_def.inc" |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace csharp { |
||||
|
||||
namespace { |
||||
|
||||
std::string StripDotProto(const std::string& proto_file) { |
||||
int lastindex = proto_file.find_last_of('.'); |
||||
return proto_file.substr(0, lastindex); |
||||
} |
||||
|
||||
// Returns the Pascal-cased last part of the proto file. For example,
|
||||
// input of "google/protobuf/foo_bar.proto" would result in "FooBar".
|
||||
std::string GetFileNameBase(const FileDescriptor* descriptor) { |
||||
std::string proto_file = descriptor->name(); |
||||
int lastslash = proto_file.find_last_of('/'); |
||||
std::string base = proto_file.substr(lastslash + 1); |
||||
return UnderscoresToPascalCase(StripDotProto(base)); |
||||
} |
||||
|
||||
std::string ToCSharpName(const std::string& name, const FileDescriptor* file) { |
||||
std::string result = GetFileNamespace(file); |
||||
if (!result.empty()) { |
||||
result += '.'; |
||||
} |
||||
std::string classname; |
||||
if (file->package().empty()) { |
||||
classname = name; |
||||
} else { |
||||
// Strip the proto package from full_name since we've replaced it with
|
||||
// the C# namespace.
|
||||
classname = name.substr(file->package().size() + 1); |
||||
} |
||||
result += absl::StrReplaceAll(classname, {{".", ".Types."}}); |
||||
return "global::" + result; |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
std::string GetFileNamespace(const FileDescriptor* descriptor) { |
||||
if (descriptor->options().has_csharp_namespace()) { |
||||
return descriptor->options().csharp_namespace(); |
||||
} |
||||
return UnderscoresToCamelCase(descriptor->package(), true, true); |
||||
} |
||||
|
||||
std::string GetClassName(const Descriptor* descriptor) { |
||||
return ToCSharpName(descriptor->full_name(), descriptor->file()); |
||||
} |
||||
|
||||
std::string GetClassName(const EnumDescriptor* descriptor) { |
||||
return ToCSharpName(descriptor->full_name(), descriptor->file()); |
||||
} |
||||
|
||||
std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor) { |
||||
// TODO: Detect collisions with existing messages,
|
||||
// and append an underscore if necessary.
|
||||
return GetFileNameBase(descriptor) + "Reflection"; |
||||
} |
||||
|
||||
std::string GetReflectionClassName(const FileDescriptor* descriptor) { |
||||
std::string result = GetFileNamespace(descriptor); |
||||
if (!result.empty()) { |
||||
result += '.'; |
||||
} |
||||
result += GetReflectionClassUnqualifiedName(descriptor); |
||||
return "global::" + result; |
||||
} |
||||
|
||||
std::string GetExtensionClassUnqualifiedName(const FileDescriptor* descriptor) { |
||||
// TODO: Detect collisions with existing messages,
|
||||
// and append an underscore if necessary.
|
||||
return GetFileNameBase(descriptor) + "Extensions"; |
||||
} |
||||
|
||||
std::string GetOutputFile(const FileDescriptor* descriptor, |
||||
const std::string file_extension, |
||||
const bool generate_directories, |
||||
const std::string base_namespace, |
||||
std::string* error) { |
||||
std::string relative_filename = GetFileNameBase(descriptor) + file_extension; |
||||
if (!generate_directories) { |
||||
return relative_filename; |
||||
} |
||||
std::string ns = GetFileNamespace(descriptor); |
||||
std::string namespace_suffix = ns; |
||||
if (!base_namespace.empty()) { |
||||
// Check that the base_namespace is either equal to or a leading part of
|
||||
// the file namespace. This isn't just a simple prefix; "Foo.B" shouldn't
|
||||
// be regarded as a prefix of "Foo.Bar". The simplest option is to add "."
|
||||
// to both.
|
||||
std::string extended_ns = ns + "."; |
||||
if (extended_ns.find(base_namespace + ".") != 0) { |
||||
*error = "Namespace " + ns + " is not a prefix namespace of base namespace " + base_namespace; |
||||
return ""; // This will be ignored, because we've set an error.
|
||||
} |
||||
namespace_suffix = ns.substr(base_namespace.length()); |
||||
if (namespace_suffix.find('.') == 0) { |
||||
namespace_suffix = namespace_suffix.substr(1); |
||||
} |
||||
} |
||||
|
||||
std::string namespace_dir = |
||||
absl::StrReplaceAll(namespace_suffix, {{".", "/"}}); |
||||
if (!namespace_dir.empty()) { |
||||
namespace_dir += "/"; |
||||
} |
||||
return namespace_dir + relative_filename; |
||||
} |
||||
|
||||
std::string UnderscoresToPascalCase(const std::string& input) { |
||||
return UnderscoresToCamelCase(input, true); |
||||
} |
||||
|
||||
// TODO(jtattermusch): can we reuse a utility function?
|
||||
std::string UnderscoresToCamelCase(const std::string& input, |
||||
bool cap_next_letter, |
||||
bool preserve_period) { |
||||
std::string result; |
||||
|
||||
// Note: I distrust ctype.h due to locales.
|
||||
for (int i = 0; i < input.size(); i++) { |
||||
if ('a' <= input[i] && input[i] <= 'z') { |
||||
if (cap_next_letter) { |
||||
result += input[i] + ('A' - 'a'); |
||||
} else { |
||||
result += input[i]; |
||||
} |
||||
cap_next_letter = false; |
||||
} else if ('A' <= input[i] && input[i] <= 'Z') { |
||||
if (i == 0 && !cap_next_letter) { |
||||
// Force first letter to lower-case unless explicitly told to
|
||||
// capitalize it.
|
||||
result += input[i] + ('a' - 'A'); |
||||
} else { |
||||
// Capital letters after the first are left as-is.
|
||||
result += input[i]; |
||||
} |
||||
cap_next_letter = false; |
||||
} else if ('0' <= input[i] && input[i] <= '9') { |
||||
result += input[i]; |
||||
cap_next_letter = true; |
||||
} else { |
||||
cap_next_letter = true; |
||||
if (input[i] == '.' && preserve_period) { |
||||
result += '.'; |
||||
} |
||||
} |
||||
} |
||||
// Add a trailing "_" if the name should be altered.
|
||||
if (input.size() > 0 && input[input.size() - 1] == '#') { |
||||
result += '_'; |
||||
} |
||||
|
||||
// https://github.com/protocolbuffers/protobuf/issues/8101
|
||||
// To avoid generating invalid identifiers - if the input string
|
||||
// starts with _<digit> (or multiple underscores then digit) then
|
||||
// we need to preserve the underscore as an identifier cannot start
|
||||
// with a digit.
|
||||
// This check is being done after the loop rather than before
|
||||
// to handle the case where there are multiple underscores before the
|
||||
// first digit. We let them all be consumed so we can see if we would
|
||||
// start with a digit.
|
||||
// Note: not preserving leading underscores for all otherwise valid identifiers
|
||||
// so as to not break anything that relies on the existing behaviour
|
||||
if (result.size() > 0 && ('0' <= result[0] && result[0] <= '9') |
||||
&& input.size() > 0 && input[0] == '_') |
||||
{ |
||||
result.insert(0, 1, '_'); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
} // namespace csharp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc" |
@ -0,0 +1,194 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include "google/protobuf/compiler/java/names.h" |
||||
|
||||
#include <string> |
||||
|
||||
#include "absl/container/flat_hash_set.h" |
||||
#include "google/protobuf/compiler/java/helpers.h" |
||||
#include "google/protobuf/compiler/java/name_resolver.h" |
||||
#include "google/protobuf/compiler/java/names.h" |
||||
#include "google/protobuf/compiler/java/options.h" |
||||
#include "google/protobuf/descriptor.pb.h" |
||||
|
||||
// Must be last.
|
||||
#include "google/protobuf/port_def.inc" |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
namespace { |
||||
|
||||
const char* DefaultPackage(Options options) { |
||||
return options.opensource_runtime ? "" : "com.google.protos"; |
||||
} |
||||
|
||||
bool IsReservedName(absl::string_view name) { |
||||
static const auto& kReservedNames = |
||||
*new absl::flat_hash_set<absl::string_view>({ |
||||
"abstract", "assert", "boolean", "break", "byte", |
||||
"case", "catch", "char", "class", "const", |
||||
"continue", "default", "do", "double", "else", |
||||
"enum", "extends", "final", "finally", "float", |
||||
"for", "goto", "if", "implements", "import", |
||||
"instanceof", "int", "interface", "long", "native", |
||||
"new", "package", "private", "protected", "public", |
||||
"return", "short", "static", "strictfp", "super", |
||||
"switch", "synchronized", "this", "throw", "throws", |
||||
"transient", "try", "void", "volatile", "while", |
||||
}); |
||||
return kReservedNames.contains(name); |
||||
} |
||||
|
||||
bool IsForbidden(const std::string& field_name) { |
||||
// Names that should be avoided (in UpperCamelCase format).
|
||||
// Using them will cause the compiler to generate accessors whose names
|
||||
// collide with methods defined in base classes.
|
||||
// Keep this list in sync with specialFieldNames in
|
||||
// java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java
|
||||
static const auto& kForbiddenNames = |
||||
*new absl::flat_hash_set<absl::string_view>({ |
||||
// java.lang.Object:
|
||||
"Class", |
||||
// com.google.protobuf.MessageLiteOrBuilder:
|
||||
"DefaultInstanceForType", |
||||
// com.google.protobuf.MessageLite:
|
||||
"ParserForType", |
||||
"SerializedSize", |
||||
// com.google.protobuf.MessageOrBuilder:
|
||||
"AllFields", |
||||
"DescriptorForType", |
||||
"InitializationErrorString", |
||||
"UnknownFields", |
||||
// obsolete. kept for backwards compatibility of generated code
|
||||
"CachedSize", |
||||
}); |
||||
return kForbiddenNames.contains(UnderscoresToCamelCase(field_name, true)); |
||||
} |
||||
|
||||
std::string FieldName(const FieldDescriptor* field) { |
||||
std::string field_name; |
||||
// Groups are hacky: The name of the field is just the lower-cased name
|
||||
// of the group type. In Java, though, we would like to retain the original
|
||||
// capitalization of the type name.
|
||||
if (GetType(field) == FieldDescriptor::TYPE_GROUP) { |
||||
field_name = field->message_type()->name(); |
||||
} else { |
||||
field_name = field->name(); |
||||
} |
||||
if (IsForbidden(field_name)) { |
||||
// Append a trailing "#" to indicate that the name should be decorated to
|
||||
// avoid collision with other names.
|
||||
field_name += "#"; |
||||
} |
||||
return field_name; |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
std::string ClassName(const Descriptor* descriptor) { |
||||
ClassNameResolver name_resolver; |
||||
return name_resolver.GetClassName(descriptor, true); |
||||
} |
||||
|
||||
std::string ClassName(const EnumDescriptor* descriptor) { |
||||
ClassNameResolver name_resolver; |
||||
return name_resolver.GetClassName(descriptor, true); |
||||
} |
||||
|
||||
std::string ClassName(const ServiceDescriptor* descriptor) { |
||||
ClassNameResolver name_resolver; |
||||
return name_resolver.GetClassName(descriptor, true); |
||||
} |
||||
|
||||
std::string ClassName(const FileDescriptor* descriptor) { |
||||
ClassNameResolver name_resolver; |
||||
return name_resolver.GetClassName(descriptor, true); |
||||
} |
||||
|
||||
|
||||
std::string FileJavaPackage(const FileDescriptor* file, bool immutable, |
||||
Options options) { |
||||
std::string result; |
||||
|
||||
if (file->options().has_java_package()) { |
||||
result = file->options().java_package(); |
||||
} else { |
||||
result = DefaultPackage(options); |
||||
if (!file->package().empty()) { |
||||
if (!result.empty()) result += '.'; |
||||
result += file->package(); |
||||
} |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
std::string FileJavaPackage(const FileDescriptor* file, Options options) { |
||||
return FileJavaPackage(file, true /* immutable */, options); |
||||
} |
||||
|
||||
std::string CapitalizedFieldName(const FieldDescriptor* field) { |
||||
return UnderscoresToCamelCase(FieldName(field), true); |
||||
} |
||||
|
||||
std::string UnderscoresToCamelCase(const FieldDescriptor* field) { |
||||
return UnderscoresToCamelCase(FieldName(field), false); |
||||
} |
||||
|
||||
std::string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field) { |
||||
return UnderscoresToCamelCase(FieldName(field), true); |
||||
} |
||||
|
||||
std::string UnderscoresToCamelCase(const MethodDescriptor* method) { |
||||
return UnderscoresToCamelCase(method->name(), false); |
||||
} |
||||
|
||||
std::string UnderscoresToCamelCaseCheckReserved(const FieldDescriptor* field) { |
||||
std::string name = UnderscoresToCamelCase(field); |
||||
if (IsReservedName(name)) { |
||||
return name + "_"; |
||||
} |
||||
return name; |
||||
} |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc" |
@ -0,0 +1,363 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Helper functions for generating ObjectiveC code.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_NAMES_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_NAMES_H__ |
||||
|
||||
#include <string> |
||||
#include <vector> |
||||
|
||||
#include "google/protobuf/descriptor.h" |
||||
#include "google/protobuf/descriptor.pb.h" |
||||
#include "google/protobuf/io/zero_copy_stream.h" |
||||
|
||||
// clang-format off
|
||||
#include "google/protobuf/port_def.inc" |
||||
// clang-format on
|
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace objectivec { |
||||
|
||||
// Get/Set the path to a file to load for objc class prefix lookups.
|
||||
std::string PROTOC_EXPORT GetPackageToPrefixMappingsPath(); |
||||
void PROTOC_EXPORT SetPackageToPrefixMappingsPath( |
||||
const std::string& file_path); |
||||
// Get/Set if the proto package should be used to make the default prefix for
|
||||
// symbols. This will then impact most of the type naming apis below. It is done
|
||||
// as a global to not break any other generator reusing the methods since they
|
||||
// are exported.
|
||||
bool PROTOC_EXPORT UseProtoPackageAsDefaultPrefix(); |
||||
void PROTOC_EXPORT SetUseProtoPackageAsDefaultPrefix(bool on_or_off); |
||||
// Get/Set the path to a file to load as exceptions when
|
||||
// `UseProtoPackageAsDefaultPrefix()` is `true`. An empty string means there
|
||||
// should be no exceptions.
|
||||
std::string PROTOC_EXPORT GetProtoPackagePrefixExceptionList(); |
||||
void PROTOC_EXPORT SetProtoPackagePrefixExceptionList( |
||||
const std::string& file_path); |
||||
// Get/Set a prefix to add before the prefix generated from the package name.
|
||||
// This is only used when UseProtoPackageAsDefaultPrefix() is True.
|
||||
std::string PROTOC_EXPORT GetForcedPackagePrefix(); |
||||
void PROTOC_EXPORT SetForcedPackagePrefix(const std::string& prefix); |
||||
|
||||
// Generator Prefix Validation Options (see objectivec_generator.cc for a
|
||||
// description of each):
|
||||
struct Options { |
||||
Options(); |
||||
std::string expected_prefixes_path; |
||||
std::vector<std::string> expected_prefixes_suppressions; |
||||
bool prefixes_must_be_registered; |
||||
bool require_prefixes; |
||||
}; |
||||
|
||||
// Escape C++ trigraphs by escaping question marks to "\?".
|
||||
std::string PROTOC_EXPORT EscapeTrigraphs(absl::string_view to_escape); |
||||
|
||||
// Remove white space from either end of a absl::string_view.
|
||||
void PROTOC_EXPORT TrimWhitespace(absl::string_view* input); |
||||
|
||||
// Returns true if the name requires a ns_returns_not_retained attribute applied
|
||||
// to it.
|
||||
bool PROTOC_EXPORT IsRetainedName(const std::string& name); |
||||
|
||||
// Returns true if the name starts with "init" and will need to have special
|
||||
// handling under ARC.
|
||||
bool PROTOC_EXPORT IsInitName(const std::string& name); |
||||
|
||||
// Returns true if the name requires a cf_returns_not_retained attribute applied
|
||||
// to it.
|
||||
bool PROTOC_EXPORT IsCreateName(const std::string& name); |
||||
|
||||
// Gets the objc_class_prefix or the prefix made from the proto package.
|
||||
std::string PROTOC_EXPORT FileClassPrefix(const FileDescriptor* file); |
||||
|
||||
// Gets the path of the file we're going to generate (sans the .pb.h
|
||||
// extension). The path will be dependent on the objectivec package
|
||||
// declared in the proto package.
|
||||
std::string PROTOC_EXPORT FilePath(const FileDescriptor* file); |
||||
|
||||
// Just like FilePath(), but without the directory part.
|
||||
std::string PROTOC_EXPORT FilePathBasename(const FileDescriptor* file); |
||||
|
||||
// Gets the name of the root class we'll generate in the file. This class
|
||||
// is not meant for external consumption, but instead contains helpers that
|
||||
// the rest of the classes need
|
||||
std::string PROTOC_EXPORT FileClassName(const FileDescriptor* file); |
||||
|
||||
// These return the fully-qualified class name corresponding to the given
|
||||
// descriptor.
|
||||
std::string PROTOC_EXPORT ClassName(const Descriptor* descriptor); |
||||
std::string PROTOC_EXPORT ClassName(const Descriptor* descriptor, |
||||
std::string* out_suffix_added); |
||||
std::string PROTOC_EXPORT EnumName(const EnumDescriptor* descriptor); |
||||
|
||||
// Returns the fully-qualified name of the enum value corresponding to the
|
||||
// the descriptor.
|
||||
std::string PROTOC_EXPORT EnumValueName(const EnumValueDescriptor* descriptor); |
||||
|
||||
// Returns the name of the enum value corresponding to the descriptor.
|
||||
std::string PROTOC_EXPORT EnumValueShortName(const EnumValueDescriptor* descriptor); |
||||
|
||||
// Reverse what an enum does.
|
||||
std::string PROTOC_EXPORT UnCamelCaseEnumShortName(const std::string& name); |
||||
|
||||
// Returns the name to use for the extension (used as the method off the file's
|
||||
// Root class).
|
||||
std::string PROTOC_EXPORT ExtensionMethodName(const FieldDescriptor* descriptor); |
||||
|
||||
// Returns the transformed field name.
|
||||
std::string PROTOC_EXPORT FieldName(const FieldDescriptor* field); |
||||
std::string PROTOC_EXPORT FieldNameCapitalized(const FieldDescriptor* field); |
||||
|
||||
// Returns the transformed oneof name.
|
||||
std::string PROTOC_EXPORT OneofEnumName(const OneofDescriptor* descriptor); |
||||
std::string PROTOC_EXPORT OneofName(const OneofDescriptor* descriptor); |
||||
std::string PROTOC_EXPORT OneofNameCapitalized(const OneofDescriptor* descriptor); |
||||
|
||||
// Returns a symbol that can be used in C code to refer to an Objective C
|
||||
// class without initializing the class.
|
||||
std::string PROTOC_EXPORT ObjCClass(const std::string& class_name); |
||||
|
||||
// Declares an Objective C class without initializing the class so that it can
|
||||
// be refrerred to by ObjCClass.
|
||||
std::string PROTOC_EXPORT ObjCClassDeclaration(const std::string& class_name); |
||||
|
||||
inline bool HasPreservingUnknownEnumSemantics(const FileDescriptor* file) { |
||||
return file->syntax() == FileDescriptor::SYNTAX_PROTO3; |
||||
} |
||||
|
||||
inline bool IsMapEntryMessage(const Descriptor* descriptor) { |
||||
return descriptor->options().map_entry(); |
||||
} |
||||
|
||||
// Reverse of the above.
|
||||
std::string PROTOC_EXPORT UnCamelCaseFieldName(const std::string& name, |
||||
const FieldDescriptor* field); |
||||
|
||||
enum ObjectiveCType { |
||||
OBJECTIVECTYPE_INT32, |
||||
OBJECTIVECTYPE_UINT32, |
||||
OBJECTIVECTYPE_INT64, |
||||
OBJECTIVECTYPE_UINT64, |
||||
OBJECTIVECTYPE_FLOAT, |
||||
OBJECTIVECTYPE_DOUBLE, |
||||
OBJECTIVECTYPE_BOOLEAN, |
||||
OBJECTIVECTYPE_STRING, |
||||
OBJECTIVECTYPE_DATA, |
||||
OBJECTIVECTYPE_ENUM, |
||||
OBJECTIVECTYPE_MESSAGE |
||||
}; |
||||
|
||||
enum FlagType { |
||||
FLAGTYPE_DESCRIPTOR_INITIALIZATION, |
||||
FLAGTYPE_EXTENSION, |
||||
FLAGTYPE_FIELD |
||||
}; |
||||
|
||||
template <class TDescriptor> |
||||
std::string GetOptionalDeprecatedAttribute(const TDescriptor* descriptor, |
||||
const FileDescriptor* file = NULL, |
||||
bool preSpace = true, |
||||
bool postNewline = false) { |
||||
bool isDeprecated = descriptor->options().deprecated(); |
||||
// The file is only passed when checking Messages & Enums, so those types
|
||||
// get tagged. At the moment, it doesn't seem to make sense to tag every
|
||||
// field or enum value with when the file is deprecated.
|
||||
bool isFileLevelDeprecation = false; |
||||
if (!isDeprecated && file) { |
||||
isFileLevelDeprecation = file->options().deprecated(); |
||||
isDeprecated = isFileLevelDeprecation; |
||||
} |
||||
if (isDeprecated) { |
||||
std::string message; |
||||
const FileDescriptor* sourceFile = descriptor->file(); |
||||
if (isFileLevelDeprecation) { |
||||
message = sourceFile->name() + " is deprecated."; |
||||
} else { |
||||
message = descriptor->full_name() + " is deprecated (see " + |
||||
sourceFile->name() + ")."; |
||||
} |
||||
|
||||
std::string result = std::string("GPB_DEPRECATED_MSG(\"") + message + "\")"; |
||||
if (preSpace) { |
||||
result.insert(0, " "); |
||||
} |
||||
if (postNewline) { |
||||
result.append("\n"); |
||||
} |
||||
return result; |
||||
} else { |
||||
return ""; |
||||
} |
||||
} |
||||
|
||||
std::string PROTOC_EXPORT GetCapitalizedType(const FieldDescriptor* field); |
||||
|
||||
ObjectiveCType PROTOC_EXPORT |
||||
GetObjectiveCType(FieldDescriptor::Type field_type); |
||||
|
||||
inline ObjectiveCType GetObjectiveCType(const FieldDescriptor* field) { |
||||
return GetObjectiveCType(field->type()); |
||||
} |
||||
|
||||
bool PROTOC_EXPORT IsPrimitiveType(const FieldDescriptor* field); |
||||
bool PROTOC_EXPORT IsReferenceType(const FieldDescriptor* field); |
||||
|
||||
std::string PROTOC_EXPORT |
||||
GPBGenericValueFieldName(const FieldDescriptor* field); |
||||
std::string PROTOC_EXPORT DefaultValue(const FieldDescriptor* field); |
||||
bool PROTOC_EXPORT HasNonZeroDefaultValue(const FieldDescriptor* field); |
||||
|
||||
std::string PROTOC_EXPORT |
||||
BuildFlagsString(const FlagType type, const std::vector<std::string>& strings); |
||||
|
||||
// Builds HeaderDoc/appledoc style comments out of the comments in the .proto
|
||||
// file.
|
||||
std::string PROTOC_EXPORT BuildCommentsString(const SourceLocation& location, |
||||
bool prefer_single_line); |
||||
|
||||
// The name the commonly used by the library when built as a framework.
|
||||
// This lines up to the name used in the CocoaPod.
|
||||
extern PROTOC_EXPORT const char* const ProtobufLibraryFrameworkName; |
||||
// Returns the CPP symbol name to use as the gate for framework style imports
|
||||
// for the given framework name to use.
|
||||
std::string PROTOC_EXPORT |
||||
ProtobufFrameworkImportSymbol(const std::string& framework_name); |
||||
|
||||
// Checks if the file is one of the proto's bundled with the library.
|
||||
bool PROTOC_EXPORT |
||||
IsProtobufLibraryBundledProtoFile(const FileDescriptor* file); |
||||
|
||||
// Checks the prefix for the given files and outputs any warnings as needed. If
|
||||
// there are flat out errors, then out_error is filled in with the first error
|
||||
// and the result is false.
|
||||
bool PROTOC_EXPORT ValidateObjCClassPrefixes( |
||||
const std::vector<const FileDescriptor*>& files, |
||||
const Options& validation_options, std::string* out_error); |
||||
// Same was the other ValidateObjCClassPrefixes() calls, but the options all
|
||||
// come from the environment variables.
|
||||
bool PROTOC_EXPORT ValidateObjCClassPrefixes( |
||||
const std::vector<const FileDescriptor*>& files, std::string* out_error); |
||||
|
||||
// Generate decode data needed for ObjC's GPBDecodeTextFormatName() to transform
|
||||
// the input into the expected output.
|
||||
class PROTOC_EXPORT TextFormatDecodeData { |
||||
public: |
||||
TextFormatDecodeData(); |
||||
~TextFormatDecodeData(); |
||||
|
||||
TextFormatDecodeData(const TextFormatDecodeData&) = delete; |
||||
TextFormatDecodeData& operator=(const TextFormatDecodeData&) = delete; |
||||
|
||||
void AddString(int32_t key, const std::string& input_for_decode, |
||||
const std::string& desired_output); |
||||
size_t num_entries() const { return entries_.size(); } |
||||
std::string Data() const; |
||||
|
||||
static std::string DecodeDataForString(const std::string& input_for_decode, |
||||
const std::string& desired_output); |
||||
|
||||
private: |
||||
typedef std::pair<int32_t, std::string> DataEntry; |
||||
std::vector<DataEntry> entries_; |
||||
}; |
||||
|
||||
// Helper for parsing simple files.
|
||||
class PROTOC_EXPORT LineConsumer { |
||||
public: |
||||
LineConsumer(); |
||||
virtual ~LineConsumer(); |
||||
virtual bool ConsumeLine(const absl::string_view& line, std::string* out_error) = 0; |
||||
}; |
||||
|
||||
bool PROTOC_EXPORT ParseSimpleFile(const std::string& path, |
||||
LineConsumer* line_consumer, |
||||
std::string* out_error); |
||||
|
||||
bool PROTOC_EXPORT ParseSimpleStream(io::ZeroCopyInputStream& input_stream, |
||||
const std::string& stream_name, |
||||
LineConsumer* line_consumer, |
||||
std::string* out_error); |
||||
|
||||
// Helper class for parsing framework import mappings and generating
|
||||
// import statements.
|
||||
class PROTOC_EXPORT ImportWriter { |
||||
public: |
||||
ImportWriter(const std::string& generate_for_named_framework, |
||||
const std::string& named_framework_to_proto_path_mappings_path, |
||||
const std::string& runtime_import_prefix, |
||||
bool include_wkt_imports); |
||||
~ImportWriter(); |
||||
|
||||
void AddFile(const FileDescriptor* file, const std::string& header_extension); |
||||
void Print(io::Printer* printer) const; |
||||
|
||||
static void PrintRuntimeImports(io::Printer* printer, |
||||
const std::vector<std::string>& header_to_import, |
||||
const std::string& runtime_import_prefix, |
||||
bool default_cpp_symbol = false); |
||||
|
||||
private: |
||||
class ProtoFrameworkCollector : public LineConsumer { |
||||
public: |
||||
ProtoFrameworkCollector(std::map<std::string, std::string>* inout_proto_file_to_framework_name) |
||||
: map_(inout_proto_file_to_framework_name) {} |
||||
|
||||
virtual bool ConsumeLine(const absl::string_view& line, std::string* out_error) override; |
||||
|
||||
private: |
||||
std::map<std::string, std::string>* map_; |
||||
}; |
||||
|
||||
void ParseFrameworkMappings(); |
||||
|
||||
const std::string generate_for_named_framework_; |
||||
const std::string named_framework_to_proto_path_mappings_path_; |
||||
const std::string runtime_import_prefix_; |
||||
const bool include_wkt_imports_; |
||||
std::map<std::string, std::string> proto_file_to_framework_name_; |
||||
bool need_to_parse_mapping_file_; |
||||
|
||||
std::vector<std::string> protobuf_imports_; |
||||
std::vector<std::string> other_framework_imports_; |
||||
std::vector<std::string> other_imports_; |
||||
}; |
||||
|
||||
} // namespace objectivec
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc" |
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_NAMES_H__
|
@ -0,0 +1,144 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "google/protobuf/compiler/php/names.h" |
||||
|
||||
#include <string> |
||||
|
||||
#include "google/protobuf/compiler/code_generator.h" |
||||
#include "google/protobuf/compiler/plugin.h" |
||||
#include "google/protobuf/descriptor.h" |
||||
#include "google/protobuf/descriptor.pb.h" |
||||
|
||||
const char* const kReservedNames[] = { |
||||
"abstract", "and", "array", "as", "break", |
||||
"callable", "case", "catch", "class", "clone", |
||||
"const", "continue", "declare", "default", "die", |
||||
"do", "echo", "else", "elseif", "empty", |
||||
"enddeclare", "endfor", "endforeach", "endif", "endswitch", |
||||
"endwhile", "eval", "exit", "extends", "final", |
||||
"finally", "fn", "for", "foreach", "function", |
||||
"global", "goto", "if", "implements", "include", |
||||
"include_once", "instanceof", "insteadof", "interface", "isset", |
||||
"list", "match", "namespace", "new", "or", |
||||
"parent", "print", "private", "protected", "public", |
||||
"readonly", "require", "require_once", "return", "self", |
||||
"static", "switch", "throw", "trait", "try", |
||||
"unset", "use", "var", "while", "xor", |
||||
"yield", "int", "float", "bool", "string", |
||||
"true", "false", "null", "void", "iterable"}; |
||||
const int kReservedNamesSize = 80; |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace php { |
||||
|
||||
bool IsReservedName(absl::string_view name) { |
||||
std::string lower(name); |
||||
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower); |
||||
for (int i = 0; i < kReservedNamesSize; i++) { |
||||
if (lower == kReservedNames[i]) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
std::string ReservedNamePrefix(const std::string& classname, |
||||
const FileDescriptor* file) { |
||||
if (IsReservedName(classname)) { |
||||
if (file->package() == "google.protobuf") { |
||||
return "GPB"; |
||||
} else { |
||||
return "PB"; |
||||
} |
||||
} |
||||
|
||||
return ""; |
||||
} |
||||
|
||||
namespace { |
||||
|
||||
template <typename DescriptorType> |
||||
std::string ClassNamePrefixImpl(const std::string& classname, |
||||
const DescriptorType* desc) { |
||||
const std::string& prefix = (desc->file()->options()).php_class_prefix(); |
||||
if (!prefix.empty()) { |
||||
return prefix; |
||||
} |
||||
|
||||
return ReservedNamePrefix(classname, desc->file()); |
||||
} |
||||
|
||||
template <typename DescriptorType> |
||||
std::string GeneratedClassNameImpl(const DescriptorType* desc) { |
||||
std::string classname = ClassNamePrefixImpl(desc->name(), desc) + desc->name(); |
||||
const Descriptor* containing = desc->containing_type(); |
||||
while (containing != NULL) { |
||||
classname = ClassNamePrefixImpl(containing->name(), desc) + containing->name() |
||||
+ '\\' + classname; |
||||
containing = containing->containing_type(); |
||||
} |
||||
return classname; |
||||
} |
||||
|
||||
std::string GeneratedClassNameImpl(const ServiceDescriptor* desc) { |
||||
std::string classname = desc->name(); |
||||
return ClassNamePrefixImpl(classname, desc) + classname; |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
std::string ClassNamePrefix(const std::string& classname, |
||||
const Descriptor* desc) { |
||||
return ClassNamePrefixImpl(classname, desc); |
||||
} |
||||
std::string ClassNamePrefix(const std::string& classname, |
||||
const EnumDescriptor* desc) { |
||||
return ClassNamePrefixImpl(classname, desc); |
||||
} |
||||
|
||||
std::string GeneratedClassName(const Descriptor* desc) { |
||||
return GeneratedClassNameImpl(desc); |
||||
} |
||||
|
||||
std::string GeneratedClassName(const EnumDescriptor* desc) { |
||||
return GeneratedClassNameImpl(desc); |
||||
} |
||||
|
||||
std::string GeneratedClassName(const ServiceDescriptor* desc) { |
||||
return GeneratedClassNameImpl(desc); |
||||
} |
||||
|
||||
} // namespace php
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,73 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_PHP_NAMES_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_PHP_NAMES_H__ |
||||
|
||||
#include "google/protobuf/descriptor.h" |
||||
|
||||
#include <string> |
||||
|
||||
#include "absl/strings/string_view.h" |
||||
#include "google/protobuf/port_def.inc" |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace php { |
||||
|
||||
// Whether or not a name is reserved.
|
||||
PROTOC_EXPORT bool IsReservedName(absl::string_view name); |
||||
|
||||
// A prefix to stick in front of reserved names to avoid clashes.
|
||||
PROTOC_EXPORT std::string ReservedNamePrefix(const std::string& classname, |
||||
const FileDescriptor* file); |
||||
|
||||
// A prefix to stick in front of all class names.
|
||||
PROTOC_EXPORT std::string ClassNamePrefix(const std::string& classname, |
||||
const Descriptor* desc); |
||||
PROTOC_EXPORT std::string ClassNamePrefix(const std::string& classname, |
||||
const EnumDescriptor* desc); |
||||
|
||||
// To skip reserved keywords in php, some generated classname are prefixed.
|
||||
// Other code generators may need following API to figure out the actual
|
||||
// classname.
|
||||
PROTOC_EXPORT std::string GeneratedClassName(const Descriptor* desc); |
||||
PROTOC_EXPORT std::string GeneratedClassName(const EnumDescriptor* desc); |
||||
PROTOC_EXPORT std::string GeneratedClassName(const ServiceDescriptor* desc); |
||||
|
||||
} // namespace php
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc" |
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_PHP_NAMES_H__
|
Loading…
Reference in new issue