Add the file a symbol is declared in to Reflection (#6613)

* Add the file a symbol is declared in to Reflection

If we move a code-generator to depend on Reflection,
it may need to know which file something was declared in
to properly name generated files.

* Doc comments in reflection, and more precise tests

* Add --project-root flag to flatc, normalize declaraion_file to this root

* fix --project-root stuff

* posixpath

* fix scripts

* format

* rename --project-root to --bfbs-filenames

Also, make it optional, rather than defaulting to `./`, if its not
specified, then don't serialize the filenames.

* bfbs generation

* fix some tests

* uncomment a thing

* add  to project root directory conditionally

* fix

* git clang format

* Added help description and removed != nullptr

* "

* Remove accidental change to docs

* Remove accidental change to docs

* Pool strings

Co-authored-by: Casper Neo <cneo@google.com>
This commit is contained in:
Casper
2021-06-17 11:50:04 -04:00
committed by GitHub
parent 2cf7bb7966
commit c58ae94225
20 changed files with 868 additions and 674 deletions

View File

@@ -158,6 +158,10 @@ CheckedError Parser::RecurseError() {
" reached");
}
const std::string &Parser::GetPooledString(const std::string &s) const {
return *(string_cache_.insert(s).first);
}
class Parser::ParseDepthGuard {
public:
explicit ParseDepthGuard(Parser *parser_not_null)
@@ -2281,13 +2285,18 @@ struct EnumValBuilder {
bool user_value;
};
CheckedError Parser::ParseEnum(const bool is_union, EnumDef **dest) {
CheckedError Parser::ParseEnum(const bool is_union, EnumDef **dest,
const char *filename) {
std::vector<std::string> enum_comment = doc_comment_;
NEXT();
std::string enum_name = attribute_;
EXPECT(kTokenIdentifier);
EnumDef *enum_def;
ECHECK(StartEnum(enum_name, is_union, &enum_def));
if (filename != nullptr && !opts.project_root.empty()) {
enum_def->declaration_file =
&GetPooledString(RelativeToRootPath(opts.project_root, filename));
}
enum_def->doc_comment = enum_comment;
if (!is_union && !opts.proto_mode) {
// Give specialized error message, since this type spec used to
@@ -2516,7 +2525,7 @@ static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) {
return a_id < b_id;
}
CheckedError Parser::ParseDecl() {
CheckedError Parser::ParseDecl(const char *filename) {
std::vector<std::string> dc = doc_comment_;
bool fixed = IsIdent("struct");
if (!fixed && !IsIdent("table")) return Error("declaration expected");
@@ -2527,6 +2536,10 @@ CheckedError Parser::ParseDecl() {
ECHECK(StartStruct(name, &struct_def));
struct_def->doc_comment = dc;
struct_def->fixed = fixed;
if (filename && !opts.project_root.empty()) {
struct_def->declaration_file =
&GetPooledString(RelativeToRootPath(opts.project_root, filename));
}
ECHECK(ParseMetaData(&struct_def->attributes));
struct_def->sortbysize =
struct_def->attributes.Lookup("original_order") == nullptr && !fixed;
@@ -2606,7 +2619,7 @@ CheckedError Parser::ParseDecl() {
return NoError();
}
CheckedError Parser::ParseService() {
CheckedError Parser::ParseService(const char *filename) {
std::vector<std::string> service_comment = doc_comment_;
NEXT();
auto service_name = attribute_;
@@ -2616,6 +2629,10 @@ CheckedError Parser::ParseService() {
service_def.file = file_being_parsed_;
service_def.doc_comment = service_comment;
service_def.defined_namespace = current_namespace_;
if (filename != nullptr && !opts.project_root.empty()) {
service_def.declaration_file =
&GetPooledString(RelativeToRootPath(opts.project_root, filename));
}
if (services_.Add(current_namespace_->GetFullyQualifiedName(service_name),
&service_def))
return Error("service already exists: " + service_name);
@@ -2731,7 +2748,7 @@ CheckedError Parser::ParseProtoDecl() {
} else if (IsIdent("enum")) {
// These are almost the same, just with different terminator:
EnumDef *enum_def;
ECHECK(ParseEnum(false, &enum_def));
ECHECK(ParseEnum(false, &enum_def, nullptr));
if (Is(';')) NEXT();
// Temp: remove any duplicates, as .fbs files can't handle them.
enum_def->RemoveDuplicates();
@@ -3371,9 +3388,9 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
} else if (token_ == '{') {
return NoError();
} else if (IsIdent("enum")) {
ECHECK(ParseEnum(false, nullptr));
ECHECK(ParseEnum(false, nullptr, source_filename));
} else if (IsIdent("union")) {
ECHECK(ParseEnum(true, nullptr));
ECHECK(ParseEnum(true, nullptr, source_filename));
} else if (IsIdent("root_type")) {
NEXT();
auto root_type = attribute_;
@@ -3412,9 +3429,9 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
EXPECT(';');
known_attributes_[name] = false;
} else if (IsIdent("rpc_service")) {
ECHECK(ParseService());
ECHECK(ParseService(source_filename));
} else {
ECHECK(ParseDecl());
ECHECK(ParseDecl(source_filename));
}
}
return NoError();
@@ -3491,32 +3508,44 @@ void Parser::Serialize() {
AssignIndices(structs_.vec);
AssignIndices(enums_.vec);
std::vector<Offset<reflection::Object>> object_offsets;
std::set<std::string> files;
for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
auto offset = (*it)->Serialize(&builder_, *this);
object_offsets.push_back(offset);
(*it)->serialized_location = offset.o;
const std::string *file = (*it)->declaration_file;
if (file) files.insert(*file);
}
std::vector<Offset<reflection::Enum>> enum_offsets;
for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
auto offset = (*it)->Serialize(&builder_, *this);
enum_offsets.push_back(offset);
(*it)->serialized_location = offset.o;
const std::string *file = (*it)->declaration_file;
if (file) files.insert(*file);
}
std::vector<Offset<reflection::Service>> service_offsets;
for (auto it = services_.vec.begin(); it != services_.vec.end(); ++it) {
auto offset = (*it)->Serialize(&builder_, *this);
service_offsets.push_back(offset);
(*it)->serialized_location = offset.o;
const std::string *file = (*it)->declaration_file;
if (file) files.insert(*file);
}
auto objs__ = builder_.CreateVectorOfSortedTables(&object_offsets);
auto enum__ = builder_.CreateVectorOfSortedTables(&enum_offsets);
auto fiid__ = builder_.CreateString(file_identifier_);
auto fext__ = builder_.CreateString(file_extension_);
auto serv__ = builder_.CreateVectorOfSortedTables(&service_offsets);
auto schema_offset = reflection::CreateSchema(
// TODO(caspern): CreateVectorOfSharedStrings
std::vector<Offset<flatbuffers::String>> file_offsets;
for (auto it = files.begin(); it != files.end(); it++) {
file_offsets.push_back(builder_.CreateSharedString(*it));
}
const auto objs__ = builder_.CreateVectorOfSortedTables(&object_offsets);
const auto enum__ = builder_.CreateVectorOfSortedTables(&enum_offsets);
const auto fiid__ = builder_.CreateString(file_identifier_);
const auto fext__ = builder_.CreateString(file_extension_);
const auto serv__ = builder_.CreateVectorOfSortedTables(&service_offsets);
const auto files__ = builder_.CreateVector(file_offsets);
const auto schema_offset = reflection::CreateSchema(
builder_, objs__, enum__, fiid__, fext__,
(root_struct_def_ ? root_struct_def_->serialized_location : 0), serv__,
static_cast<reflection::AdvancedFeatures>(advanced_features_));
static_cast<reflection::AdvancedFeatures>(advanced_features_), files__);
if (opts.size_prefixed) {
builder_.FinishSizePrefixed(schema_offset, reflection::SchemaIdentifier());
} else {
@@ -3557,16 +3586,18 @@ Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder,
field_offsets.push_back((*it)->Serialize(
builder, static_cast<uint16_t>(it - fields.vec.begin()), parser));
}
auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
auto name__ = builder->CreateString(qualified_name);
auto flds__ = builder->CreateVectorOfSortedTables(&field_offsets);
auto attr__ = SerializeAttributes(builder, parser);
auto docs__ = parser.opts.binary_schema_comments
? builder->CreateVectorOfStrings(doc_comment)
: 0;
return reflection::CreateObject(*builder, name__, flds__, fixed,
static_cast<int>(minalign),
static_cast<int>(bytesize), attr__, docs__);
const auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
const auto name__ = builder->CreateString(qualified_name);
const auto flds__ = builder->CreateVectorOfSortedTables(&field_offsets);
const auto attr__ = SerializeAttributes(builder, parser);
const auto docs__ = parser.opts.binary_schema_comments
? builder->CreateVectorOfStrings(doc_comment)
: 0;
std::string decl_file_in_project = declaration_file ? *declaration_file : "";
const auto file__ = builder->CreateSharedString(decl_file_in_project);
return reflection::CreateObject(
*builder, name__, flds__, fixed, static_cast<int>(minalign),
static_cast<int>(bytesize), attr__, docs__, file__);
}
bool StructDef::Deserialize(Parser &parser, const reflection::Object *object) {
@@ -3685,14 +3716,17 @@ Offset<reflection::Service> ServiceDef::Serialize(FlatBufferBuilder *builder,
for (auto it = calls.vec.begin(); it != calls.vec.end(); ++it) {
servicecall_offsets.push_back((*it)->Serialize(builder, parser));
}
auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
auto name__ = builder->CreateString(qualified_name);
auto call__ = builder->CreateVector(servicecall_offsets);
auto attr__ = SerializeAttributes(builder, parser);
auto docs__ = parser.opts.binary_schema_comments
? builder->CreateVectorOfStrings(doc_comment)
: 0;
return reflection::CreateService(*builder, name__, call__, attr__, docs__);
const auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
const auto name__ = builder->CreateString(qualified_name);
const auto call__ = builder->CreateVector(servicecall_offsets);
const auto attr__ = SerializeAttributes(builder, parser);
const auto docs__ = parser.opts.binary_schema_comments
? builder->CreateVectorOfStrings(doc_comment)
: 0;
std::string decl_file_in_project = declaration_file ? *declaration_file : "";
const auto file__ = builder->CreateSharedString(decl_file_in_project);
return reflection::CreateService(*builder, name__, call__, attr__, docs__,
file__);
}
bool ServiceDef::Deserialize(Parser &parser,
@@ -3719,16 +3753,18 @@ Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder,
for (auto it = vals.vec.begin(); it != vals.vec.end(); ++it) {
enumval_offsets.push_back((*it)->Serialize(builder, parser));
}
auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
auto name__ = builder->CreateString(qualified_name);
auto vals__ = builder->CreateVector(enumval_offsets);
auto type__ = underlying_type.Serialize(builder);
auto attr__ = SerializeAttributes(builder, parser);
auto docs__ = parser.opts.binary_schema_comments
? builder->CreateVectorOfStrings(doc_comment)
: 0;
const auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
const auto name__ = builder->CreateString(qualified_name);
const auto vals__ = builder->CreateVector(enumval_offsets);
const auto type__ = underlying_type.Serialize(builder);
const auto attr__ = SerializeAttributes(builder, parser);
const auto docs__ = parser.opts.binary_schema_comments
? builder->CreateVectorOfStrings(doc_comment)
: 0;
std::string decl_file_in_project = declaration_file ? *declaration_file : "";
const auto file__ = builder->CreateSharedString(decl_file_in_project);
return reflection::CreateEnum(*builder, name__, vals__, is_union, type__,
attr__, docs__);
attr__, docs__, file__);
}
bool EnumDef::Deserialize(Parser &parser, const reflection::Enum *_enum) {