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::Warning: return 'W'; 48 case DiagnosticsEngine::Error: return 'E'; 49 case DiagnosticsEngine::Fatal: return 'F'; 50 } 51 52 llvm_unreachable("Unknown diagnostic level"); 53 } 54 55 static IntrusiveRefCntPtr<DiagnosticsEngine> 56 createDiagnostics(unsigned int argc, char **argv) { 57 IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs()); 58 59 // Buffer diagnostics from argument parsing so that we can output them using a 60 // well formed diagnostic object. 61 TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer; 62 IntrusiveRefCntPtr<DiagnosticsEngine> InterimDiags( 63 new DiagnosticsEngine(DiagIDs, new DiagnosticOptions(), DiagsBuffer)); 64 65 // Try to build a CompilerInvocation. 66 OwningPtr<CompilerInvocation> Invocation( 67 createInvocationFromCommandLine(ArrayRef<const char *>(argv, argc), 68 InterimDiags)); 69 if (!Invocation) 70 return NULL; 71 72 // Build the diagnostics parser 73 IntrusiveRefCntPtr<DiagnosticsEngine> FinalDiags = 74 CompilerInstance::createDiagnostics(&Invocation->getDiagnosticOpts()); 75 if (!FinalDiags) 76 return NULL; 77 78 // Flush any errors created when initializing everything. This could happen 79 // for invalid command lines, which will probably give non-sensical results. 80 DiagsBuffer->FlushDiagnostics(*FinalDiags); 81 82 return FinalDiags; 83 } 84 85 int ShowEnabledWarnings::run(unsigned int argc, char **argv, raw_ostream &Out) { 86 // First check our one flag (--levels). 87 bool ShouldShowLevels = true; 88 if (argc > 0) { 89 StringRef FirstArg(*argv); 90 if (FirstArg.equals("--no-levels")) { 91 ShouldShowLevels = false; 92 --argc; 93 ++argv; 94 } else if (FirstArg.equals("--levels")) { 95 ShouldShowLevels = true; 96 --argc; 97 ++argv; 98 } 99 } 100 101 // Create the diagnostic engine. 102 IntrusiveRefCntPtr<DiagnosticsEngine> Diags = createDiagnostics(argc, argv); 103 if (!Diags) { 104 printUsage(); 105 return EXIT_FAILURE; 106 } 107 108 // Now we have our diagnostics. Iterate through EVERY diagnostic and see 109 // which ones are turned on. 110 // FIXME: It would be very nice to print which flags are turning on which 111 // diagnostics, but this can be done with a diff. 112 ArrayRef<DiagnosticRecord> AllDiagnostics = getBuiltinDiagnosticsByName(); 113 std::vector<PrettyDiag> Active; 114 115 for (ArrayRef<DiagnosticRecord>::iterator I = AllDiagnostics.begin(), 116 E = AllDiagnostics.end(); 117 I != E; ++I) { 118 unsigned DiagID = I->DiagID; 119 120 if (DiagnosticIDs::isBuiltinNote(DiagID)) 121 continue; 122 123 if (!DiagnosticIDs::isBuiltinWarningOrExtension(DiagID)) 124 continue; 125 126 DiagnosticsEngine::Level DiagLevel = 127 Diags->getDiagnosticLevel(DiagID, SourceLocation()); 128 if (DiagLevel == DiagnosticsEngine::Ignored) 129 continue; 130 131 StringRef WarningOpt = DiagnosticIDs::getWarningOptionForDiag(DiagID); 132 Active.push_back(PrettyDiag(I->getName(), WarningOpt, DiagLevel)); 133 } 134 135 // Print them all out. 136 for (std::vector<PrettyDiag>::const_iterator I = Active.begin(), 137 E = Active.end(); I != E; ++I) { 138 if (ShouldShowLevels) 139 Out << getCharForLevel(I->Level) << " "; 140 Out << I->Name; 141 if (!I->Flag.empty()) 142 Out << " [-W" << I->Flag << "]"; 143 Out << '\n'; 144 } 145 146 return EXIT_SUCCESS; 147 } 148