Skip to content

Commit

Permalink
Use the new MetadataValidator in C#, Java, JavaScript, Ruby, PHP, and…
Browse files Browse the repository at this point in the history
… MATLAB (#3256)
  • Loading branch information
InsertCreativityHere authored Dec 16, 2024
1 parent ca7be91 commit d9a2cd9
Show file tree
Hide file tree
Showing 17 changed files with 488 additions and 933 deletions.
61 changes: 31 additions & 30 deletions cpp/src/Slice/MetadataValidation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,66 +74,67 @@ Slice::validateMetadata(const UnitPtr& p, string_view prefix, map<string, Metada

// "amd"
MetadataInfo amdInfo = {
{typeid(InterfaceDecl), typeid(Operation)},
MetadataArgumentKind::NoArguments,
.validOn = {typeid(InterfaceDecl), typeid(Operation)},
.acceptedArgumentKind = MetadataArgumentKind::NoArguments,
};
knownMetadata.emplace("amd", std::move(amdInfo));

// "deprecated"
MetadataInfo deprecatedInfo = {
{typeid(InterfaceDecl),
typeid(ClassDecl),
typeid(Operation),
typeid(Exception),
typeid(Struct),
typeid(Sequence),
typeid(Dictionary),
typeid(Enum),
typeid(Enumerator),
typeid(Const),
typeid(DataMember)},
MetadataArgumentKind::OptionalTextArgument,
.validOn =
{typeid(InterfaceDecl),
typeid(ClassDecl),
typeid(Operation),
typeid(Exception),
typeid(Struct),
typeid(Sequence),
typeid(Dictionary),
typeid(Enum),
typeid(Enumerator),
typeid(Const),
typeid(DataMember)},
.acceptedArgumentKind = MetadataArgumentKind::OptionalTextArgument,
};
knownMetadata.emplace("deprecate", std::move(deprecatedInfo)); // Kept as an alias for 'deprecated'.
knownMetadata.emplace("deprecate", deprecatedInfo); // Kept as an alias for 'deprecated'.
knownMetadata.emplace("deprecated", std::move(deprecatedInfo));

// "format"
MetadataInfo formatInfo = {
{typeid(InterfaceDecl), typeid(Operation)},
MetadataArgumentKind::SingleArgument,
{{"compact", "sliced", "default"}},
.validOn = {typeid(InterfaceDecl), typeid(Operation)},
.acceptedArgumentKind = MetadataArgumentKind::SingleArgument,
.validArgumentValues = {{"compact", "sliced", "default"}},
};
knownMetadata.emplace("format", std::move(formatInfo));

// "marshaled-result"
MetadataInfo marshaledResultInfo = {
{typeid(InterfaceDecl), typeid(Operation)},
MetadataArgumentKind::NoArguments,
.validOn = {typeid(InterfaceDecl), typeid(Operation)},
.acceptedArgumentKind = MetadataArgumentKind::NoArguments,
};
knownMetadata.emplace("marshaled-result", std::move(marshaledResultInfo));

// "protected"
MetadataInfo protectedInfo = {
{typeid(ClassDecl), typeid(Slice::Exception), typeid(Struct), typeid(DataMember)},
MetadataArgumentKind::NoArguments,
.validOn = {typeid(ClassDecl), typeid(Slice::Exception), typeid(Struct), typeid(DataMember)},
.acceptedArgumentKind = MetadataArgumentKind::NoArguments,
};
knownMetadata.emplace("protected", std::move(protectedInfo));

// "suppress-warning"
MetadataInfo suppressWarningInfo = {
{typeid(Unit)},
MetadataArgumentKind::AnyNumberOfArguments,
{{"all", "deprecated", "invalid-comment"}},
.validOn = {typeid(Unit)},
.acceptedArgumentKind = MetadataArgumentKind::AnyNumberOfArguments,
.validArgumentValues = {{"all", "deprecated", "invalid-comment"}},
.mustBeUnique = false,
};
suppressWarningInfo.mustBeUnique = false;
knownMetadata.emplace("suppress-warning", std::move(suppressWarningInfo));

// TODO: we should probably just remove this metadata. It's only checked by slice2java,
// and there's already a 'java:UserException' metadata that we also check... better to only keep that one.
// "UserException"
MetadataInfo userExceptionInfo = {
{typeid(Operation)},
MetadataArgumentKind::NoArguments,
.validOn = {typeid(Operation)},
.acceptedArgumentKind = MetadataArgumentKind::NoArguments,
};
knownMetadata.emplace("UserException", std::move(userExceptionInfo));

Expand Down Expand Up @@ -350,7 +351,7 @@ MetadataVisitor::isMetadataValid(const MetadataPtr& metadata, const SyntaxTreeBa

// Fourth, we check what the metadata was applied to - does that Slice definition support this metadata?
SyntaxTreeBasePtr appliedTo;
if (info.acceptedContexts == MetadataApplicationContext::Definitions)
if (info.acceptedContext == MetadataApplicationContext::Definitions)
{
if (isTypeContext)
{
Expand Down Expand Up @@ -402,7 +403,7 @@ MetadataVisitor::isMetadataValid(const MetadataPtr& metadata, const SyntaxTreeBa
}

// If this metadata is only valid in the context of parameters issue a warning if that condition wasn't met.
if (info.acceptedContexts == MetadataApplicationContext::ParameterTypeReferences && !isAppliedToParameter)
if (info.acceptedContext == MetadataApplicationContext::ParameterTypeReferences && !isAppliedToParameter)
{
auto msg = '\'' + directive + "' metadata can only be applied to operation parameters and return types";
p->unit()->warning(metadata->file(), metadata->line(), InvalidMetadata, msg);
Expand Down
2 changes: 1 addition & 1 deletion cpp/src/Slice/MetadataValidation.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ namespace Slice
std::optional<StringList> validArgumentValues = std::nullopt;

/// Specifies in what contexts the metadata can appear (i.e. can it apply to defintions, references, both?)
MetadataApplicationContext acceptedContexts = MetadataApplicationContext::Definitions;
MetadataApplicationContext acceptedContext = MetadataApplicationContext::Definitions;

/// Indicates whether it's valid and meaningful for this metadata to appear multiple times on the same thing.
bool mustBeUnique = true;
Expand Down
2 changes: 1 addition & 1 deletion cpp/src/Slice/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ Slice::Metadata::Metadata(string rawMetadata, string file, int line) : GrammarBa
{
// Check if the metadata starts with a language prefix.
// NOTE: It is important that this list is kept in alphabetical order!
constexpr string_view languages[] = {"cpp", "cs", "java", "js", "matlab", "php", "python", "ruby", "swift"};
constexpr string_view languages[] = {"cpp", "cs", "java", "js", "matlab", "php", "python", "rb", "swift"};
string prefix = rawMetadata.substr(0, firstColonPos);
bool hasLangPrefix = binary_search(&languages[0], &languages[sizeof(languages) / sizeof(*languages)], prefix);
if (hasLangPrefix)
Expand Down
148 changes: 74 additions & 74 deletions cpp/src/slice2cpp/Gen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -860,108 +860,106 @@ Slice::Gen::validateMetadata(const UnitPtr& u)

// "cpp:array"
MetadataInfo arrayInfo = {
{typeid(Sequence)},
MetadataArgumentKind::NoArguments,
nullopt,
MetadataApplicationContext::ParameterTypeReferences,
.validOn = {typeid(Sequence)},
.acceptedArgumentKind = MetadataArgumentKind::NoArguments,
.acceptedContext = MetadataApplicationContext::ParameterTypeReferences,
};
knownMetadata.emplace("cpp:array", std::move(arrayInfo));

// "cpp:const"
MetadataInfo constInfo = {
{typeid(Operation)},
MetadataArgumentKind::NoArguments,
.validOn = {typeid(Operation)},
.acceptedArgumentKind = MetadataArgumentKind::NoArguments,
};
knownMetadata.emplace("cpp:const", std::move(constInfo));

// "cpp:dll-export"
MetadataInfo dllExportInfo = {
{typeid(Unit)},
MetadataArgumentKind::SingleArgument,
.validOn = {typeid(Unit)},
.acceptedArgumentKind = MetadataArgumentKind::SingleArgument,
};
knownMetadata.emplace("cpp:dll-export", std::move(dllExportInfo));

// "cpp:doxygen:include"
MetadataInfo doxygenInfo = {
{typeid(Unit)},
MetadataArgumentKind::RequiredTextArgument,
};
doxygenInfo.extraValidation = [](const MetadataPtr& meta, const SyntaxTreeBasePtr&) -> optional<string>
{
if (meta->arguments().find("include:") != 0)
.validOn = {typeid(Unit)},
.acceptedArgumentKind = MetadataArgumentKind::RequiredTextArgument,
.extraValidation = [](const MetadataPtr& meta, const SyntaxTreeBasePtr&) -> optional<string>
{
ostringstream msg;
msg << "ignoring unknown metadata: '" << meta << '\'';
return msg.str();
}
return nullopt;
if (meta->arguments().find("include:") != 0)
{
ostringstream msg;
msg << "ignoring unknown metadata: '" << meta << '\'';
return msg.str();
}
return nullopt;
},
};
knownMetadata.emplace("cpp:doxygen", std::move(doxygenInfo));

// "cpp:header-ext"
MetadataInfo headerExtInfo = {
{typeid(Unit)},
MetadataArgumentKind::SingleArgument,
.validOn = {typeid(Unit)},
.acceptedArgumentKind = MetadataArgumentKind::SingleArgument,
};
knownMetadata.emplace("cpp:header-ext", std::move(headerExtInfo));

// "cpp:ice_print"
MetadataInfo icePrintInfo = {
{typeid(Exception)},
MetadataArgumentKind::NoArguments,
.validOn = {typeid(Exception)},
.acceptedArgumentKind = MetadataArgumentKind::NoArguments,
};
knownMetadata.emplace("cpp:ice_print", std::move(icePrintInfo));

// "cpp:include"
MetadataInfo includeInfo = {
{typeid(Unit)},
MetadataArgumentKind::RequiredTextArgument,
.validOn = {typeid(Unit)},
.acceptedArgumentKind = MetadataArgumentKind::RequiredTextArgument,
.mustBeUnique = false,
};
includeInfo.mustBeUnique = false;
knownMetadata.emplace("cpp:include", std::move(includeInfo));

// "cpp:no-default-include"
MetadataInfo noDefaultIncludeInfo = {
{typeid(Unit)},
MetadataArgumentKind::NoArguments,
.validOn = {typeid(Unit)},
.acceptedArgumentKind = MetadataArgumentKind::NoArguments,
};
knownMetadata.emplace("cpp:no-default-include", std::move(noDefaultIncludeInfo));

// "cpp:no-stream"
MetadataInfo noStreamInfo = {
{typeid(Unit)},
MetadataArgumentKind::NoArguments,
.validOn = {typeid(Unit)},
.acceptedArgumentKind = MetadataArgumentKind::NoArguments,
};
knownMetadata.emplace("cpp:no-stream", std::move(noStreamInfo));

// "cpp:source-ext"
MetadataInfo sourceExtInfo = {
{typeid(Unit)},
MetadataArgumentKind::SingleArgument,
.validOn = {typeid(Unit)},
.acceptedArgumentKind = MetadataArgumentKind::SingleArgument,
};
knownMetadata.emplace("cpp:source-ext", std::move(sourceExtInfo));

// "cpp:source-include"
MetadataInfo sourceIncludeInfo = {
{typeid(Unit)},
MetadataArgumentKind::RequiredTextArgument,
.validOn = {typeid(Unit)},
.acceptedArgumentKind = MetadataArgumentKind::RequiredTextArgument,
.mustBeUnique = false,
};
sourceIncludeInfo.mustBeUnique = false;
knownMetadata.emplace("cpp:source-include", std::move(sourceIncludeInfo));

// "cpp:unscoped"
MetadataInfo unscopedInfo = {
{typeid(Enum)},
MetadataArgumentKind::NoArguments,
.validOn = {typeid(Enum)},
.acceptedArgumentKind = MetadataArgumentKind::NoArguments,
};
knownMetadata.emplace("cpp:unscoped", std::move(unscopedInfo));

// "cpp:view-type"
MetadataInfo viewTypeInfo = {
{typeid(Sequence), typeid(Dictionary)},
MetadataArgumentKind::RequiredTextArgument,
nullopt,
MetadataApplicationContext::ParameterTypeReferences,
.validOn = {typeid(Sequence), typeid(Dictionary)},
.acceptedArgumentKind = MetadataArgumentKind::RequiredTextArgument,
.acceptedContext = MetadataApplicationContext::ParameterTypeReferences,
};
knownMetadata.emplace("cpp:view-type", std::move(viewTypeInfo));

Expand All @@ -970,44 +968,46 @@ Slice::Gen::validateMetadata(const UnitPtr& u)
// One for switching between wide and narrow strings, and another for customizing the mapping of sequences/dicts.
// Thankfully, there is no overlap in what these can be applied to, but having separate cases like this still means
// the validation framework isn't useful here. So, we turn off almost everything, and use a custom function instead.
MetadataInfo typeInfo;
typeInfo.acceptedArgumentKind = MetadataArgumentKind::RequiredTextArgument;
typeInfo.acceptedContexts = MetadataApplicationContext::DefinitionsAndTypeReferences;
typeInfo.extraValidation = [](const MetadataPtr& meta, const SyntaxTreeBasePtr& p) -> optional<string>
{
// 'cpp:type' can be placed on containers, but only if it is the 'string' flavor of the metadata.
if (dynamic_pointer_cast<Module>(p) || dynamic_pointer_cast<InterfaceDecl>(p) ||
dynamic_pointer_cast<ClassDecl>(p) || dynamic_pointer_cast<Struct>(p) ||
dynamic_pointer_cast<Slice::Exception>(p))
{
const string& argument = meta->arguments();
if (argument != "string" && argument != "wstring")
MetadataInfo typeInfo = {
.validOn = {}, // Setting it to an empty list skips this validation step. We do it all in `extraValidation`.
.acceptedArgumentKind = MetadataArgumentKind::RequiredTextArgument,
.acceptedContext = MetadataApplicationContext::DefinitionsAndTypeReferences,
.extraValidation = [](const MetadataPtr& meta, const SyntaxTreeBasePtr& p) -> optional<string>
{
// 'cpp:type' can be placed on containers, but only if it is the 'string' flavor of the metadata.
if (dynamic_pointer_cast<Module>(p) || dynamic_pointer_cast<InterfaceDecl>(p) ||
dynamic_pointer_cast<ClassDecl>(p) || dynamic_pointer_cast<Struct>(p) ||
dynamic_pointer_cast<Slice::Exception>(p))
{
return "invalid argument '" + argument + "' supplied to 'cpp:type' metadata in this context";
const string& argument = meta->arguments();
if (argument != "string" && argument != "wstring")
{
return "invalid argument '" + argument + "' supplied to 'cpp:type' metadata in this context";
}
return nullopt;
}
return nullopt;
}

// Otherwise, the metadata must of been applied to a type reference.
if (auto builtin = dynamic_pointer_cast<Builtin>(p); builtin && builtin->kind() == Builtin::KindString)
{
const string& argument = meta->arguments();
if (argument != "string" && argument != "wstring")
// Otherwise, the metadata must of been applied to a type reference.
if (auto builtin = dynamic_pointer_cast<Builtin>(p); builtin && builtin->kind() == Builtin::KindString)
{
const string& argument = meta->arguments();
if (argument != "string" && argument != "wstring")
{
return "invalid argument '" + argument + "' supplied to 'cpp:type' metadata in this context";
}
return nullopt;
}
else if (
dynamic_pointer_cast<Sequence>(p) || dynamic_pointer_cast<Dictionary>(p) ||
dynamic_pointer_cast<ClassDecl>(p))
{
return "invalid argument '" + argument + "' supplied to 'cpp:type' metadata in this context";
return nullopt; // TODO: I see no reason to support 'cpp:type' on class declarations.
}
return nullopt;
}
else if (
dynamic_pointer_cast<Sequence>(p) || dynamic_pointer_cast<Dictionary>(p) ||
dynamic_pointer_cast<ClassDecl>(p))
{
return nullopt; // TODO: I see no reason to support 'cpp:type' on class declarations.
}
else
{
return Slice::misappliedMetadataMessage(meta, p);
}
else
{
return Slice::misappliedMetadataMessage(meta, p);
}
},
};
knownMetadata.emplace("cpp:type", typeInfo);

Expand Down
Loading

0 comments on commit d9a2cd9

Please sign in to comment.