[cfe-commits] r159093 - in /cfe/trunk: test/Misc/warning-flags-tree.c tools/diagtool/CMakeLists.txt tools/diagtool/DiagnosticNames.cpp tools/diagtool/DiagnosticNames.h tools/diagtool/ListWarnings.cpp tools/diagtool/ShowEnabledWarnings.cpp tools/diagtool/TreeView.cpp

Jordan Rose jordan_rose at apple.com
Sat Jun 23 17:07:45 PDT 2012


Author: jrose
Date: Sat Jun 23 19:07:45 2012
New Revision: 159093

URL: http://llvm.org/viewvc/llvm-project?rev=159093&view=rev
Log:
[diagtool] Add a new "tree" command to shows warnings activated by a flag.

% diagtool tree -Wunused-value
-Wunused-value
  -Wunused-comparison
    warn_unused_comparison
  -Wunused-result
    warn_unused_result
  warn_unused_call
  warn_unused_container_subscript_expr
  warn_unused_expr
  warn_unused_property_expr
  warn_unused_voidptr

Added:
    cfe/trunk/test/Misc/warning-flags-tree.c
    cfe/trunk/tools/diagtool/TreeView.cpp
Modified:
    cfe/trunk/tools/diagtool/CMakeLists.txt
    cfe/trunk/tools/diagtool/DiagnosticNames.cpp
    cfe/trunk/tools/diagtool/DiagnosticNames.h
    cfe/trunk/tools/diagtool/ListWarnings.cpp
    cfe/trunk/tools/diagtool/ShowEnabledWarnings.cpp

Added: cfe/trunk/test/Misc/warning-flags-tree.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/warning-flags-tree.c?rev=159093&view=auto
==============================================================================
--- cfe/trunk/test/Misc/warning-flags-tree.c (added)
+++ cfe/trunk/test/Misc/warning-flags-tree.c Sat Jun 23 19:07:45 2012
@@ -0,0 +1,56 @@
+// RUN: diagtool tree | FileCheck -strict-whitespace %s
+// RUN: diagtool tree -Weverything | FileCheck -strict-whitespace %s
+// RUN: diagtool tree everything | FileCheck -strict-whitespace %s
+//
+// These three ways of running diagtool tree are the same:
+// they produce a tree for every top-level diagnostic flag.
+// Just check a few to make sure we're actually showing more than one group.
+//
+// CHECK: -W
+// CHECK:   -Wextra
+// CHECK:     -Wmissing-field-initializers
+// CHECK:       warn_missing_field_initializers
+// CHECK: -Wall
+// CHECK:   -Wmost
+
+// These flags are currently unimplemented; test that we output them anyway.
+// CHECK: -Wstrict-aliasing
+// CHECK-NEXT: -Wstrict-aliasing=0
+// CHECK-NEXT: -Wstrict-aliasing=1
+// CHECK-NEXT: -Wstrict-aliasing=2
+// CHECK: -Wstrict-overflow
+// CHECK-NEXT: -Wstrict-overflow=0
+// CHECK-NEXT: -Wstrict-overflow=1
+// CHECK-NEXT: -Wstrict-overflow=2
+// CHECK-NEXT: -Wstrict-overflow=3
+// CHECK-NEXT: -Wstrict-overflow=4
+// CHECK-NEXT: -Wstrict-overflow=5
+
+
+// RUN: not diagtool tree -Wthis-is-not-a-valid-flag
+
+
+// RUN: diagtool tree -Wgnu | FileCheck -strict-whitespace -check-prefix CHECK-GNU %s
+// CHECK-GNU: -Wgnu
+// CHECK-GNU:   -Wgnu-designator
+// CHECK-GNU:     ext_gnu_array_range
+// CHECK-GNU:     ext_gnu_missing_equal_designator
+// CHECK-GNU:     ext_gnu_old_style_field_designator
+// CHECK-GNU:   -Wvla
+// CHECK-GNU:     ext_vla
+// CHECK-GNU:   ext_array_init_copy
+// CHECK-GNU:   ext_empty_struct_union
+// CHECK-GNU:   ext_expr_not_ice
+// There are more GNU extensions but we don't need to check them all.
+
+// RUN: diagtool tree --flags-only -Wgnu | FileCheck -check-prefix CHECK-FLAGS-ONLY %s
+// CHECK-FLAGS-ONLY: -Wgnu
+// CHECK-FLAGS-ONLY:   -Wgnu-designator
+// CHECK-FLAGS-ONLY-NOT:     ext_gnu_array_range
+// CHECK-FLAGS-ONLY-NOT:     ext_gnu_missing_equal_designator
+// CHECK-FLAGS-ONLY-NOT:     ext_gnu_old_style_field_designator
+// CHECK-FLAGS-ONLY:   -Wvla
+// CHECK-FLAGS-ONLY-NOT:     ext_vla
+// CHECK-FLAGS-ONLY-NOT:   ext_array_init_copy
+// CHECK-FLAGS-ONLY-NOT:   ext_empty_struct_union
+// CHECK-FLAGS-ONLY-NOT:   ext_expr_not_ice

Modified: cfe/trunk/tools/diagtool/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/diagtool/CMakeLists.txt?rev=159093&r1=159092&r2=159093&view=diff
==============================================================================
--- cfe/trunk/tools/diagtool/CMakeLists.txt (original)
+++ cfe/trunk/tools/diagtool/CMakeLists.txt Sat Jun 23 19:07:45 2012
@@ -8,6 +8,7 @@
   DiagnosticNames.cpp
   ListWarnings.cpp
   ShowEnabledWarnings.cpp
+  TreeView.cpp
 )
 
 add_dependencies(diagtool

Modified: cfe/trunk/tools/diagtool/DiagnosticNames.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/diagtool/DiagnosticNames.cpp?rev=159093&r1=159092&r2=159093&view=diff
==============================================================================
--- cfe/trunk/tools/diagtool/DiagnosticNames.cpp (original)
+++ cfe/trunk/tools/diagtool/DiagnosticNames.cpp Sat Jun 23 19:07:45 2012
@@ -9,17 +9,69 @@
 
 #include "DiagnosticNames.h"
 #include "clang/Basic/AllDiagnostics.h"
+#include "llvm/ADT/STLExtras.h"
 
 using namespace clang;
+using namespace diagtool;
 
-const diagtool::DiagnosticRecord diagtool::BuiltinDiagnostics[] = {
+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
-  { 0, 0, 0 }
 };
 
-const size_t diagtool::BuiltinDiagnosticsCount =
-  sizeof(diagtool::BuiltinDiagnostics) /
-  sizeof(diagtool::BuiltinDiagnostics[0]) - 1;
+llvm::ArrayRef<DiagnosticRecord> diagtool::getBuiltinDiagnosticsByName() {
+  return 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/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 OptionTable;
+}

Modified: cfe/trunk/tools/diagtool/DiagnosticNames.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/diagtool/DiagnosticNames.h?rev=159093&r1=159092&r2=159093&view=diff
==============================================================================
--- cfe/trunk/tools/diagtool/DiagnosticNames.h (original)
+++ cfe/trunk/tools/diagtool/DiagnosticNames.h Sat Jun 23 19:07:45 2012
@@ -7,22 +7,122 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/DataTypes.h"
 
 namespace diagtool {
+
   struct DiagnosticRecord {
     const char *NameStr;
-    unsigned short DiagID;
+    short DiagID;
     uint8_t NameLen;
     
     llvm::StringRef getName() const {
       return llvm::StringRef(NameStr, NameLen);
     }
+
+    bool operator<(const DiagnosticRecord &Other) const {
+      return getName() < Other.getName();
+    }
   };
 
-  extern const DiagnosticRecord BuiltinDiagnostics[];
-  extern const size_t BuiltinDiagnosticsCount;
+  /// \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
 

Modified: cfe/trunk/tools/diagtool/ListWarnings.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/diagtool/ListWarnings.cpp?rev=159093&r1=159092&r2=159093&view=diff
==============================================================================
--- cfe/trunk/tools/diagtool/ListWarnings.cpp (original)
+++ cfe/trunk/tools/diagtool/ListWarnings.cpp Sat Jun 23 19:07:45 2012
@@ -25,6 +25,7 @@
              ListWarnings)
   
 using namespace clang;
+using namespace diagtool;
 
 namespace {
 struct Entry {
@@ -52,9 +53,11 @@
   std::vector<Entry> Flagged, Unflagged;
   llvm::StringMap<std::vector<unsigned> > flagHistogram;
   
-  for (const diagtool::DiagnosticRecord *di = diagtool::BuiltinDiagnostics,
-       *de = di + diagtool::BuiltinDiagnosticsCount; di != de; ++di) {
-    
+  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))
@@ -74,9 +77,6 @@
     }
   }
   
-  std::sort(Flagged.begin(), Flagged.end());
-  std::sort(Unflagged.begin(), Unflagged.end());
-
   out << "Warnings with flags (" << Flagged.size() << "):\n";
   printEntries(Flagged, out);
   

Modified: cfe/trunk/tools/diagtool/ShowEnabledWarnings.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/diagtool/ShowEnabledWarnings.cpp?rev=159093&r1=159092&r2=159093&view=diff
==============================================================================
--- cfe/trunk/tools/diagtool/ShowEnabledWarnings.cpp (original)
+++ cfe/trunk/tools/diagtool/ShowEnabledWarnings.cpp Sat Jun 23 19:07:45 2012
@@ -21,6 +21,7 @@
              ShowEnabledWarnings)
 
 using namespace clang;
+using namespace diagtool;
 
 namespace {
   struct PrettyDiag {
@@ -109,10 +110,12 @@
   // 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 (const diagtool::DiagnosticRecord *I = diagtool::BuiltinDiagnostics,
-       *E = I + diagtool::BuiltinDiagnosticsCount; I != E; ++I) {
+  for (ArrayRef<DiagnosticRecord>::iterator I = AllDiagnostics.begin(),
+                                            E = AllDiagnostics.end();
+       I != E; ++I) {
     unsigned DiagID = I->DiagID;
     
     if (DiagnosticIDs::isBuiltinNote(DiagID))
@@ -130,8 +133,6 @@
     Active.push_back(PrettyDiag(I->getName(), WarningOpt, DiagLevel));
   }
 
-  std::sort(Active.begin(), Active.end());
-
   // Print them all out.
   for (std::vector<PrettyDiag>::const_iterator I = Active.begin(),
        E = Active.end(); I != E; ++I) {

Added: cfe/trunk/tools/diagtool/TreeView.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/diagtool/TreeView.cpp?rev=159093&view=auto
==============================================================================
--- cfe/trunk/tools/diagtool/TreeView.cpp (added)
+++ cfe/trunk/tools/diagtool/TreeView.cpp Sat Jun 23 19:07:45 2012
@@ -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);
+}
+





More information about the cfe-commits mailing list