diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2012-08-15 20:02:54 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2012-08-15 20:02:54 +0000 |
commit | 56d91b49b13fe55c918afbda19f6165b5fbff87a (patch) | |
tree | 9abb1a658a297776086f4e0dfa6ca533de02104e /tools/diagtool | |
parent | 41e20f564abdb05101d6b2b29c59459a966c22cc (diff) |
Notes
Diffstat (limited to 'tools/diagtool')
-rw-r--r-- | tools/diagtool/CMakeLists.txt | 28 | ||||
-rw-r--r-- | tools/diagtool/DiagnosticNames.cpp | 78 | ||||
-rw-r--r-- | tools/diagtool/DiagnosticNames.h | 128 | ||||
-rw-r--r-- | tools/diagtool/ListWarnings.cpp | 37 | ||||
-rw-r--r-- | tools/diagtool/Makefile | 10 | ||||
-rw-r--r-- | tools/diagtool/ShowEnabledWarnings.cpp | 148 | ||||
-rw-r--r-- | tools/diagtool/TreeView.cpp | 135 | ||||
-rw-r--r-- | tools/diagtool/diagtool_main.cpp | 2 |
8 files changed, 524 insertions, 42 deletions
diff --git a/tools/diagtool/CMakeLists.txt b/tools/diagtool/CMakeLists.txt index f1fd9de03be0e..a107cbd70bb8c 100644 --- a/tools/diagtool/CMakeLists.txt +++ b/tools/diagtool/CMakeLists.txt @@ -1,24 +1,32 @@ -set( LLVM_LINK_COMPONENTS +set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + asmparser support - ) - -set( LLVM_USED_LIBS - clangBasic - clangLex - clangSema + mc ) add_clang_executable(diagtool diagtool_main.cpp DiagTool.cpp + DiagnosticNames.cpp ListWarnings.cpp + ShowEnabledWarnings.cpp + TreeView.cpp ) +add_dependencies(diagtool + ClangDiagnosticIndexName + ) + +target_link_libraries(diagtool + clangBasic + clangLex + clangSema + clangFrontend + ) + if(UNIX) set(CLANGXX_LINK_OR_COPY create_symlink) else() set(CLANGXX_LINK_OR_COPY copy) endif() - -install(TARGETS diagtool - RUNTIME DESTINATION bin) diff --git a/tools/diagtool/DiagnosticNames.cpp b/tools/diagtool/DiagnosticNames.cpp new file mode 100644 index 0000000000000..31f352414f902 --- /dev/null +++ b/tools/diagtool/DiagnosticNames.cpp @@ -0,0 +1,78 @@ +//===- DiagnosticNames.cpp - Defines a table of all builtin diagnostics ----==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DiagnosticNames.h" +#include "clang/Basic/AllDiagnostics.h" +#include "llvm/ADT/STLExtras.h" + +using namespace clang; +using namespace diagtool; + +static const DiagnosticRecord BuiltinDiagnosticsByName[] = { +#define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t) }, +#include "clang/Basic/DiagnosticIndexName.inc" +#undef DIAG_NAME_INDEX +}; + +llvm::ArrayRef<DiagnosticRecord> diagtool::getBuiltinDiagnosticsByName() { + return llvm::makeArrayRef(BuiltinDiagnosticsByName); +} + + +// FIXME: Is it worth having two tables, especially when this one can get +// out of sync easily? +static const DiagnosticRecord BuiltinDiagnosticsByID[] = { +#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP, \ + SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER, \ + CATEGORY) \ + { #ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t) }, +#include "clang/Basic/DiagnosticCommonKinds.inc" +#include "clang/Basic/DiagnosticDriverKinds.inc" +#include "clang/Basic/DiagnosticFrontendKinds.inc" +#include "clang/Basic/DiagnosticSerializationKinds.inc" +#include "clang/Basic/DiagnosticLexKinds.inc" +#include "clang/Basic/DiagnosticParseKinds.inc" +#include "clang/Basic/DiagnosticASTKinds.inc" +#include "clang/Basic/DiagnosticCommentKinds.inc" +#include "clang/Basic/DiagnosticSemaKinds.inc" +#include "clang/Basic/DiagnosticAnalysisKinds.inc" +#undef DIAG +}; + +static bool orderByID(const DiagnosticRecord &Left, + const DiagnosticRecord &Right) { + return Left.DiagID < Right.DiagID; +} + +const DiagnosticRecord &diagtool::getDiagnosticForID(short DiagID) { + DiagnosticRecord Key = {0, DiagID, 0}; + + const DiagnosticRecord *Result = + std::lower_bound(BuiltinDiagnosticsByID, + llvm::array_endof(BuiltinDiagnosticsByID), + Key, orderByID); + assert(Result && "diagnostic not found; table may be out of date"); + return *Result; +} + + +#define GET_DIAG_ARRAYS +#include "clang/Basic/DiagnosticGroups.inc" +#undef GET_DIAG_ARRAYS + +// Second the table of options, sorted by name for fast binary lookup. +static const GroupRecord OptionTable[] = { +#define GET_DIAG_TABLE +#include "clang/Basic/DiagnosticGroups.inc" +#undef GET_DIAG_TABLE +}; + +llvm::ArrayRef<GroupRecord> diagtool::getDiagnosticGroups() { + return llvm::makeArrayRef(OptionTable); +} diff --git a/tools/diagtool/DiagnosticNames.h b/tools/diagtool/DiagnosticNames.h new file mode 100644 index 0000000000000..9a731587e5e0c --- /dev/null +++ b/tools/diagtool/DiagnosticNames.h @@ -0,0 +1,128 @@ +//===- DiagnosticNames.h - Defines a table of all builtin diagnostics ------==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/DataTypes.h" + +namespace diagtool { + + struct DiagnosticRecord { + const char *NameStr; + short DiagID; + uint8_t NameLen; + + llvm::StringRef getName() const { + return llvm::StringRef(NameStr, NameLen); + } + + bool operator<(const DiagnosticRecord &Other) const { + return getName() < Other.getName(); + } + }; + + /// \brief Get every diagnostic in the system, sorted by name. + llvm::ArrayRef<DiagnosticRecord> getBuiltinDiagnosticsByName(); + + /// \brief Get a diagnostic by its ID. + const DiagnosticRecord &getDiagnosticForID(short DiagID); + + + struct GroupRecord { + // Be safe with the size of 'NameLen' because we don't statically check if + // the size will fit in the field; the struct size won't decrease with a + // shorter type anyway. + size_t NameLen; + const char *NameStr; + const short *Members; + const short *SubGroups; + + llvm::StringRef getName() const { + return llvm::StringRef(NameStr, NameLen); + } + + template<typename RecordType> + class group_iterator { + const short *CurrentID; + + friend struct GroupRecord; + group_iterator(const short *Start) : CurrentID(Start) { + if (CurrentID && *CurrentID == -1) + CurrentID = 0; + } + + public: + typedef RecordType value_type; + typedef const value_type & reference; + typedef const value_type * pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + inline reference operator*() const; + inline pointer operator->() const { + return &operator*(); + } + + inline short getID() const { + return *CurrentID; + } + + group_iterator &operator++() { + ++CurrentID; + if (*CurrentID == -1) + CurrentID = 0; + return *this; + } + + bool operator==(group_iterator &Other) const { + return CurrentID == Other.CurrentID; + } + + bool operator!=(group_iterator &Other) const { + return CurrentID != Other.CurrentID; + } + }; + + typedef group_iterator<GroupRecord> subgroup_iterator; + subgroup_iterator subgroup_begin() const { + return SubGroups; + } + subgroup_iterator subgroup_end() const { + return 0; + } + + typedef group_iterator<DiagnosticRecord> diagnostics_iterator; + diagnostics_iterator diagnostics_begin() const { + return Members; + } + diagnostics_iterator diagnostics_end() const { + return 0; + } + + bool operator<(const GroupRecord &Other) const { + return getName() < Other.getName(); + } + }; + + /// \brief Get every diagnostic group in the system, sorted by name. + llvm::ArrayRef<GroupRecord> getDiagnosticGroups(); + + template<> + inline GroupRecord::subgroup_iterator::reference + GroupRecord::subgroup_iterator::operator*() const { + return getDiagnosticGroups()[*CurrentID]; + } + + template<> + inline GroupRecord::diagnostics_iterator::reference + GroupRecord::diagnostics_iterator::operator*() const { + return getDiagnosticForID(*CurrentID); + } +} // end namespace diagtool + diff --git a/tools/diagtool/ListWarnings.cpp b/tools/diagtool/ListWarnings.cpp index 2bbeca802497d..d554a2ef41ed7 100644 --- a/tools/diagtool/ListWarnings.cpp +++ b/tools/diagtool/ListWarnings.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "DiagTool.h" +#include "DiagnosticNames.h" #include "clang/Basic/Diagnostic.h" #include "llvm/Support/Format.h" #include "llvm/ADT/StringMap.h" @@ -24,28 +25,7 @@ DEF_DIAGTOOL("list-warnings", ListWarnings) using namespace clang; - -namespace { -struct StaticDiagNameIndexRec { - const char *NameStr; - unsigned short DiagID; - uint8_t NameLen; - - StringRef getName() const { - return StringRef(NameStr, NameLen); - } -}; -} - -static const StaticDiagNameIndexRec StaticDiagNameIndex[] = { -#define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t) }, -#include "clang/Basic/DiagnosticIndexName.inc" -#undef DIAG_NAME_INDEX - { 0, 0, 0 } -}; - -static const unsigned StaticDiagNameIndexSize = - sizeof(StaticDiagNameIndex)/sizeof(StaticDiagNameIndex[0])-1; +using namespace diagtool; namespace { struct Entry { @@ -73,9 +53,11 @@ int ListWarnings::run(unsigned int argc, char **argv, llvm::raw_ostream &out) { std::vector<Entry> Flagged, Unflagged; llvm::StringMap<std::vector<unsigned> > flagHistogram; - for (const StaticDiagNameIndexRec *di = StaticDiagNameIndex, *de = StaticDiagNameIndex + StaticDiagNameIndexSize; + ArrayRef<DiagnosticRecord> AllDiagnostics = getBuiltinDiagnosticsByName(); + + for (ArrayRef<DiagnosticRecord>::iterator di = AllDiagnostics.begin(), + de = AllDiagnostics.end(); di != de; ++di) { - unsigned diagID = di->DiagID; if (DiagnosticIDs::isBuiltinNote(diagID)) @@ -95,9 +77,6 @@ int ListWarnings::run(unsigned int argc, char **argv, llvm::raw_ostream &out) { } } - std::sort(Flagged.begin(), Flagged.end()); - std::sort(Unflagged.begin(), Unflagged.end()); - out << "Warnings with flags (" << Flagged.size() << "):\n"; printEntries(Flagged, out); @@ -119,6 +98,10 @@ int ListWarnings::run(unsigned int argc, char **argv, llvm::raw_ostream &out) { out << " Average number of diagnostics per flag: " << llvm::format("%.4g", avgDiagsPerFlag) << '\n'; + out << " Number in -Wpedantic (not covered by other -W flags): " + << flagHistogram.GetOrCreateValue("pedantic").getValue().size() + << '\n'; + out << '\n'; return 0; diff --git a/tools/diagtool/Makefile b/tools/diagtool/Makefile index 6e3bcfc292b1b..b629712e772b2 100644 --- a/tools/diagtool/Makefile +++ b/tools/diagtool/Makefile @@ -1,4 +1,4 @@ -##===- tools/driver/Makefile -------------------------------*- Makefile -*-===## +##===- tools/diagtool/Makefile -----------------------------*- Makefile -*-===## # # The LLVM Compiler Infrastructure # @@ -16,9 +16,11 @@ TOOL_NO_EXPORTS := 1 # Don't install this. NO_INSTALL = 1 -LINK_COMPONENTS := support - -USEDLIBS = clangBasic.a +include $(CLANG_LEVEL)/../../Makefile.config +LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc +USEDLIBS = clangFrontend.a clangDriver.a clangSerialization.a clangParse.a \ + clangSema.a clangAnalysis.a clangEdit.a clangAST.a clangLex.a \ + clangBasic.a include $(CLANG_LEVEL)/Makefile diff --git a/tools/diagtool/ShowEnabledWarnings.cpp b/tools/diagtool/ShowEnabledWarnings.cpp new file mode 100644 index 0000000000000..7162451b4e733 --- /dev/null +++ b/tools/diagtool/ShowEnabledWarnings.cpp @@ -0,0 +1,148 @@ +//===- ShowEnabledWarnings - diagtool tool for printing enabled flags -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DiagTool.h" +#include "DiagnosticNames.h" +#include "clang/Basic/LLVM.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/TextDiagnosticBuffer.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Frontend/Utils.h" +#include "llvm/Support/TargetSelect.h" + +DEF_DIAGTOOL("show-enabled", + "Show which warnings are enabled for a given command line", + ShowEnabledWarnings) + +using namespace clang; +using namespace diagtool; + +namespace { + struct PrettyDiag { + StringRef Name; + StringRef Flag; + DiagnosticsEngine::Level Level; + + PrettyDiag(StringRef name, StringRef flag, DiagnosticsEngine::Level level) + : Name(name), Flag(flag), Level(level) {} + + bool operator<(const PrettyDiag &x) const { return Name < x.Name; } + }; +} + +static void printUsage() { + llvm::errs() << "Usage: diagtool show-enabled [<flags>] <single-input.c>\n"; +} + +static char getCharForLevel(DiagnosticsEngine::Level Level) { + switch (Level) { + case DiagnosticsEngine::Ignored: return ' '; + case DiagnosticsEngine::Note: return '-'; + case DiagnosticsEngine::Warning: return 'W'; + case DiagnosticsEngine::Error: return 'E'; + case DiagnosticsEngine::Fatal: return 'F'; + } + + llvm_unreachable("Unknown diagnostic level"); +} + +static IntrusiveRefCntPtr<DiagnosticsEngine> +createDiagnostics(unsigned int argc, char **argv) { + IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs()); + + // Buffer diagnostics from argument parsing so that we can output them using a + // well formed diagnostic object. + TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer; + IntrusiveRefCntPtr<DiagnosticsEngine> InterimDiags( + new DiagnosticsEngine(DiagIDs, DiagsBuffer)); + + // Try to build a CompilerInvocation. + OwningPtr<CompilerInvocation> Invocation( + createInvocationFromCommandLine(ArrayRef<const char *>(argv, argc), + InterimDiags)); + if (!Invocation) + return NULL; + + // Build the diagnostics parser + IntrusiveRefCntPtr<DiagnosticsEngine> FinalDiags = + CompilerInstance::createDiagnostics(Invocation->getDiagnosticOpts(), + argc, argv); + if (!FinalDiags) + return NULL; + + // Flush any errors created when initializing everything. This could happen + // for invalid command lines, which will probably give non-sensical results. + DiagsBuffer->FlushDiagnostics(*FinalDiags); + + return FinalDiags; +} + +int ShowEnabledWarnings::run(unsigned int argc, char **argv, raw_ostream &Out) { + // First check our one flag (--levels). + bool ShouldShowLevels = true; + if (argc > 0) { + StringRef FirstArg(*argv); + if (FirstArg.equals("--no-levels")) { + ShouldShowLevels = false; + --argc; + ++argv; + } else if (FirstArg.equals("--levels")) { + ShouldShowLevels = true; + --argc; + ++argv; + } + } + + // Create the diagnostic engine. + IntrusiveRefCntPtr<DiagnosticsEngine> Diags = createDiagnostics(argc, argv); + if (!Diags) { + printUsage(); + return EXIT_FAILURE; + } + + // Now we have our diagnostics. Iterate through EVERY diagnostic and see + // which ones are turned on. + // FIXME: It would be very nice to print which flags are turning on which + // diagnostics, but this can be done with a diff. + ArrayRef<DiagnosticRecord> AllDiagnostics = getBuiltinDiagnosticsByName(); + std::vector<PrettyDiag> Active; + + for (ArrayRef<DiagnosticRecord>::iterator I = AllDiagnostics.begin(), + E = AllDiagnostics.end(); + I != E; ++I) { + unsigned DiagID = I->DiagID; + + if (DiagnosticIDs::isBuiltinNote(DiagID)) + continue; + + if (!DiagnosticIDs::isBuiltinWarningOrExtension(DiagID)) + continue; + + DiagnosticsEngine::Level DiagLevel = + Diags->getDiagnosticLevel(DiagID, SourceLocation()); + if (DiagLevel == DiagnosticsEngine::Ignored) + continue; + + StringRef WarningOpt = DiagnosticIDs::getWarningOptionForDiag(DiagID); + Active.push_back(PrettyDiag(I->getName(), WarningOpt, DiagLevel)); + } + + // Print them all out. + for (std::vector<PrettyDiag>::const_iterator I = Active.begin(), + E = Active.end(); I != E; ++I) { + if (ShouldShowLevels) + Out << getCharForLevel(I->Level) << " "; + Out << I->Name; + if (!I->Flag.empty()) + Out << " [-W" << I->Flag << "]"; + Out << '\n'; + } + + return EXIT_SUCCESS; +} diff --git a/tools/diagtool/TreeView.cpp b/tools/diagtool/TreeView.cpp new file mode 100644 index 0000000000000..9db2c26dd92dc --- /dev/null +++ b/tools/diagtool/TreeView.cpp @@ -0,0 +1,135 @@ +//===- TreeView.cpp - diagtool tool for printing warning flags ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This diagnostic tool +// +//===----------------------------------------------------------------------===// + +#include "DiagTool.h" +#include "DiagnosticNames.h" +#include "clang/Basic/Diagnostic.h" +#include "llvm/Support/Format.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/DenseSet.h" +#include "clang/AST/ASTDiagnostic.h" +#include "clang/Basic/AllDiagnostics.h" + +DEF_DIAGTOOL("tree", + "Show warning flags in a tree view", + TreeView) + +using namespace clang; +using namespace diagtool; + +static void printUsage() { + llvm::errs() << "Usage: diagtool tree [--flags-only] [<diagnostic-group>]\n"; +} + +static void printGroup(llvm::raw_ostream &out, const GroupRecord &Group, + bool FlagsOnly, unsigned Indent = 0) { + out.indent(Indent * 2); + out << "-W" << Group.getName() << "\n"; + + ++Indent; + for (GroupRecord::subgroup_iterator I = Group.subgroup_begin(), + E = Group.subgroup_end(); + I != E; ++I) { + printGroup(out, *I, FlagsOnly, Indent); + } + + if (!FlagsOnly) { + for (GroupRecord::diagnostics_iterator I = Group.diagnostics_begin(), + E = Group.diagnostics_end(); + I != E; ++I) { + out.indent(Indent * 2); + out << I->getName() << "\n"; + } + } +} + +static int showGroup(llvm::raw_ostream &out, StringRef RootGroup, + bool FlagsOnly) { + ArrayRef<GroupRecord> AllGroups = getDiagnosticGroups(); + + GroupRecord Key = { RootGroup.size(), RootGroup.data(), 0, 0 }; + const GroupRecord *Found = + std::lower_bound(AllGroups.begin(), AllGroups.end(), Key); + + if (Found == AllGroups.end() || Found->getName() != RootGroup) { + llvm::errs() << "No such diagnostic group exists\n"; + return 1; + } + + printGroup(out, *Found, FlagsOnly); + + return 0; +} + +static int showAll(llvm::raw_ostream &out, bool FlagsOnly) { + ArrayRef<GroupRecord> AllGroups = getDiagnosticGroups(); + llvm::DenseSet<unsigned> NonRootGroupIDs; + + for (ArrayRef<GroupRecord>::iterator I = AllGroups.begin(), + E = AllGroups.end(); + I != E; ++I) { + for (GroupRecord::subgroup_iterator SI = I->subgroup_begin(), + SE = I->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(out, AllGroups[i], FlagsOnly); + } + + return 0; +} + +int TreeView::run(unsigned int argc, char **argv, llvm::raw_ostream &out) { + // First check our one flag (--flags-only). + bool FlagsOnly = false; + if (argc > 0) { + StringRef FirstArg(*argv); + if (FirstArg.equals("--flags-only")) { + FlagsOnly = 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; + } + + if (ShowAll) + return showAll(out, FlagsOnly); + + return showGroup(out, RootGroup, FlagsOnly); +} + diff --git a/tools/diagtool/diagtool_main.cpp b/tools/diagtool/diagtool_main.cpp index e34f0dc06c657..4eef54dbfece9 100644 --- a/tools/diagtool/diagtool_main.cpp +++ b/tools/diagtool/diagtool_main.cpp @@ -18,7 +18,7 @@ using namespace diagtool; int main(int argc, char *argv[]) { if (argc > 1) if (DiagTool *tool = diagTools->getTool(argv[1])) - return tool->run(argc - 1, &argv[2], llvm::errs()); + return tool->run(argc - 2, &argv[2], llvm::outs()); llvm::errs() << "usage: diagtool <command> [<args>]\n\n"; diagTools->printCommands(llvm::errs()); |