clang 20.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"
25#include "llvm/ADT/SmallPtrSet.h"
26#include "llvm/ADT/SmallVector.h"
27#include "llvm/Support/Casting.h"
28
29using namespace clang;
30using namespace ento;
31using namespace tooling;
32
33namespace {
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.
37class TextDiagnostics : public PathDiagnosticConsumer {
39 DiagnosticsEngine &DiagEng;
40 const LangOptions &LO;
41 bool ShouldDisplayPathNotes;
42
43public:
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");
68
69 Replacements Repls;
70 auto reportPiece = [&](unsigned ID, FullSourceLoc Loc, StringRef String,
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
137void 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
147void 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}
#define SM(sm)
Definition: Cuda.cpp:83
Defines the clang::Preprocessor interface.
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:192
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Definition: Diagnostic.h:1547
unsigned getCustomDiagID(Level L, const char(&FormatString)[N])
Return an ID for a diagnostic with the specified format string and level.
Definition: Diagnostic.h:873
SourceManager & getSourceManager() const
Definition: Diagnostic.h:584
Annotates a diagnostic with some code that should be inserted, removed, or replaced to fix the proble...
Definition: Diagnostic.h:71
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:476
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:137
const LangOptions & getLangOpts() const
DiagnosticsEngine & getDiagnostics() 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.
@ None
Only runs visitors, no output generated.
@ Minimal
Used for SARIF and text output.
virtual bool supportsLogicalOpControlFlow() const
virtual void FlushDiagnosticsImpl(std::vector< const PathDiagnostic * > &Diags, FilesMade *filesMade)=0
virtual bool supportsCrossFileDiagnostics() const
Return true if the PathDiagnosticConsumer supports individual PathDiagnostics that span multiple file...
virtual StringRef getName() const =0
virtual PathGenerationScheme getGenerationScheme() const
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.
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...
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....