Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use the 'New' Metadata Validator for slice2swift #3530

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cpp/src/slice2swift/Gen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ void
Gen::generate(const UnitPtr& p)
{
SwiftGenerator::validateMetadata(p);
SwiftGenerator::validateSwiftModuleMappings(p);

ImportVisitor importVisitor(_out);
p->visit(&importVisitor);
Expand Down
313 changes: 99 additions & 214 deletions cpp/src/slice2swift/SwiftUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "SwiftUtil.h"
#include "../Ice/OutputUtil.h"
#include "../Slice/MetadataValidation.h"
#include "../Slice/Util.h"

#include <algorithm>
Expand Down Expand Up @@ -615,8 +616,104 @@ SwiftGenerator::writeServantDocSummary(IceInternal::Output& out, const Interface
void
SwiftGenerator::validateMetadata(const UnitPtr& u)
{
MetadataVisitor visitor;
u->visit(&visitor);
map<string, MetadataInfo> knownMetadata;

// "swift:attribute"
MetadataInfo attributeInfo = {
.validOn = {typeid(ClassDecl), typeid(Struct), typeid(Slice::Exception), typeid(Enum)},
.acceptedArgumentKind = MetadataArgumentKind::RequiredTextArgument,
.mustBeUnique = false,
};
knownMetadata.emplace("swift:attribute", attributeInfo);

// "swift:class-resolver-prefix"
MetadataInfo classResolverPrefixInfo = {
.validOn = {typeid(Unit)},
.acceptedArgumentKind = MetadataArgumentKind::SingleArgument,
};
knownMetadata.emplace("swift:class-resolver-prefix", classResolverPrefixInfo);

// "swift:inherits"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should drop swift:inherits.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After this is merged I'll have a follow up PR to drop swift:inherits and loosen the swift:module check.
I think that should be all the issues around Swift metadata.

MetadataInfo inheritsInfo = {
.validOn = {typeid(InterfaceDecl)},
.acceptedArgumentKind = MetadataArgumentKind::RequiredTextArgument,
.mustBeUnique = false,
};
knownMetadata.emplace("swift:inherits", inheritsInfo);

// "swift:module"
MetadataInfo moduleInfo = {
.validOn = {typeid(Module)},
// Even though it's really 'module:prefix' the validator sees this as a single argument since there's no commas.
.acceptedArgumentKind = MetadataArgumentKind::SingleArgument,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should drop the MetadataArgumentKind::MultipleArguments (?) option since we don't use it for any Slice metadata except support warnings.

};
knownMetadata.emplace("swift:module", moduleInfo);

// Pass this information off to the parser's metadata validation logic.
Slice::validateMetadata(u, "swift", knownMetadata);
}

void
SwiftGenerator::validateSwiftModuleMappings(const UnitPtr& unit)
Comment on lines +656 to +657
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All this code was just moved out of MetadataValidator::visitUnit into a new static function.
I didn't change anything else about it.

{
using ModuleMap = std::map<std::string, std::string>;
// Each Slice unit has to map all top-level modules to a single Swift module
ModuleMap mappedModules;
// With a given Swift module a Slice module has to map to a single prefix
std::map<std::string, ModuleMap> mappedModulePrefixes;

// Any modules that are directly contained on the unit are (by definition) top-level modules.
// And since there is only one unit per compilation, this must be all the top-level modules.
for (const auto& module : unit->modules())
{
string swiftPrefix;
string swiftModule = getSwiftModule(module, swiftPrefix);

const string filename = module->definitionContext()->filename();
auto current = mappedModules.find(filename);

if (current == mappedModules.end())
{
mappedModules[filename] = swiftModule;
}
else if (current->second != swiftModule)
{
ostringstream os;
os << "invalid module mapping:\n Slice module '" << module->scoped() << "' should map to Swift module '"
<< current->second << "'" << endl;
unit->error(module->file(), module->line(), os.str());
}

auto prefixes = mappedModulePrefixes.find(swiftModule);
if (prefixes == mappedModulePrefixes.end())
{
ModuleMap mappings;
mappings[module->name()] = swiftPrefix;
mappedModulePrefixes[swiftModule] = mappings;
}
else
{
current = prefixes->second.find(module->name());
if (current == prefixes->second.end())
{
prefixes->second[module->name()] = swiftPrefix;
}
else if (current->second != swiftPrefix)
{
ostringstream os;
os << "invalid module prefix:\n Slice module '" << module->scoped() << "' is already using";
if (current->second.empty())
{
os << " no prefix " << endl;
}
else
{
os << " a different Swift module prefix '" << current->second << "'" << endl;
}
unit->error(module->file(), module->line(), os.str());
}
}
}
}

string
Expand Down Expand Up @@ -1265,78 +1362,6 @@ SwiftGenerator::writeMarshalUnmarshalCode(
}
}

bool
SwiftGenerator::MetadataVisitor::visitUnitStart(const UnitPtr& unit)
{
using ModuleMap = std::map<std::string, std::string>;
// Each Slice unit has to map all top-level modules to a single Swift module
ModuleMap mappedModules;
// With a given Swift module a Slice module has to map to a single prefix
std::map<std::string, ModuleMap> mappedModulePrefixes;

// Any modules that are directly contained on the unit are (by definition) top-level modules.
// And since there is only one unit per compilation, this must be all the top-level modules.
for (const auto& module : unit->modules())
{
string swiftPrefix;
string swiftModule = getSwiftModule(module, swiftPrefix);

const string filename = module->definitionContext()->filename();
auto current = mappedModules.find(filename);

if (current == mappedModules.end())
{
mappedModules[filename] = swiftModule;
}
else if (current->second != swiftModule)
{
ostringstream os;
os << "invalid module mapping:\n Slice module '" << module->scoped() << "' should map to Swift module '"
<< current->second << "'" << endl;
unit->error(module->file(), module->line(), os.str());
}

auto prefixes = mappedModulePrefixes.find(swiftModule);
if (prefixes == mappedModulePrefixes.end())
{
ModuleMap mappings;
mappings[module->name()] = swiftPrefix;
mappedModulePrefixes[swiftModule] = mappings;
}
else
{
current = prefixes->second.find(module->name());
if (current == prefixes->second.end())
{
prefixes->second[module->name()] = swiftPrefix;
}
else if (current->second != swiftPrefix)
{
ostringstream os;
os << "invalid module prefix:\n Slice module '" << module->scoped() << "' is already using";
if (current->second.empty())
{
os << " no prefix " << endl;
}
else
{
os << " a different Swift module prefix '" << current->second << "'" << endl;
}
unit->error(module->file(), module->line(), os.str());
}
}
}

return true;
}

bool
SwiftGenerator::MetadataVisitor::visitModuleStart(const ModulePtr& p)
{
p->setMetadata(validate(p, p));
return true;
}

string
SwiftGenerator::paramLabel(const string& param, const ParameterList& params)
{
Expand Down Expand Up @@ -2018,143 +2043,3 @@ SwiftGenerator::writeDispatchOperation(::IceInternal::Output& out, const Operati

out << eb;
}

bool
SwiftGenerator::MetadataVisitor::visitClassDefStart(const ClassDefPtr& p)
{
p->setMetadata(validate(p, p));
for (const auto& member : p->dataMembers())
{
// TODO we should probably be passing `member` instead of `member->type()`.
// Otherwise I'm pretty sure we're just skipping the data-member metadata.
member->setMetadata(validate(member->type(), member));
}
return true;
}

bool
SwiftGenerator::MetadataVisitor::visitInterfaceDefStart(const InterfaceDefPtr& p)
{
p->setMetadata(validate(p, p));
return true;
}

void
SwiftGenerator::MetadataVisitor::visitOperation(const OperationPtr& p)
{
p->setMetadata(validate(p, p));
for (const auto& param : p->parameters())
{
param->setMetadata(validate(param->type(), param));
}
}

bool
SwiftGenerator::MetadataVisitor::visitExceptionStart(const ExceptionPtr& p)
{
p->setMetadata(validate(p, p));
for (const auto& member : p->dataMembers())
{
member->setMetadata(validate(member->type(), member));
}
return true;
}

bool
SwiftGenerator::MetadataVisitor::visitStructStart(const StructPtr& p)
{
p->setMetadata(validate(p, p));
for (const auto& member : p->dataMembers())
{
member->setMetadata(validate(member->type(), member));
}
return true;
}

void
SwiftGenerator::MetadataVisitor::visitSequence(const SequencePtr& p)
{
p->setMetadata(validate(p, p));
}

void
SwiftGenerator::MetadataVisitor::visitDictionary(const DictionaryPtr& p)
{
const string prefix = "swift:";

for (const auto& metadata : p->keyMetadata())
{
if (metadata->directive().find(prefix) == 0)
{
ostringstream msg;
msg << "ignoring invalid metadata '" << *metadata << "' for dictionary key type";
p->unit()->warning(metadata->file(), metadata->line(), InvalidMetadata, msg.str());
}
}

for (const auto& metadata : p->valueMetadata())
{
if (metadata->directive().find(prefix) == 0)
{
ostringstream msg;
msg << "ignoring invalid metadata '" << *metadata << "' for dictionary value type";
p->unit()->warning(metadata->file(), metadata->line(), InvalidMetadata, msg.str());
}
}

p->setMetadata(validate(p, p));
}

void
SwiftGenerator::MetadataVisitor::visitEnum(const EnumPtr& p)
{
p->setMetadata(validate(p, p));
}

void
SwiftGenerator::MetadataVisitor::visitConst(const ConstPtr& p)
{
p->setMetadata(validate(p, p));
}

MetadataList
SwiftGenerator::MetadataVisitor::validate(const SyntaxTreeBasePtr& p, const ContainedPtr& cont)
{
MetadataList newMetadata = cont->getMetadata();

for (auto m = newMetadata.begin(); m != newMetadata.end();)
{
MetadataPtr meta = *m++;
string_view directive = meta->directive();
string_view arguments = meta->arguments();

if (directive.find("swift:") != 0)
{
continue;
}

if (dynamic_pointer_cast<Module>(p) && directive == "swift:module" && !arguments.empty())
{
continue;
}

if (dynamic_pointer_cast<InterfaceDecl>(p) && directive == "swift:inherits" && !arguments.empty())
{
continue;
}

if ((dynamic_pointer_cast<ClassDecl>(p) || dynamic_pointer_cast<Struct>(p) || dynamic_pointer_cast<Enum>(p) ||
dynamic_pointer_cast<Exception>(p)) &&
directive == "swift:attribute" && !arguments.empty())
{
continue;
}

ostringstream msg;
msg << "ignoring invalid metadata '" << *meta << "'";
p->unit()->warning(meta->file(), meta->line(), InvalidMetadata, msg.str());
newMetadata.remove(meta);
continue;
}
return newMetadata;
}
26 changes: 4 additions & 22 deletions cpp/src/slice2swift/SwiftUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ namespace Slice

static void validateMetadata(const UnitPtr&);

// Swift only allows 1 package per file, so this function checks that if there are multiple top-level-modules
// within a single Slice file, that they all map to the same Swift package.
static void validateSwiftModuleMappings(const UnitPtr&);

protected:
void writeDocLines(
IceInternal::Output&,
Expand Down Expand Up @@ -119,28 +123,6 @@ namespace Slice
void writeSwiftAttributes(::IceInternal::Output&, const MetadataList&);
void writeProxyOperation(::IceInternal::Output&, const OperationPtr&);
void writeDispatchOperation(::IceInternal::Output&, const OperationPtr&);

private:
class MetadataVisitor final : public ParserVisitor
{
public:
bool visitUnitStart(const UnitPtr&) final;
bool visitModuleStart(const ModulePtr&) final;
bool visitClassDefStart(const ClassDefPtr&) final;
bool visitInterfaceDefStart(const InterfaceDefPtr&) final;
void visitOperation(const OperationPtr&) final;
bool visitExceptionStart(const ExceptionPtr&) final;
bool visitStructStart(const StructPtr&) final;
void visitSequence(const SequencePtr&) final;
void visitDictionary(const DictionaryPtr&) final;
void visitEnum(const EnumPtr&) final;
void visitConst(const ConstPtr&) final;

[[nodiscard]] bool shouldVisitIncludedDefinitions() const final { return true; }

private:
MetadataList validate(const SyntaxTreeBasePtr&, const ContainedPtr&);
};
};
}

Expand Down