clang  19.0.0git
TextDiagnostics.cpp
Go to the documentation of this file.
1 //===--- TextDiagnostics.cpp - Text Diagnostics for Paths -------*- C++ -*-===//
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 // This file defines the TextDiagnostics object.
10 //
11 //===----------------------------------------------------------------------===//
12 
16 #include "clang/Basic/Version.h"
18 #include "clang/Frontend/ASTUnit.h"
19 #include "clang/Lex/Preprocessor.h"
24 #include "clang/Tooling/Tooling.h"
25 #include "llvm/ADT/SmallPtrSet.h"
26 #include "llvm/ADT/SmallVector.h"
27 #include "llvm/Support/Casting.h"
28 
29 using namespace clang;
30 using namespace ento;
31 using namespace tooling;
32 
33 namespace {
34 /// Emits minimal diagnostics (report message + notes) for the 'none' output
35 /// type to the standard error, or to complement many others. Emits detailed
36 /// diagnostics in textual format for the 'text' output type.
37 class TextDiagnostics : public PathDiagnosticConsumer {
39  DiagnosticsEngine &DiagEng;
40  const LangOptions &LO;
41  bool ShouldDisplayPathNotes;
42 
43 public:
44  TextDiagnostics(PathDiagnosticConsumerOptions DiagOpts,
45  DiagnosticsEngine &DiagEng, const LangOptions &LO,
46  bool ShouldDisplayPathNotes)
47  : DiagOpts(std::move(DiagOpts)), DiagEng(DiagEng), LO(LO),
48  ShouldDisplayPathNotes(ShouldDisplayPathNotes) {}
49  ~TextDiagnostics() override {}
50 
51  StringRef getName() const override { return "TextDiagnostics"; }
52 
53  bool supportsLogicalOpControlFlow() const override { return true; }
54  bool supportsCrossFileDiagnostics() const override { return true; }
55 
56  PathGenerationScheme getGenerationScheme() const override {
57  return ShouldDisplayPathNotes ? Minimal : None;
58  }
59 
60  void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
61  FilesMade *filesMade) override {
62  unsigned WarnID =
66  unsigned NoteID = DiagEng.getCustomDiagID(DiagnosticsEngine::Note, "%0");
67  SourceManager &SM = DiagEng.getSourceManager();
68 
69  Replacements Repls;
70  auto reportPiece = [&](unsigned ID, FullSourceLoc Loc, StringRef String,
71  ArrayRef<SourceRange> Ranges,
72  ArrayRef<FixItHint> Fixits) {
73  if (!DiagOpts.ShouldApplyFixIts) {
74  DiagEng.Report(Loc, ID) << String << Ranges << Fixits;
75  return;
76  }
77 
78  DiagEng.Report(Loc, ID) << String << Ranges;
79  for (const FixItHint &Hint : Fixits) {
80  Replacement Repl(SM, Hint.RemoveRange, Hint.CodeToInsert);
81 
82  if (llvm::Error Err = Repls.add(Repl)) {
83  llvm::errs() << "Error applying replacement " << Repl.toString()
84  << ": " << Err << "\n";
85  }
86  }
87  };
88 
89  for (const PathDiagnostic *PD : Diags) {
90  std::string WarningMsg = (DiagOpts.ShouldDisplayDiagnosticName
91  ? " [" + PD->getCheckerName() + "]"
92  : "")
93  .str();
94 
95  reportPiece(WarnID, PD->getLocation().asLocation(),
96  (PD->getShortDescription() + WarningMsg).str(),
97  PD->path.back()->getRanges(), PD->path.back()->getFixits());
98 
99  // First, add extra notes, even if paths should not be included.
100  for (const auto &Piece : PD->path) {
101  if (!isa<PathDiagnosticNotePiece>(Piece.get()))
102  continue;
103 
104  reportPiece(NoteID, Piece->getLocation().asLocation(),
105  Piece->getString(), Piece->getRanges(),
106  Piece->getFixits());
107  }
108 
109  if (!ShouldDisplayPathNotes)
110  continue;
111 
112  // Then, add the path notes if necessary.
113  PathPieces FlatPath = PD->path.flatten(/*ShouldFlattenMacros=*/true);
114  for (const auto &Piece : FlatPath) {
115  if (isa<PathDiagnosticNotePiece>(Piece.get()))
116  continue;
117 
118  reportPiece(NoteID, Piece->getLocation().asLocation(),
119  Piece->getString(), Piece->getRanges(),
120  Piece->getFixits());
121  }
122  }
123 
124  if (Repls.empty())
125  return;
126 
127  Rewriter Rewrite(SM, LO);
128  if (!applyAllReplacements(Repls, Rewrite)) {
129  llvm::errs() << "An error occurred during applying fix-it.\n";
130  }
131 
132  Rewrite.overwriteChangedFiles();
133  }
134 };
135 } // end anonymous namespace
136 
137 void ento::createTextPathDiagnosticConsumer(
139  const std::string &Prefix, const Preprocessor &PP,
141  const MacroExpansionContext &MacroExpansions) {
142  C.emplace_back(new TextDiagnostics(std::move(DiagOpts), PP.getDiagnostics(),
143  PP.getLangOpts(),
144  /*ShouldDisplayPathNotes=*/true));
145 }
146 
147 void ento::createTextMinimalPathDiagnosticConsumer(
149  const std::string &Prefix, const Preprocessor &PP,
151  const MacroExpansionContext &MacroExpansions) {
152  C.emplace_back(new TextDiagnostics(std::move(DiagOpts), PP.getDiagnostics(),
153  PP.getLangOpts(),
154  /*ShouldDisplayPathNotes=*/false));
155 }
static char ID
Definition: Arena.cpp:183
#define SM(sm)
Definition: Cuda.cpp:83
Defines the clang::Preprocessor interface.
static std::string getName(const CallEvent &Call)
SourceLocation Loc
Definition: SemaObjC.cpp:755
Defines the SourceManager interface.
Defines version macros and version-related utility functions for Clang.
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:193
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Definition: Diagnostic.h:1553
unsigned getCustomDiagID(Level L, const char(&FormatString)[N])
Return an ID for a diagnostic with the specified format string and level.
Definition: Diagnostic.h:879
SourceManager & getSourceManager() const
Definition: Diagnostic.h:590
Annotates a diagnostic with some code that should be inserted, removed, or replaced to fix the proble...
Definition: Diagnostic.h:72
A SourceLocation and its associated SourceManager.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:482
MacroExpansionContext tracks the macro expansions processed by the Preprocessor.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:128
DiagnosticsEngine & getDiagnostics() const
const LangOptions & getLangOpts() const
Rewriter - This is the main interface to the rewrite buffers.
Definition: Rewriter.h:32
This class handles loading and caching of source files into memory.
This class is used for tools that requires cross translation unit capability.
PathDiagnostic - PathDiagnostic objects represent a single path-sensitive diagnostic.
PathPieces flatten(bool ShouldFlattenMacros) const
A text replacement.
Definition: Replacement.h:83
Maintains a set of replacements that are conflict-free.
Definition: Replacement.h:212
llvm::Error add(const Replacement &R)
Adds a new replacement R to the current set of replacements.
constexpr XRayInstrMask None
Definition: XRayInstr.h:38
std::vector< PathDiagnosticConsumer * > PathDiagnosticConsumers
bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite)
Apply all replacements in Replaces to the Rewriter Rewrite.
The JSON file list parser is used to communicate input to InstallAPI.
@ Rewrite
We are substituting template parameters for (typically) other template parameters in order to rewrite...
Definition: Format.h:5433
These options tweak the behavior of path diangostic consumers.
bool ShouldDisplayWarningsAsErrors
Whether the consumer should treat consumed diagnostics as hard errors.
bool ShouldApplyFixIts
Whether the consumer should attempt to rewrite the source file with fix-it hints attached to the diag...
bool ShouldDisplayDiagnosticName
Whether the consumer should present the name of the entity that emitted the diagnostic (eg....