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

Configurable warnings #2319

Merged
merged 6 commits into from
Oct 27, 2022
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
3 changes: 2 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ set(SOUFFLE_SOURCES
ram/transform/Transformer.cpp
ram/transform/TupleId.cpp
ram/utility/NodeMapper.cpp
reports/ErrorReport.cpp
reports/DebugReport.cpp
synthesiser/Synthesiser.cpp
synthesiser/Relation.cpp
Expand Down Expand Up @@ -317,7 +318,7 @@ target_link_libraries(souffle libsouffle)
install(TARGETS souffle DESTINATION bin)

if (EMSCRIPTEN)
target_link_libraries(souffle -sMODULARIZE=1
target_link_libraries(souffle -sMODULARIZE=1
-s'EXPORTED_RUNTIME_METHODS=["FS"]' -sEXPORT_NAME="SOUFFLE")
endif()

Expand Down
12 changes: 8 additions & 4 deletions src/ast/transform/SemanticChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,8 @@ void SemanticCheckerImpl::checkClause(const Clause& clause) {
if (varName[0] == '_') {
assert(varName.size() > 1 && "named variable should not be a single underscore");
if (numAppearances > 1) {
report.addWarning("Variable " + varName + " marked as singleton but occurs more than once",
report.addWarning(WarnType::VarAppearsOnce,
"Variable " + varName + " marked as singleton but occurs more than once",
varLocation);
}
}
Expand Down Expand Up @@ -548,7 +549,8 @@ void SemanticCheckerImpl::checkComplexRule(const std::set<const Clause*>& multiR
const auto& varName = cur.first;
const auto& varLocation = var_pos[varName]->getSrcLoc();
if (varName[0] != '_' && numAppearances == 1) {
report.addWarning("Variable " + varName + " only occurs once", varLocation);
report.addWarning(
WarnType::VarAppearsOnce, "Variable " + varName + " only occurs once", varLocation);
}
}
}
Expand Down Expand Up @@ -643,7 +645,8 @@ void SemanticCheckerImpl::checkRelation(const Relation& relation) {
return sClause.getHead()->getQualifiedName() == relation.getQualifiedName();
});
if (relation.getRepresentation() == RelationRepresentation::BTREE_DELETE && !hasSubsumptiveRule) {
report.addWarning("No subsumptive rule for relation " + toString(relation.getQualifiedName()),
report.addWarning(WarnType::NoSubsumptiveRule,
"No subsumptive rule for relation " + toString(relation.getQualifiedName()),
relation.getSrcLoc());
} else if (relation.getRepresentation() != RelationRepresentation::BTREE_DELETE && hasSubsumptiveRule) {
report.addError("Relation \"" + toString(relation.getQualifiedName()) +
Expand All @@ -666,7 +669,8 @@ void SemanticCheckerImpl::checkRelation(const Relation& relation) {
// check whether this relation is empty
if (program.getClauses(relation).empty() && !ioTypes.isInput(&relation) &&
!relation.hasQualifier(RelationQualifier::SUPPRESSED)) {
report.addWarning("No rules/facts defined for relation " + toString(relation.getQualifiedName()),
report.addWarning(WarnType::NoRulesNorFacts,
"No rules/facts defined for relation " + toString(relation.getQualifiedName()),
relation.getSrcLoc());
}
}
Expand Down
39 changes: 38 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,38 @@ class MCPPPreprocInput : public PreprocInput {
}
};

static WarnSet process_warn_opts(void) {
WarnSet warns;
if (!Global::config().has("no-warn")) {
if (Global::config().has("warn")) {
for (auto&& option : Global::config().getMany("warn")) {
if (option == "all") {
warns.set();
} else {
auto valid = warns.setStr(option);
if (!valid) {
throw std::runtime_error("no such warning " + std::string(option));
}
}
}
}
if (Global::config().has("wno")) {
for (auto&& option : Global::config().getMany("wno")) {
if (option == "none") { // default
} else if (option == "all") {
warns.reset();
} else {
auto valid = warns.resetStr(option);
if (!valid) {
throw std::runtime_error("no such warning " + std::string(option));
}
}
}
}
}
return warns;
}

int main(int argc, char** argv) {
/* Time taking for overall runtime */
auto souffle_start = std::chrono::high_resolution_clock::now();
Expand Down Expand Up @@ -423,6 +455,10 @@ int main(int argc, char** argv) {
{"library-dir", 'L', "DIR", "", true, "Specify directory for library files."},
{"libraries", 'l', "FILE", "", true, "Specify libraries."},
{"no-warn", 'w', "", "", false, "Disable warnings."},
{"warn", 'W', "WARN", "all", true, "Enable a warning."},
{"wno", '\xb', "WARN", "none", true, "Disable a specific warning."},
// TODO(lb):
// {"Werror", '\xc', "WARN", "none", false, "Turn a warning into an error."},
{"magic-transform", 'm', "RELATIONS", "", false,
"Enable magic set transformation changes on the given relations, use '*' "
"for all."},
Expand Down Expand Up @@ -619,7 +655,8 @@ int main(int argc, char** argv) {
// ------- parse program -------------

// parse file
ErrorReport errReport(Global::config().has("no-warn"));
ErrorReport errReport(process_warn_opts());

DebugReport debugReport;
Own<ast::TranslationUnit> astTranslationUnit = ParserDriver::parseTranslationUnit(
InputPath.string(), Input->getInputStream(), errReport, debugReport);
Expand Down
11 changes: 6 additions & 5 deletions src/parser/ParserDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,14 +209,15 @@ void ParserDriver::addIoFromDeprecatedTag(ast::Relation& rel) {
std::set<RelationTag> ParserDriver::addDeprecatedTag(
RelationTag tag, SrcLocation tagLoc, std::set<RelationTag> tags) {
if (!Global::config().has("legacy")) {
warning(tagLoc, tfm::format("Deprecated %s qualifier was used", tag));
warning(WarnType::DeprecatedQualifier, tagLoc, tfm::format("Deprecated %s qualifier was used", tag));
}
return addTag(tag, std::move(tagLoc), std::move(tags));
}

Own<ast::Counter> ParserDriver::addDeprecatedCounter(SrcLocation tagLoc) {
if (!Global::config().has("legacy")) {
warning(tagLoc, "Deprecated $ symbol was used. Use functor 'autoinc()' instead.");
warning(WarnType::DollarSign, tagLoc,
"Deprecated $ symbol was used. Use functor 'autoinc()' instead.");
}
return mk<ast::Counter>();
}
Expand Down Expand Up @@ -244,13 +245,13 @@ std::set<RelationTag> ParserDriver::addTag(RelationTag tag, std::vector<Relation
Own<ast::SubsetType> ParserDriver::mkDeprecatedSubType(
ast::QualifiedName name, ast::QualifiedName baseTypeName, SrcLocation loc) {
if (!Global::config().has("legacy")) {
warning(loc, "Deprecated type declaration used");
warning(WarnType::DeprecatedTypeDecl, loc, "Deprecated type declaration used");
}
return mk<ast::SubsetType>(std::move(name), std::move(baseTypeName), std::move(loc));
}

void ParserDriver::warning(const SrcLocation& loc, const std::string& msg) {
translationUnit->getErrorReport().addWarning(msg, loc);
void ParserDriver::warning(const WarnType type, const SrcLocation& loc, const std::string& msg) {
translationUnit->getErrorReport().addWarning(type, msg, loc);
}
void ParserDriver::error(const SrcLocation& loc, const std::string& msg) {
translationUnit->getErrorReport().addError(msg, loc);
Expand Down
2 changes: 1 addition & 1 deletion src/parser/ParserDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class ParserDriver {
static Own<ast::TranslationUnit> parseTranslationUnit(
const std::string& code, ErrorReport& errorReport, DebugReport& debugReport);

void warning(const SrcLocation& loc, const std::string& msg);
void warning(const WarnType warn, const SrcLocation& loc, const std::string& msg);
void error(const SrcLocation& loc, const std::string& msg);
void error(const std::string& msg);

Expand Down
76 changes: 76 additions & 0 deletions src/reports/ErrorReport.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Souffle - A Datalog Compiler
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved
* Licensed under the Universal Permissive License v 1.0 as shown at:
* - https://opensource.org/licenses/UPL
* - <souffle root>/licenses/SOUFFLE-UPL.txt
*/

/************************************************************************
*
* @file reports/ErrorReport.h
*
* Defines a class for error reporting.
*
***********************************************************************/

#include "reports/ErrorReport.h"

namespace souffle {

std::optional<WarnType> WarnSet::warnTypeFromString(const std::string& s) {
if (s == "deprecated-type-decl") {
return std::optional<WarnType>(WarnType::DeprecatedTypeDecl);
} else if (s == "deprecated-qualifier") {
return std::optional<WarnType>(WarnType::DeprecatedQualifier);
} else if (s == "dollar-sign") {
return std::optional<WarnType>(WarnType::DollarSign);
} else if (s == "no-rules-nor-facts") {
return std::optional<WarnType>(WarnType::NoRulesNorFacts);
} else if (s == "no-subsumptive-rule") {
return std::optional<WarnType>(WarnType::NoSubsumptiveRule);
} else if (s == "var-appears-once") {
return std::optional<WarnType>(WarnType::VarAppearsOnce);
}
return std::optional<WarnType>(std::nullopt);
}

bool WarnSet::test(const WarnType warn) {
return warns.test(static_cast<std::size_t>(warn));
}

void WarnSet::set(const WarnType warn) {
warns.set(static_cast<std::size_t>(warn));
}

void WarnSet::set() {
warns.set();
}

void WarnSet::reset(const WarnType warn) {
warns.reset(static_cast<std::size_t>(warn));
}

void WarnSet::reset() {
warns.reset();
}

bool WarnSet::setStr(const std::string& str) {
const auto warn = warnTypeFromString(str);
if (warn.has_value()) {
this->set(warn.value());
return true;
}
return false;
}

bool WarnSet::resetStr(const std::string& str) {
const auto warn = warnTypeFromString(str);
if (warn.has_value()) {
this->reset(warn.value());
return true;
}
return false;
}

}; // namespace souffle
62 changes: 58 additions & 4 deletions src/reports/ErrorReport.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@

#include "parser/SrcLocation.h"
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cstdlib>
#include <iostream>
#include <optional>
#include <set>
#include <string>
#include <utility>
Expand Down Expand Up @@ -143,9 +145,61 @@ class Diagnostic {
std::vector<DiagnosticMessage> additionalMessages;
};

enum class WarnType : std::size_t {
DeprecatedTypeDecl,
DeprecatedQualifier,
DollarSign,
NoRulesNorFacts,
NoSubsumptiveRule,
// This last element is used as the size parameter to std::bitset in the
// definition of WarnSet. If the last element changes, the definition of
// WarnSet must be updated accordingly.
VarAppearsOnce,
};

class WarnSet {
public:
WarnSet() : warns(std::bitset<(std::size_t)WarnType::VarAppearsOnce + 1>()) {
this->set(); // default to enabling all warnings
}

WarnSet(const WarnSet& other) = default;

bool test(const WarnType warn);

// Enable all warnings
void set();

// Enable one warning
void set(const WarnType warn);

// Disable all warnings
void reset(const WarnType warn);

// Disable one warning
void reset();

// Enable one warning
//
// Returns whether or not the string was valid
bool setStr(const std::string& str);

// Disable one warning
//
// Returns whether or not the string was valid
bool resetStr(const std::string& str);

private:
std::bitset<(std::size_t)WarnType::VarAppearsOnce + 1> warns;

std::optional<WarnType> warnTypeFromString(const std::string& s);
};

class ErrorReport {
public:
ErrorReport(bool nowarn = false) : nowarn(nowarn) {}
ErrorReport() : warns(WarnSet()) {}

ErrorReport(WarnSet warns) : warns(warns) {}

ErrorReport(const ErrorReport& other) = default;

Expand All @@ -170,8 +224,8 @@ class ErrorReport {
}

/** Adds a warning with the given message and location */
void addWarning(const std::string& message, SrcLocation location) {
if (!nowarn) {
void addWarning(const WarnType type, const std::string& message, SrcLocation location) {
if (warns.test(type)) {
diagnostics.insert(
Diagnostic(Diagnostic::Type::WARNING, DiagnosticMessage(message, std::move(location))));
}
Expand Down Expand Up @@ -203,7 +257,7 @@ class ErrorReport {

private:
std::set<Diagnostic> diagnostics;
bool nowarn;
WarnSet warns;
};

} // end of namespace souffle