clang-tools 22.0.0git
Diagnostics.h
Go to the documentation of this file.
1//===--- Diagnostics.h -------------------------------------------*- 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#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_DIAGNOSTICS_H
10#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_DIAGNOSTICS_H
11
12#include "Protocol.h"
13#include "clang/Basic/Diagnostic.h"
14#include "clang/Basic/LangOptions.h"
15#include "clang/Basic/SourceLocation.h"
16#include "llvm/ADT/ArrayRef.h"
17#include "llvm/ADT/DenseSet.h"
18#include "llvm/ADT/SmallVector.h"
19#include "llvm/ADT/StringSet.h"
20#include "llvm/Support/JSON.h"
21#include "llvm/Support/SourceMgr.h"
22#include <cassert>
23#include <functional>
24#include <memory>
25#include <optional>
26#include <string>
27#include <utility>
28#include <vector>
29
30namespace clang {
31namespace tidy {
33} // namespace tidy
34namespace clangd {
35
37 /// If true, Clangd uses an LSP extension to embed the fixes with the
38 /// diagnostics that are sent to the client.
40
41 /// If true, Clangd uses the relatedInformation field to include other
42 /// locations (in particular attached notes).
43 /// Otherwise, these are flattened into the diagnostic message.
45
46 /// If true, Clangd uses an LSP extension to send the diagnostic's
47 /// category to the client. The category typically describes the compilation
48 /// stage during which the issue was produced, e.g. "Semantic Issue" or "Parse
49 /// Issue".
51
52 /// If true, Clangd will add a number of available fixes to the diagnostic's
53 /// message.
54 bool DisplayFixesCount = true;
55};
56
57/// Contains basic information about a diagnostic.
58struct DiagBase {
59 std::string Message;
60 // Intended to be used only in error messages.
61 // May be relative, absolute or even artificially constructed.
62 std::string File;
63 // Absolute path to containing file, if available.
64 std::optional<std::string> AbsFile;
65
67 DiagnosticsEngine::Level Severity = DiagnosticsEngine::Note;
68 std::string Category;
69 // Since File is only descriptive, we store a separate flag to distinguish
70 // diags from the main file.
71 bool InsideMainFile = false;
72 unsigned ID = 0; // e.g. member of clang::diag, or clang-tidy assigned ID.
73 // Feature modules can make use of this field to propagate data from a
74 // diagnostic to a CodeAction request. Each module should only append to the
75 // list.
76 llvm::json::Object OpaqueData;
77};
78llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const DiagBase &D);
79
80/// Represents a single fix-it that editor can apply to fix the error.
81struct Fix {
82 /// Message for the fix-it.
83 std::string Message;
84 /// TextEdits from clang's fix-its. Must be non-empty.
85 llvm::SmallVector<TextEdit, 1> Edits;
86
87 /// Annotations for the Edits.
88 llvm::SmallVector<std::pair<ChangeAnnotationIdentifier, ChangeAnnotation>>
90};
91llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Fix &F);
92
93/// Represents a note for the diagnostic. Severity of notes can only be 'note'
94/// or 'remark'.
95struct Note : DiagBase {};
96
97/// A top-level diagnostic that may have Notes and Fixes.
98struct Diag : DiagBase {
99 std::string Name; // if ID was recognized.
100 // The source of this diagnostic.
108 /// Elaborate on the problem, usually pointing to a related piece of code.
109 std::vector<Note> Notes;
110 /// *Alternative* fixes for this diagnostic, one should be chosen.
111 std::vector<Fix> Fixes;
112 llvm::SmallVector<DiagnosticTag, 1> Tags;
113};
114llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Diag &D);
115
116Diag toDiag(const llvm::SMDiagnostic &, Diag::DiagSource Source);
117
118/// Conversion to LSP diagnostics. Formats the error message of each diagnostic
119/// to include all its notes. Notes inside main file are also provided as
120/// separate diagnostics with their corresponding fixits. Notes outside main
121/// file do not have a corresponding LSP diagnostic, but can still be included
122/// as part of their main diagnostic's message.
123void toLSPDiags(
124 const Diag &D, const URIForFile &File, const ClangdDiagnosticOptions &Opts,
125 llvm::function_ref<void(clangd::Diagnostic, llvm::ArrayRef<Fix>)> OutFn);
126
127/// Convert from clang diagnostic level to LSP severity.
128int getSeverity(DiagnosticsEngine::Level L);
129
130/// Returns a URI providing more information about a particular diagnostic.
131std::optional<std::string> getDiagnosticDocURI(Diag::DiagSource, unsigned ID,
132 llvm::StringRef Name);
133
134/// StoreDiags collects the diagnostics that can later be reported by
135/// clangd. It groups all notes for a diagnostic into a single Diag
136/// and filters out diagnostics that don't mention the main file (i.e. neither
137/// the diag itself nor its notes are in the main file).
139public:
140 // The ClangTidyContext populates Source and Name for clang-tidy diagnostics.
141 std::vector<Diag> take(const clang::tidy::ClangTidyContext *Tidy = nullptr);
142
143 void BeginSourceFile(const LangOptions &Opts,
144 const Preprocessor *PP) override;
145 void EndSourceFile() override;
146 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
147 const clang::Diagnostic &Info) override;
148
149 /// When passed a main diagnostic, returns fixes to add to it.
150 /// When passed a note diagnostic, returns fixes to replace it with.
151 using DiagFixer = std::function<std::vector<Fix>(DiagnosticsEngine::Level,
152 const clang::Diagnostic &)>;
153 using LevelAdjuster = std::function<DiagnosticsEngine::Level(
154 DiagnosticsEngine::Level, const clang::Diagnostic &)>;
156 std::function<void(const clang::Diagnostic &, clangd::Diag &)>;
157 /// If set, possibly adds fixes for diagnostics using \p Fixer.
158 void contributeFixes(DiagFixer Fixer) { this->Fixer = Fixer; }
159 /// If set, this allows the client of this class to adjust the level of
160 /// diagnostics, such as promoting warnings to errors, or ignoring
161 /// diagnostics.
162 void setLevelAdjuster(LevelAdjuster Adjuster) { this->Adjuster = Adjuster; }
163 /// Invokes a callback every time a diagnostics is completely formed. Handler
164 /// of the callback can also mutate the diagnostic.
165 void setDiagCallback(DiagCallback CB) { DiagCB = std::move(CB); }
166
167private:
168 void flushLastDiag();
169
170 DiagFixer Fixer = nullptr;
171 LevelAdjuster Adjuster = nullptr;
172 DiagCallback DiagCB = nullptr;
173 std::vector<Diag> Output;
174 std::optional<LangOptions> LangOpts;
175 std::optional<Diag> LastDiag;
176 std::optional<FullSourceLoc> LastDiagLoc; // Valid only when LastDiag is set.
177 bool LastDiagOriginallyError = false; // Valid only when LastDiag is set.
178 SourceManager *OrigSrcMgr = nullptr;
179
180 llvm::DenseSet<std::pair<unsigned, unsigned>> IncludedErrorLocations;
181};
182
183/// Determine whether a (non-clang-tidy) diagnostic is suppressed by config.
184bool isDiagnosticSuppressed(const clang::Diagnostic &Diag,
185 const llvm::StringSet<> &Suppressed,
186 const LangOptions &);
187/// Take a user-specified diagnostic code, and convert it to a normalized form
188/// stored in the config and consumed by isDiagnosticsSuppressed.
189///
190/// (This strips err_ and -W prefix so we can match with or without them.)
191llvm::StringRef normalizeSuppressedCode(llvm::StringRef);
192
193} // namespace clangd
194} // namespace clang
195
196#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_DIAGNOSTICS_H
StoreDiags collects the diagnostics that can later be reported by clangd.
void contributeFixes(DiagFixer Fixer)
If set, possibly adds fixes for diagnostics using Fixer.
void setLevelAdjuster(LevelAdjuster Adjuster)
If set, this allows the client of this class to adjust the level of diagnostics, such as promoting wa...
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) override
std::vector< Diag > take(const clang::tidy::ClangTidyContext *Tidy=nullptr)
std::function< void(const clang::Diagnostic &, clangd::Diag &)> DiagCallback
void setDiagCallback(DiagCallback CB)
Invokes a callback every time a diagnostics is completely formed.
void BeginSourceFile(const LangOptions &Opts, const Preprocessor *PP) override
void EndSourceFile() override
std::function< DiagnosticsEngine::Level( DiagnosticsEngine::Level, const clang::Diagnostic &)> LevelAdjuster
std::function< std::vector< Fix >(DiagnosticsEngine::Level, const clang::Diagnostic &)> DiagFixer
When passed a main diagnostic, returns fixes to add to it.
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
Definition AST.cpp:45
bool isDiagnosticSuppressed(const clang::Diagnostic &Diag, const llvm::StringSet<> &Suppress, const LangOptions &LangOpts)
Determine whether a (non-clang-tidy) diagnostic is suppressed by config.
@ Info
An information message.
Definition Protocol.h:738
void toLSPDiags(const Diag &D, const URIForFile &File, const ClangdDiagnosticOptions &Opts, llvm::function_ref< void(clangd::Diagnostic, llvm::ArrayRef< Fix >)> OutFn)
Conversion to LSP diagnostics.
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const CodeCompletion &C)
llvm::StringRef normalizeSuppressedCode(llvm::StringRef Code)
Take a user-specified diagnostic code, and convert it to a normalized form stored in the config and c...
Diag toDiag(const llvm::SMDiagnostic &D, Diag::DiagSource Source)
int getSeverity(DiagnosticsEngine::Level L)
Convert from clang diagnostic level to LSP severity.
std::optional< std::string > getDiagnosticDocURI(Diag::DiagSource Source, unsigned ID, llvm::StringRef Name)
Returns a URI providing more information about a particular diagnostic.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
bool EmbedFixesInDiagnostics
If true, Clangd uses an LSP extension to embed the fixes with the diagnostics that are sent to the cl...
Definition Diagnostics.h:39
bool SendDiagnosticCategory
If true, Clangd uses an LSP extension to send the diagnostic's category to the client.
Definition Diagnostics.h:50
bool DisplayFixesCount
If true, Clangd will add a number of available fixes to the diagnostic's message.
Definition Diagnostics.h:54
bool EmitRelatedLocations
If true, Clangd uses the relatedInformation field to include other locations (in particular attached ...
Definition Diagnostics.h:44
Contains basic information about a diagnostic.
Definition Diagnostics.h:58
llvm::json::Object OpaqueData
Definition Diagnostics.h:76
DiagnosticsEngine::Level Severity
Definition Diagnostics.h:67
std::optional< std::string > AbsFile
Definition Diagnostics.h:64
A top-level diagnostic that may have Notes and Fixes.
Definition Diagnostics.h:98
std::vector< Fix > Fixes
Alternative fixes for this diagnostic, one should be chosen.
llvm::SmallVector< DiagnosticTag, 1 > Tags
enum clang::clangd::Diag::DiagSource Source
std::vector< Note > Notes
Elaborate on the problem, usually pointing to a related piece of code.
Represents a single fix-it that editor can apply to fix the error.
Definition Diagnostics.h:81
llvm::SmallVector< std::pair< ChangeAnnotationIdentifier, ChangeAnnotation > > Annotations
Annotations for the Edits.
Definition Diagnostics.h:89
std::string Message
Message for the fix-it.
Definition Diagnostics.h:83
llvm::SmallVector< TextEdit, 1 > Edits
TextEdits from clang's fix-its. Must be non-empty.
Definition Diagnostics.h:85
Represents a note for the diagnostic.
Definition Diagnostics.h:95