//===- TreeView.cpp - diagtool tool for printing warning flags ------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "DiagTool.h" #include "DiagnosticNames.h" #include "clang/Basic/AllDiagnostics.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" #include "llvm/ADT/DenseSet.h" #include "llvm/Support/Format.h" #include "llvm/Support/Process.h" DEF_DIAGTOOL("tree", "Show warning flags in a tree view", TreeView) using namespace clang; using namespace diagtool; class TreePrinter { using Colors = llvm::raw_ostream::Colors; public: llvm::raw_ostream &out; bool Internal; TreePrinter(llvm::raw_ostream &out) : out(out), Internal(false) {} static bool isIgnored(unsigned DiagID) { // FIXME: This feels like a hack. static clang::DiagnosticsEngine Diags(new DiagnosticIDs, new DiagnosticOptions); return Diags.isIgnored(DiagID, SourceLocation()); } static bool enabledByDefault(const GroupRecord &Group) { for (const DiagnosticRecord &DR : Group.diagnostics()) { if (isIgnored(DR.DiagID)) return false; } for (const GroupRecord &GR : Group.subgroups()) { if (!enabledByDefault(GR)) return false; } return true; } void printGroup(const GroupRecord &Group, unsigned Indent = 0) { out.indent(Indent * 2); if (enabledByDefault(Group)) out << Colors::GREEN; else out << Colors::YELLOW; out << "-W" << Group.getName() << "\n" << Colors::RESET; ++Indent; for (const GroupRecord &GR : Group.subgroups()) { printGroup(GR, Indent); } if (Internal) { for (const DiagnosticRecord &DR : Group.diagnostics()) { if (!isIgnored(DR.DiagID)) out << Colors::GREEN; out.indent(Indent * 2); out << DR.getName() << Colors::RESET << "\n"; } } } int showGroup(StringRef RootGroup) { ArrayRef AllGroups = getDiagnosticGroups(); if (RootGroup.size() > UINT16_MAX) { llvm::errs() << "No such diagnostic group exists\n"; return 1; } const GroupRecord *Found = llvm::lower_bound(AllGroups, RootGroup); if (Found == AllGroups.end() || Found->getName() != RootGroup) { llvm::errs() << "No such diagnostic group exists\n"; return 1; } printGroup(*Found); return 0; } int showAll() { ArrayRef AllGroups = getDiagnosticGroups(); llvm::DenseSet NonRootGroupIDs; for (const GroupRecord &GR : AllGroups) { for (auto SI = GR.subgroup_begin(), SE = GR.subgroup_end(); SI != SE; ++SI) { NonRootGroupIDs.insert((unsigned)SI.getID()); } } assert(NonRootGroupIDs.size() < AllGroups.size()); for (unsigned i = 0, e = AllGroups.size(); i != e; ++i) { if (!NonRootGroupIDs.count(i)) printGroup(AllGroups[i]); } return 0; } void showKey() { out << '\n' << Colors::GREEN << "GREEN" << Colors::RESET << " = enabled by default\n\n"; } }; static void printUsage() { llvm::errs() << "Usage: diagtool tree [--internal] []\n"; } int TreeView::run(unsigned int argc, char **argv, llvm::raw_ostream &out) { // First check our one flag (--flags-only). bool Internal = false; if (argc > 0) { StringRef FirstArg(*argv); if (FirstArg.equals("--internal")) { Internal = true; --argc; ++argv; } } bool ShowAll = false; StringRef RootGroup; switch (argc) { case 0: ShowAll = true; break; case 1: RootGroup = argv[0]; if (RootGroup.startswith("-W")) RootGroup = RootGroup.substr(2); if (RootGroup == "everything") ShowAll = true; // FIXME: Handle other special warning flags, like -pedantic. break; default: printUsage(); return -1; } out.enable_colors(out.has_colors()); TreePrinter TP(out); TP.Internal = Internal; TP.showKey(); return ShowAll ? TP.showAll() : TP.showGroup(RootGroup); }