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