Skip to content

Commit

Permalink
[slang-tidy] Add quiet options and IDs to slang-tidy checks (#1020)
Browse files Browse the repository at this point in the history
This commit adds two options -q,--quiet and --super-quiet to make
slang-tidy less verbose.

Also adds another option --code that will give information about the
check identified with the code provided.

To facilitate identifying checks, at check failure the check will print
its identifier in the explanation message
  • Loading branch information
Sustrak committed Jun 11, 2024
1 parent 62d3958 commit 07b7d65
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 33 deletions.
2 changes: 1 addition & 1 deletion tools/tidy/include/ASTHelperVisitors.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ struct TidyVisitor {

[[nodiscard]] bool skip(std::string_view path) const {
auto file = std::filesystem::path(path).filename().string();
auto parentPath = weakly_canonical(std::filesystem::path(path));
auto parentPath = weakly_canonical(std::filesystem::path(path).parent_path());
const auto& skipFiles = config.getSkipFiles();
const auto& skipPaths = config.getSkipPaths();
return std::find(skipFiles.begin(), skipFiles.end(), file) != skipFiles.end() ||
Expand Down
6 changes: 6 additions & 0 deletions tools/tidy/include/TidyFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ class TidyCheck {
virtual slang::DiagnosticSeverity diagSeverity() const = 0;
virtual std::string diagString() const = 0;

std::string diagMessage() const {
auto kindStr = std::string(toString(kind));
std::transform(kindStr.begin(), kindStr.end(), kindStr.begin(), ::toupper);
return fmt::format("[{}-{}] {}", kindStr, diagCode().getCode(), diagString());
}

[[nodiscard]] virtual const slang::Diagnostics& getDiagnostics() const { return diagnostics; }
[[nodiscard]] virtual const slang::TidyKind getKind() const { return kind; }

Expand Down
2 changes: 1 addition & 1 deletion tools/tidy/include/TidyKind.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ SLANG_ENUM(TidyKind, KIND)

inline std::optional<slang::TidyKind> tidyKindFromStr(std::string str) {
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
if (str == "synthesis")
if (str == "synthesis" || str == "synth")
return slang::TidyKind::Synthesis;
if (str == "style")
return slang::TidyKind::Style;
Expand Down
136 changes: 105 additions & 31 deletions tools/tidy/src/tidy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
#include <filesystem>
#include <unordered_set>

#include "slang/ast/Compilation.h"
#include "slang/diagnostics/TextDiagnosticClient.h"
#include "slang/driver/Driver.h"
#include "slang/util/VersionInfo.h"
Expand Down Expand Up @@ -51,12 +50,27 @@ int main(int argc, char** argv) {
std::vector<std::string> skippedPaths;
driver.cmdLine.add("--skip-path", skippedPaths, "Paths to be skipped by slang-tidy");

std::optional<bool> quietArg;
driver.cmdLine.add("-q,--quiet", quietArg,
"slang-tidy will only print errors. Options that make slang-tidy print "
"information will not be affected by this.");
std::optional<bool> superQuietArg;
driver.cmdLine.add("--super-quiet", superQuietArg,
"slang-tidy will not print anything. Options that make slang-tidy print "
"information will not be affected by this.");

std::optional<std::string> infoCode;
driver.cmdLine.add("--code", infoCode, "print information about the error or warning.");

if (!driver.parseCommandLine(argc, argv))
return 1;

bool superQuiet = superQuietArg.value_or(false);
// slang-tidy on superQuiet mode, also implies being in quiet mode
bool quiet = quietArg.value_or(false) || superQuiet;

if (showHelp) {
slang::OS::print(
fmt::format("{}", driver.cmdLine.getHelpText("slang SystemVerilog linter")));
OS::print(fmt::format("{}", driver.cmdLine.getHelpText("slang SystemVerilog linter")));
return 0;
}

Expand All @@ -67,28 +81,40 @@ int main(int argc, char** argv) {
return 0;
}

// Create the config class and populate it with the config file if provided
TidyConfig tidyConfig;
if (tidyConfigFile) {
if (!exists(std::filesystem::path(tidyConfigFile.value()))) {
slang::OS::printE(fmt::format("the path provided for the config file does not exist {}",
tidyConfigFile.value()));
tidyConfig = TidyConfigParser(tidyConfigFile.value()).getConfig();
if (infoCode) {
// Create a sourceManage placeholder
auto sm = SourceManager();
Registry::setSourceManager(&sm);

// Get the ID and kind from the check code string
auto hypenPos = infoCode->find('-');
if (hypenPos == std::string::npos) {
OS::printE("Check code has not the correct format. Format should be ABCD-<id>\n");
return 1;
}
else {
tidyConfig =
TidyConfigParser(std::filesystem::path(tidyConfigFile.value())).getConfig();
auto kindStr = infoCode->substr(0, hypenPos);

// Parse the ID and kind
auto kind = tidyKindFromStr(kindStr);
auto id = stoull(infoCode->substr(hypenPos + 1));

if (!kind) {
OS::printE(fmt::format("Check kind {} does not exist\n", kindStr));
return 1;
}
}
else if (auto path = project_slang_tidy_config()) {
tidyConfig = TidyConfigParser(path.value()).getConfig();
}

// Add skipped files provided by the cmd args
tidyConfig.addSkipFile(skippedFiles);
for (const auto& checkName : Registry::getRegisteredChecks()) {
const auto check = Registry::create(checkName);
if (check->diagCode().getCode() == id && check->getKind() == kind) {
OS::print(fmt::format(fmt::emphasis::bold, "[{}]\n", check->name()));
OS::print(fmt::format("{}", check->description()));
return 0;
}
}

// Add skipped paths provided by the cmd args
tidyConfig.addSkipPath(skippedPaths);
OS::printE(fmt::format("Check code {} does not exist\n", *infoCode));
return 1;
}

// Print (short)descriptions of the checks
if (printDescriptions || printShortDescriptions) {
Expand All @@ -112,6 +138,31 @@ int main(int argc, char** argv) {
return 0;
}

// Create the config class and populate it with the config file if provided
TidyConfig tidyConfig;
if (tidyConfigFile) {
if (!exists(std::filesystem::path(tidyConfigFile.value()))) {
if (!superQuiet)
OS::printE(fmt::format("the path provided for the config file does not exist {}",
tidyConfigFile.value()));
// Exit with error if the config file cannot be found
return 1;
}
else {
tidyConfig =
TidyConfigParser(std::filesystem::path(tidyConfigFile.value())).getConfig();
}
}
else if (auto path = project_slang_tidy_config()) {
tidyConfig = TidyConfigParser(path.value()).getConfig();
}

// Add skipped files provided by the cmd args
tidyConfig.addSkipFile(skippedFiles);

// Add skipped paths provided by the cmd args
tidyConfig.addSkipPath(skippedPaths);

if (!driver.processOptions())
return 1;

Expand All @@ -124,13 +175,13 @@ int main(int argc, char** argv) {
}
SLANG_CATCH(const std::exception& e) {
#if __cpp_exceptions
slang::OS::printE(fmt::format("internal compiler error: {}\n", e.what()));
OS::printE(fmt::format("internal compiler error: {}\n", e.what()));
#endif
return 1;
}

if (!compilationOk) {
slang::OS::print("slang-tidy: errors found during compilation\n");
OS::printE("slang-tidy: errors found during compilation\n");
return 1;
}

Expand All @@ -144,28 +195,51 @@ int main(int argc, char** argv) {
// Check all enabled checks
for (const auto& checkName : Registry::getEnabledChecks()) {
const auto check = Registry::create(checkName);
OS::print(fmt::format("[{}]", check->name()));

driver.diagEngine.setMessage(check->diagCode(), check->diagString());
if (!quiet)
OS::print(fmt::format("[{}]", check->name()));

driver.diagEngine.setMessage(check->diagCode(), check->diagMessage());
driver.diagEngine.setSeverity(check->diagCode(), check->diagSeverity());

auto checkOk = check->check(compilation->getRoot());
if (!checkOk) {
retCode = 1;
OS::print(fmt::emphasis::bold | fmt::fg(fmt::color::red), " FAIL\n");
for (const auto& diag : check->getDiagnostics())
driver.diagEngine.issue(diag);
OS::print(fmt::format("{}\n", driver.diagClient->getString()));
driver.diagClient->clear();

if (!quiet) {
if (check->diagSeverity() == DiagnosticSeverity::Warning) {
OS::print(fmt::emphasis::bold | fmt::fg(driver.diagClient->getSeverityColor(
DiagnosticSeverity::Warning)),
" WARN\n");
}
else if (check->diagSeverity() == DiagnosticSeverity::Error) {
OS::print(fmt::emphasis::bold | fmt::fg(driver.diagClient->getSeverityColor(
DiagnosticSeverity::Error)),
" FAIL\n");
}
else {
SLANG_UNREACHABLE;
}
}

if (!superQuiet) {
for (const auto& diag : check->getDiagnostics()) {
driver.diagEngine.issue(diag);
}
OS::print(fmt::format("{}\n", driver.diagClient->getString()));
driver.diagClient->clear();
}
}
else {
OS::print(fmt::emphasis::bold | fmt::fg(fmt::color::green), " PASS\n");
if (!quiet)
OS::print(fmt::emphasis::bold | fmt::fg(fmt::color::green), " PASS\n");
}
}

return retCode;
}

/// Searches for a .slang-tidy file from the current path until the root '/'
std::optional<std::filesystem::path> project_slang_tidy_config() {
std::optional<std::filesystem::path> ret = {};
auto cwd = std::filesystem::current_path();
Expand Down

0 comments on commit 07b7d65

Please sign in to comment.