Clang Project

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