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
13#include "clang/Analysis/MacroExpansionContext.h"
14#include "clang/Analysis/PathDiagnostic.h"
15#include "clang/Basic/SourceManager.h"
16#include "clang/CrossTU/CrossTranslationUnit.h"
17#include "clang/Frontend/ASTUnit.h"
18#include "clang/Lex/Preprocessor.h"
19#include "clang/Rewrite/Core/Rewriter.h"
20#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
21#include "clang/Tooling/Core/Replacement.h"
22#include "clang/Tooling/Tooling.h"
23
24using namespace clang;
25using namespace ento;
26using namespace tooling;
27
28namespace {
29/// Emits minimal diagnostics (report message + notes) for the 'none' output
30/// type to the standard error, or to complement many others. Emits detailed
31/// diagnostics in textual format for the 'text' output type.
32class TextDiagnostics : public PathDiagnosticConsumer {
33 PathDiagnosticConsumerOptions DiagOpts;
34 DiagnosticsEngine &DiagEng;
35 const LangOptions &LO;
36 bool ShouldDisplayPathNotes;
37
38public:
39 TextDiagnostics(PathDiagnosticConsumerOptions DiagOpts,
40 DiagnosticsEngine &DiagEng, const LangOptions &LO,
41 bool ShouldDisplayPathNotes)
42 : DiagOpts(std::move(DiagOpts)), DiagEng(DiagEng), LO(LO),
43 ShouldDisplayPathNotes(ShouldDisplayPathNotes) {}
44 ~TextDiagnostics() override {}
45
46 StringRef getName() const override { return "TextDiagnostics"; }
47
48 bool supportsLogicalOpControlFlow() const override { return true; }
49 bool supportsCrossFileDiagnostics() const override { return true; }
50
51 PathGenerationScheme getGenerationScheme() const override {
52 return ShouldDisplayPathNotes ? Minimal : None;
53 }
54
55 void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
56 FilesMade *filesMade) override {
57 unsigned WarnID =
58 DiagOpts.ShouldDisplayWarningsAsErrors
59 ? DiagEng.getCustomDiagID(L: DiagnosticsEngine::Error, FormatString: "%0")
60 : DiagEng.getCustomDiagID(L: DiagnosticsEngine::Warning, FormatString: "%0");
61 unsigned NoteID = DiagEng.getCustomDiagID(L: DiagnosticsEngine::Note, FormatString: "%0");
62 SourceManager &SM = DiagEng.getSourceManager();
63
64 Replacements Repls;
65 auto reportPiece = [&](unsigned ID, FullSourceLoc Loc, StringRef String,
66 ArrayRef<SourceRange> Ranges,
67 ArrayRef<FixItHint> Fixits) {
68 if (!DiagOpts.ShouldApplyFixIts) {
69 DiagEng.Report(Loc, DiagID: ID) << String << Ranges << Fixits;
70 return;
71 }
72
73 DiagEng.Report(Loc, DiagID: ID) << String << Ranges;
74 for (const FixItHint &Hint : Fixits) {
75 Replacement Repl(SM, Hint.RemoveRange, Hint.CodeToInsert);
76
77 if (llvm::Error Err = Repls.add(R: Repl)) {
78 llvm::errs() << "Error applying replacement " << Repl.toString()
79 << ": " << llvm::toString(E: std::move(Err)) << "\n";
80 }
81 }
82 };
83
84 for (const PathDiagnostic *PD : Diags) {
85 std::string WarningMsg = (DiagOpts.ShouldDisplayDiagnosticName
86 ? " [" + PD->getCheckerName() + "]"
87 : "")
88 .str();
89 reportPiece(WarnID, PD->getLocation().asLocation(),
90 (PD->getShortDescription() + WarningMsg).str(),
91 PD->path.back()->getRanges(), PD->path.back()->getFixits());
92
93 // First, add extra notes, even if paths should not be included.
94 for (const auto &Piece : PD->path) {
95 if (!isa<PathDiagnosticNotePiece>(Val: Piece.get()))
96 continue;
97
98 reportPiece(NoteID, Piece->getLocation().asLocation(),
99 Piece->getString(), Piece->getRanges(),
100 Piece->getFixits());
101 }
102
103 if (!ShouldDisplayPathNotes)
104 continue;
105
106 // Then, add the path notes if necessary.
107 PathPieces FlatPath = PD->path.flatten(/*ShouldFlattenMacros=*/true);
108 for (const auto &Piece : FlatPath) {
109 if (isa<PathDiagnosticNotePiece>(Val: Piece.get()))
110 continue;
111
112 reportPiece(NoteID, Piece->getLocation().asLocation(),
113 Piece->getString(), Piece->getRanges(),
114 Piece->getFixits());
115 }
116 }
117
118 if (Repls.empty())
119 return;
120
121 Rewriter Rewrite(SM, LO);
122 if (!applyAllReplacements(Replaces: Repls, Rewrite)) {
123 llvm::errs() << "An error occurred during applying fix-it.\n";
124 }
125
126 Rewrite.overwriteChangedFiles();
127 }
128};
129} // end anonymous namespace
130
131void ento::createTextPathDiagnosticConsumer(
132 PathDiagnosticConsumerOptions DiagOpts, PathDiagnosticConsumers &C,
133 const std::string &Prefix, const Preprocessor &PP,
134 const cross_tu::CrossTranslationUnitContext &CTU,
135 const MacroExpansionContext &MacroExpansions) {
136 C.emplace_back(args: new TextDiagnostics(std::move(DiagOpts), PP.getDiagnostics(),
137 PP.getLangOpts(),
138 /*ShouldDisplayPathNotes=*/true));
139}
140
141void ento::createTextMinimalPathDiagnosticConsumer(
142 PathDiagnosticConsumerOptions DiagOpts, PathDiagnosticConsumers &C,
143 const std::string &Prefix, const Preprocessor &PP,
144 const cross_tu::CrossTranslationUnitContext &CTU,
145 const MacroExpansionContext &MacroExpansions) {
146 C.emplace_back(args: new TextDiagnostics(std::move(DiagOpts), PP.getDiagnostics(),
147 PP.getLangOpts(),
148 /*ShouldDisplayPathNotes=*/false));
149}
150

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp