1 //===- ListWarnings.h - diagtool tool for printing warning flags ----------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file provides a diagtool tool that displays warning flags for
11 // diagnostics.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "DiagTool.h"
16 #include "DiagnosticNames.h"
17 #include "clang/AST/ASTDiagnostic.h"
18 #include "clang/Basic/AllDiagnostics.h"
19 #include "clang/Basic/Diagnostic.h"
20 #include "llvm/ADT/StringMap.h"
21 #include "llvm/Support/Format.h"
22 
23 DEF_DIAGTOOL("list-warnings",
24              "List warnings and their corresponding flags",
25              ListWarnings)
26 
27 using namespace clang;
28 using namespace diagtool;
29 
30 namespace {
31 struct Entry {
32   llvm::StringRef DiagName;
33   llvm::StringRef Flag;
34 
Entry__anon12bd5f5d0111::Entry35   Entry(llvm::StringRef diagN, llvm::StringRef flag)
36     : DiagName(diagN), Flag(flag) {}
37 
operator <__anon12bd5f5d0111::Entry38   bool operator<(const Entry &x) const { return DiagName < x.DiagName; }
39 };
40 }
41 
printEntries(std::vector<Entry> & entries,llvm::raw_ostream & out)42 static void printEntries(std::vector<Entry> &entries, llvm::raw_ostream &out) {
43   for (std::vector<Entry>::iterator it = entries.begin(), ei = entries.end();
44        it != ei; ++it) {
45     out << "  " << it->DiagName;
46     if (!it->Flag.empty())
47       out << " [-W" << it->Flag << "]";
48     out << '\n';
49   }
50 }
51 
run(unsigned int argc,char ** argv,llvm::raw_ostream & out)52 int ListWarnings::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
53   std::vector<Entry> Flagged, Unflagged;
54   llvm::StringMap<std::vector<unsigned> > flagHistogram;
55 
56   ArrayRef<DiagnosticRecord> AllDiagnostics = getBuiltinDiagnosticsByName();
57 
58   for (ArrayRef<DiagnosticRecord>::iterator di = AllDiagnostics.begin(),
59                                             de = AllDiagnostics.end();
60        di != de; ++di) {
61     unsigned diagID = di->DiagID;
62 
63     if (DiagnosticIDs::isBuiltinNote(diagID))
64       continue;
65 
66     if (!DiagnosticIDs::isBuiltinWarningOrExtension(diagID))
67       continue;
68 
69     Entry entry(di->getName(),
70                 DiagnosticIDs::getWarningOptionForDiag(diagID));
71 
72     if (entry.Flag.empty())
73       Unflagged.push_back(entry);
74     else {
75       Flagged.push_back(entry);
76       flagHistogram[entry.Flag].push_back(diagID);
77     }
78   }
79 
80   out << "Warnings with flags (" << Flagged.size() << "):\n";
81   printEntries(Flagged, out);
82 
83   out << "Warnings without flags (" << Unflagged.size() << "):\n";
84   printEntries(Unflagged, out);
85 
86   out << "\nSTATISTICS:\n\n";
87 
88   double percentFlagged = ((double) Flagged.size())
89     / (Flagged.size() + Unflagged.size()) * 100.0;
90 
91   out << "  Percentage of warnings with flags: "
92       << llvm::format("%.4g",percentFlagged) << "%\n";
93 
94   out << "  Number of unique flags: "
95       << flagHistogram.size() << '\n';
96 
97   double avgDiagsPerFlag = (double) Flagged.size() / flagHistogram.size();
98   out << "  Average number of diagnostics per flag: "
99       << llvm::format("%.4g", avgDiagsPerFlag) << '\n';
100 
101   out << "  Number in -Wpedantic (not covered by other -W flags): "
102       << flagHistogram["pedantic"].size() << '\n';
103 
104   out << '\n';
105 
106   return 0;
107 }
108 
109