1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
|
/*
* Copyright (c) 2011 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#include <iostream>
#include <set>
#include <vector>
#include <cassert>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/graph/graphviz.hpp>
// -----------------------------------------------------------------------------
// Include diagnostics data from CLang
// -----------------------------------------------------------------------------
#define DIAG(name, a, b, c, d, e, f, g) name,
namespace diag {
enum LexKinds {
#include <clang/Basic/DiagnosticLexKinds.inc>
#include <clang/Basic/DiagnosticParseKinds.inc>
#include <clang/Basic/DiagnosticCommonKinds.inc>
#include <clang/Basic/DiagnosticDriverKinds.inc>
#include <clang/Basic/DiagnosticFrontendKinds.inc>
#include <clang/Basic/DiagnosticSemaKinds.inc>
};
}
#define GET_DIAG_ARRAYS
#include <clang/Basic/DiagnosticGroups.inc>
#undef GET_DIAG_ARRAYS
struct DiagTableEntry {
const char* name;
const short* array;
const short* group;
};
static const DiagTableEntry diagnostics[] = {
#define GET_DIAG_TABLE
#include <clang/Basic/DiagnosticGroups.inc>
#undef GET_DIAG_TABLE
};
static const size_t diagnostics_count = sizeof(diagnostics) / sizeof(diagnostics[0]);
// -----------------------------------------------------------------------------
using namespace boost;
struct Properties {
Properties() : have(false), implicitHave(false), dontWant(false), implicitDontWant(false), ignored(false), available(false), missing(false), redundant(false), alreadyCovered(false) {
}
std::string name;
bool have;
bool implicitHave;
bool dontWant;
bool implicitDontWant;
bool ignored;
bool available;
bool missing;
bool redundant;
bool alreadyCovered;
};
class GraphVizLabelWriter {
public:
GraphVizLabelWriter(const std::vector<Properties>& properties) : properties(properties) {
}
template <class VertexOrEdge>
void operator()(std::ostream& out, const VertexOrEdge& v) const {
std::string color;
if (properties[v].missing) {
color = "orange";
}
else if (properties[v].redundant) {
color = "lightblue";
}
else if (properties[v].have) {
color = "darkgreen";
}
else if (properties[v].implicitHave) {
color = "green";
}
else if (properties[v].dontWant) {
color = "red";
}
else if (properties[v].implicitDontWant) {
color = "pink";
}
else if (properties[v].ignored) {
color = "white";
}
else if (properties[v].available) {
color = "yellow";
}
else {
assert(false);
}
out << "[label=" << escape_dot_string(properties[v].name) << " fillcolor=\"" << color << "\" style=filled]";
}
private:
const std::vector<Properties> properties;
};
int main(int argc, char* argv[]) {
// Parse command-line arguments
std::set<std::string> have;
std::set<std::string> dontWant;
std::string outputDir;
for (int i = 1; i < argc; ++i) {
std::string arg(argv[i]);
if (starts_with(arg, "-W")) {
have.insert(arg.substr(2, arg.npos));
}
else if (starts_with(arg, "-w")) {
dontWant.insert(arg.substr(2, arg.npos));
}
else if (starts_with(arg, "-O")) {
outputDir = arg.substr(2, arg.npos) + "/";
}
}
// Build the graph and initialize properties
typedef adjacency_list<vecS, vecS, bidirectionalS> Graph;
typedef graph_traits<Graph>::vertex_descriptor Vertex;
Graph g(diagnostics_count);
std::vector<Properties> properties(num_vertices(g));
for (size_t i = 0; i < diagnostics_count; ++i) {
std::string name(diagnostics[i].name);
properties[i].name = name;
properties[i].implicitHave = properties[i].have = have.find(name) != have.end();
properties[i].implicitDontWant = properties[i].dontWant = dontWant.find(name) != dontWant.end();
properties[i].ignored = diagnostics[i].group == 0 && diagnostics[i].array == 0;
properties[i].alreadyCovered = false;
properties[i].available = true;
for (const short* j = diagnostics[i].group; j && *j != -1; ++j) {
add_edge(i, *j, g);
}
}
// Sort the diagnostics
std::list<Vertex> sortedDiagnostics;
boost::topological_sort(g, std::front_inserter(sortedDiagnostics));
// Propagate dontWant and have properties down
for(std::list<Vertex>::const_iterator i = sortedDiagnostics.begin(); i != sortedDiagnostics.end(); ++i) {
graph_traits<Graph>::adjacency_iterator adjacentIt, adjacentEnd;
for (tie(adjacentIt, adjacentEnd) = adjacent_vertices(*i, g); adjacentIt != adjacentEnd; ++adjacentIt) {
properties[*adjacentIt].implicitDontWant = properties[*i].implicitDontWant || properties[*adjacentIt].implicitDontWant;
properties[*adjacentIt].implicitHave = properties[*i].implicitHave || properties[*adjacentIt].implicitHave;
}
}
// Propagate 'available' property upwards
for(std::list<Vertex>::const_reverse_iterator i = sortedDiagnostics.rbegin(); i != sortedDiagnostics.rend(); ++i) {
properties[*i].available = properties[*i].available && !properties[*i].implicitDontWant;
graph_traits<Graph>::in_edge_iterator edgesIt, edgesEnd;
graph_traits<Graph>::edge_descriptor edge;
for (tie(edgesIt, edgesEnd) = in_edges(*i, g); edgesIt != edgesEnd; ++edgesIt) {
properties[source(*edgesIt, g)].available = properties[source(*edgesIt, g)].available && properties[*i].available;
}
}
// Collect missing & redundant flags
std::set<std::string> missing;
std::set<std::string> redundant;
for(std::list<Vertex>::const_iterator i = sortedDiagnostics.begin(); i != sortedDiagnostics.end(); ++i) {
bool markChildrenCovered = true;
if (properties[*i].alreadyCovered) {
if (properties[*i].have) {
properties[*i].redundant = true;
redundant.insert(properties[*i].name);
}
}
else {
if (properties[*i].available) {
if (!properties[*i].implicitHave && !properties[*i].ignored) {
properties[*i].missing = true;
missing.insert(properties[*i].name);
}
}
else {
markChildrenCovered = false;
}
}
if (markChildrenCovered) {
graph_traits<Graph>::adjacency_iterator adjacentIt, adjacentEnd;
for (tie(adjacentIt, adjacentEnd) = adjacent_vertices(*i, g); adjacentIt != adjacentEnd; ++adjacentIt) {
properties[*adjacentIt].alreadyCovered = true;
}
}
}
// Write information
if (!missing.empty()) {
std::cout << "Missing diagnostic flags: ";
for(std::set<std::string>::const_iterator i = missing.begin(); i != missing.end(); ++i) {
std::cout << "-W" << *i << " ";
}
std::cout<< std::endl;
}
if (!redundant.empty()) {
std::cout << "Redundant diagnostic flags: ";
for(std::set<std::string>::const_iterator i = redundant.begin(); i != redundant.end(); ++i) {
std::cout << "-W" << *i << " ";
}
std::cout<< std::endl;
}
// Write graphviz file
if (!outputDir.empty()) {
std::ofstream f((outputDir + "clang-diagnostics-overview.dot").c_str());
write_graphviz(f, g, GraphVizLabelWriter(properties));
f.close();
}
return 0;
}
|