Skip to content

Commit

Permalink
Add a new check to the WML schema self-validator
Browse files Browse the repository at this point in the history
This warns about tag definitions that can never match any tag (or for which one element of the comma-separated list can never match) because there is an earlier-defined tag definition that would match it instead.

The new check also found some errors in the schema, which have been fixed.
  • Loading branch information
CelticMinstrel committed Oct 24, 2020
1 parent 24b2a50 commit 62fbb53
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 9 deletions.
9 changes: 2 additions & 7 deletions data/schema/core/actionwml.cfg
Expand Up @@ -94,12 +94,7 @@
name="while"
max=infinite
super="$conditional_wml"
{ACTION_TAG "do" min,max=0,infinite}
[tag]
name="do"
max=infinite
super="$action_wml"
[/tag]
{ACTION_TAG "do" max=infinite}
[/tag]
[tag]
name="for"
Expand Down Expand Up @@ -261,7 +256,7 @@
{REQUIRED_KEY types string_list}
[/tag]
[tag]
name="allow_extra recruit,disallow_extra_recruit,set_recruit"
name="allow_extra_recruit,disallow_extra_recruit,set_extra_recruit"
max=infinite
super="$filter_unit"
{INSERT_TAG}
Expand Down
1 change: 0 additions & 1 deletion data/schema/schema.cfg
Expand Up @@ -92,7 +92,6 @@
[tag]
name="intersection"
min=1
{LINK_TAG "wml_schema/type"}
[tag]
name="type"
max=infinite
Expand Down
48 changes: 48 additions & 0 deletions src/serialization/schema_validator.cpp
Expand Up @@ -128,6 +128,18 @@ static void wrong_path_error(const std::string& file,
print_output(ss.str(), flag_exception);
}

static void duplicate_tag_error(const std::string& file,
int line,
const std::string& tag,
const std::string& key,
const std::string& value,
bool flag_exception)
{
std::ostringstream ss;
ss << "Duplicate or fully-overlapping tag definition '" << value << "' in key '" << key << "=' in tag [" << tag << "]\n" << at(file, line) << "\n";
print_output(ss.str(), flag_exception);
}

static void wrong_type_error(const std::string & file, int line,
const std::string & tag,
const std::string & key,
Expand Down Expand Up @@ -446,10 +458,43 @@ bool schema_self_validator::tag_path_exists(const config& cfg, const reference&
return false;
}

bool schema_self_validator::tag_matches(const std::string& pattern, const std::string& tag)
{
for(const std::string& pat : utils::split(pattern)) {
if(utils::wildcard_string_match(tag, pat)) return true;
}
return false;
}

void schema_self_validator::validate(const config& cfg, const std::string& name, int start_line, const std::string& file)
{
if(type_nesting_ == 1 && name == "type") {
defined_types_.insert(cfg["name"]);
} else if(name == "tag") {
bool first = true;
std::vector<std::string> tag_names;
for(auto current : cfg.all_children_range()) {
if(current.key != "tag" && current.key != "link") continue;
std::string tag_name = current.cfg["name"];
if(current.key == "link") {
tag_name.erase(0, tag_name.find_last_of('/') + 1);
}
if(first) {
tag_names.push_back(tag_name);
first = false;
continue;
}
auto split = utils::split(tag_name);
for(const std::string& pattern : tag_names) {
for(const std::string& tag : split) {
if(tag_matches(pattern, tag)) {
queue_message(current.cfg, DUPLICATE_TAG, file, start_line, 0, current.key, "name", tag_name);
continue;
}
}
}
tag_names.push_back(tag_name);
}
} else if(name == "wml_schema") {
using namespace std::placeholders;
std::vector<reference> missing_types = referenced_types_, missing_tags = referenced_tag_paths_;
Expand Down Expand Up @@ -551,6 +596,9 @@ void schema_self_validator::print(message_info& el)
case WRONG_PATH:
wrong_path_error(el.file, el.line, el.tag, el.key, el.value, create_exceptions_);
break;
case DUPLICATE_TAG:
duplicate_tag_error(el.file, el.line, el.tag, el.key, el.value, create_exceptions_);
break;
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/serialization/schema_validator.hpp
Expand Up @@ -182,8 +182,10 @@ class schema_self_validator : public schema_validator
std::multimap<std::string, std::string> derivations_;
int type_nesting_, condition_nesting_;
bool tag_path_exists(const config& cfg, const reference& ref);
static bool tag_matches(const std::string& pattern, const std::string& tag);

void print(message_info& message) override;
enum { WRONG_TYPE = NEXT_ERROR, WRONG_PATH, NEXT_ERROR };
enum { WRONG_TYPE = NEXT_ERROR, WRONG_PATH, DUPLICATE_TAG, NEXT_ERROR };
};

} // namespace schema_validation{

0 comments on commit 62fbb53

Please sign in to comment.