Home | History | Annotate | Download | only in diagtool
      1 //===- ShowEnabledWarnings - diagtool tool for printing enabled 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 #include "DiagTool.h"
     11 #include "DiagnosticNames.h"
     12 #include "clang/Basic/LLVM.h"
     13 #include "clang/Frontend/CompilerInstance.h"
     14 #include "clang/Frontend/TextDiagnosticBuffer.h"
     15 #include "clang/Frontend/TextDiagnosticPrinter.h"
     16 #include "clang/Frontend/Utils.h"
     17 #include "llvm/Support/TargetSelect.h"
     18 
     19 DEF_DIAGTOOL("show-enabled",
     20              "Show which warnings are enabled for a given command line",
     21              ShowEnabledWarnings)
     22 
     23 using namespace clang;
     24 using namespace diagtool;
     25 
     26 namespace {
     27   struct PrettyDiag {
     28     StringRef Name;
     29     StringRef Flag;
     30     DiagnosticsEngine::Level Level;
     31 
     32     PrettyDiag(StringRef name, StringRef flag, DiagnosticsEngine::Level level)
     33     : Name(name), Flag(flag), Level(level) {}
     34 
     35     bool operator<(const PrettyDiag &x) const { return Name < x.Name; }
     36   };
     37 }
     38 
     39 static void printUsage() {
     40   llvm::errs() << "Usage: diagtool show-enabled [<flags>] <single-input.c>\n";
     41 }
     42 
     43 static char getCharForLevel(DiagnosticsEngine::Level Level) {
     44   switch (Level) {
     45   case DiagnosticsEngine::Ignored: return ' ';
     46   case DiagnosticsEngine::Note:    return '-';
     47   case DiagnosticsEngine::Remark:  return 'R';
     48   case DiagnosticsEngine::Warning: return 'W';
     49   case DiagnosticsEngine::Error:   return 'E';
     50   case DiagnosticsEngine::Fatal:   return 'F';
     51   }
     52 
     53   llvm_unreachable("Unknown diagnostic level");
     54 }
     55 
     56 static IntrusiveRefCntPtr<DiagnosticsEngine>
     57 createDiagnostics(unsigned int argc, char **argv) {
     58   IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs());
     59 
     60   // Buffer diagnostics from argument parsing so that we can output them using a
     61   // well formed diagnostic object.
     62   TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
     63   IntrusiveRefCntPtr<DiagnosticsEngine> InterimDiags(
     64     new DiagnosticsEngine(DiagIDs, new DiagnosticOptions(), DiagsBuffer));
     65 
     66   // Try to build a CompilerInvocation.
     67   SmallVector<const char *, 4> Args;
     68   Args.push_back("diagtool");
     69   Args.append(argv, argv + argc);
     70   std::unique_ptr<CompilerInvocation> Invocation(
     71       createInvocationFromCommandLine(Args, InterimDiags));
     72   if (!Invocation)
     73     return nullptr;
     74 
     75   // Build the diagnostics parser
     76   IntrusiveRefCntPtr<DiagnosticsEngine> FinalDiags =
     77     CompilerInstance::createDiagnostics(&Invocation->getDiagnosticOpts());
     78   if (!FinalDiags)
     79     return nullptr;
     80 
     81   // Flush any errors created when initializing everything. This could happen
     82   // for invalid command lines, which will probably give non-sensical results.
     83   DiagsBuffer->FlushDiagnostics(*FinalDiags);
     84 
     85   return FinalDiags;
     86 }
     87 
     88 int ShowEnabledWarnings::run(unsigned int argc, char **argv, raw_ostream &Out) {
     89   // First check our one flag (--levels).
     90   bool ShouldShowLevels = true;
     91   if (argc > 0) {
     92     StringRef FirstArg(*argv);
     93     if (FirstArg.equals("--no-levels")) {
     94       ShouldShowLevels = false;
     95       --argc;
     96       ++argv;
     97     } else if (FirstArg.equals("--levels")) {
     98       ShouldShowLevels = true;
     99       --argc;
    100       ++argv;
    101     }
    102   }
    103 
    104   // Create the diagnostic engine.
    105   IntrusiveRefCntPtr<DiagnosticsEngine> Diags = createDiagnostics(argc, argv);
    106   if (!Diags) {
    107     printUsage();
    108     return EXIT_FAILURE;
    109   }
    110 
    111   // Now we have our diagnostics. Iterate through EVERY diagnostic and see
    112   // which ones are turned on.
    113   // FIXME: It would be very nice to print which flags are turning on which
    114   // diagnostics, but this can be done with a diff.
    115   ArrayRef<DiagnosticRecord> AllDiagnostics = getBuiltinDiagnosticsByName();
    116   std::vector<PrettyDiag> Active;
    117 
    118   for (ArrayRef<DiagnosticRecord>::iterator I = AllDiagnostics.begin(),
    119                                             E = AllDiagnostics.end();
    120        I != E; ++I) {
    121     unsigned DiagID = I->DiagID;
    122 
    123     if (DiagnosticIDs::isBuiltinNote(DiagID))
    124       continue;
    125 
    126     if (!DiagnosticIDs::isBuiltinWarningOrExtension(DiagID))
    127       continue;
    128 
    129     DiagnosticsEngine::Level DiagLevel =
    130       Diags->getDiagnosticLevel(DiagID, SourceLocation());
    131     if (DiagLevel == DiagnosticsEngine::Ignored)
    132       continue;
    133 
    134     StringRef WarningOpt = DiagnosticIDs::getWarningOptionForDiag(DiagID);
    135     Active.push_back(PrettyDiag(I->getName(), WarningOpt, DiagLevel));
    136   }
    137 
    138   // Print them all out.
    139   for (std::vector<PrettyDiag>::const_iterator I = Active.begin(),
    140        E = Active.end(); I != E; ++I) {
    141     if (ShouldShowLevels)
    142       Out << getCharForLevel(I->Level) << "  ";
    143     Out << I->Name;
    144     if (!I->Flag.empty())
    145       Out << " [-W" << I->Flag << "]";
    146     Out << '\n';
    147   }
    148 
    149   return EXIT_SUCCESS;
    150 }
    151