//===- ListWarnings.h - 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 file provides a diagtool tool that displays warning flags for
// diagnostics.
//
//===----------------------------------------------------------------------===//
#include "DiagTool.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/Support/Format.h"
#include "llvm/ADT/StringMap.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/Basic/AllDiagnostics.h"
DEF_DIAGTOOL("list-warnings",
"List warnings and their corresponding flags",
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;
namespace {
struct Entry {
llvm::StringRef DiagName;
llvm::StringRef Flag;
Entry(llvm::StringRef diagN, llvm::StringRef flag)
: DiagName(diagN), Flag(flag) {}
bool operator<(const Entry &x) const { return DiagName < x.DiagName; }
};
}
static void printEntries(std::vector<Entry> &entries, llvm::raw_ostream &out) {
for (std::vector<Entry>::iterator it = entries.begin(), ei = entries.end();
it != ei; ++it) {
out << " " << it->DiagName;
if (!it->Flag.empty())
out << " [-W" << it->Flag << "]";
out << '\n';
}
}
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;
di != de; ++di) {
unsigned diagID = di->DiagID;
if (DiagnosticIDs::isBuiltinNote(diagID))
continue;
if (!DiagnosticIDs::isBuiltinWarningOrExtension(diagID))
continue;
Entry entry(di->getName(),
DiagnosticIDs::getWarningOptionForDiag(diagID));
if (entry.Flag.empty())
Unflagged.push_back(entry);
else {
Flagged.push_back(entry);
flagHistogram.GetOrCreateValue(entry.Flag).getValue().push_back(diagID);
}
}
std::sort(Flagged.begin(), Flagged.end());
std::sort(Unflagged.begin(), Unflagged.end());
out << "Warnings with flags (" << Flagged.size() << "):\n";
printEntries(Flagged, out);
out << "Warnings without flags (" << Unflagged.size() << "):\n";
printEntries(Unflagged, out);
out << "\nSTATISTICS:\n\n";
double percentFlagged = ((double) Flagged.size())
/ (Flagged.size() + Unflagged.size()) * 100.0;
out << " Percentage of warnings with flags: "
<< llvm::format("%.4g",percentFlagged) << "%\n";
out << " Number of unique flags: "
<< flagHistogram.size() << '\n';
double avgDiagsPerFlag = (double) Flagged.size() / flagHistogram.size();
out << " Average number of diagnostics per flag: "
<< llvm::format("%.4g", avgDiagsPerFlag) << '\n';
out << '\n';
return 0;
}