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 "clang/Basic/Diagnostic.h" 17 #include "llvm/Support/Format.h" 18 #include "llvm/ADT/StringMap.h" 19 #include "clang/AST/ASTDiagnostic.h" 20 #include "clang/Basic/AllDiagnostics.h" 21 22 DEF_DIAGTOOL("list-warnings", 23 "List warnings and their corresponding flags", 24 ListWarnings) 25 26 using namespace clang; 27 28 namespace { 29 struct StaticDiagNameIndexRec { 30 const char *NameStr; 31 unsigned short DiagID; 32 uint8_t NameLen; 33 34 StringRef getName() const { 35 return StringRef(NameStr, NameLen); 36 } 37 }; 38 } 39 40 static const StaticDiagNameIndexRec StaticDiagNameIndex[] = { 41 #define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t) }, 42 #include "clang/Basic/DiagnosticIndexName.inc" 43 #undef DIAG_NAME_INDEX 44 { 0, 0, 0 } 45 }; 46 47 static const unsigned StaticDiagNameIndexSize = 48 sizeof(StaticDiagNameIndex)/sizeof(StaticDiagNameIndex[0])-1; 49 50 namespace { 51 struct Entry { 52 llvm::StringRef DiagName; 53 llvm::StringRef Flag; 54 55 Entry(llvm::StringRef diagN, llvm::StringRef flag) 56 : DiagName(diagN), Flag(flag) {} 57 58 bool operator<(const Entry &x) const { return DiagName < x.DiagName; } 59 }; 60 } 61 62 static void printEntries(std::vector<Entry> &entries, llvm::raw_ostream &out) { 63 for (std::vector<Entry>::iterator it = entries.begin(), ei = entries.end(); 64 it != ei; ++it) { 65 out << " " << it->DiagName; 66 if (!it->Flag.empty()) 67 out << " [-W" << it->Flag << "]"; 68 out << '\n'; 69 } 70 } 71 72 int ListWarnings::run(unsigned int argc, char **argv, llvm::raw_ostream &out) { 73 std::vector<Entry> Flagged, Unflagged; 74 llvm::StringMap<std::vector<unsigned> > flagHistogram; 75 76 for (const StaticDiagNameIndexRec *di = StaticDiagNameIndex, *de = StaticDiagNameIndex + StaticDiagNameIndexSize; 77 di != de; ++di) { 78 79 unsigned diagID = di->DiagID; 80 81 if (DiagnosticIDs::isBuiltinNote(diagID)) 82 continue; 83 84 if (!DiagnosticIDs::isBuiltinWarningOrExtension(diagID)) 85 continue; 86 87 Entry entry(di->getName(), 88 DiagnosticIDs::getWarningOptionForDiag(diagID)); 89 90 if (entry.Flag.empty()) 91 Unflagged.push_back(entry); 92 else { 93 Flagged.push_back(entry); 94 flagHistogram.GetOrCreateValue(entry.Flag).getValue().push_back(diagID); 95 } 96 } 97 98 std::sort(Flagged.begin(), Flagged.end()); 99 std::sort(Unflagged.begin(), Unflagged.end()); 100 101 out << "Warnings with flags (" << Flagged.size() << "):\n"; 102 printEntries(Flagged, out); 103 104 out << "Warnings without flags (" << Unflagged.size() << "):\n"; 105 printEntries(Unflagged, out); 106 107 out << "\nSTATISTICS:\n\n"; 108 109 double percentFlagged = ((double) Flagged.size()) 110 / (Flagged.size() + Unflagged.size()) * 100.0; 111 112 out << " Percentage of warnings with flags: " 113 << llvm::format("%.4g",percentFlagged) << "%\n"; 114 115 out << " Number of unique flags: " 116 << flagHistogram.size() << '\n'; 117 118 double avgDiagsPerFlag = (double) Flagged.size() / flagHistogram.size(); 119 out << " Average number of diagnostics per flag: " 120 << llvm::format("%.4g", avgDiagsPerFlag) << '\n'; 121 122 out << '\n'; 123 124 return 0; 125 } 126 127