clang 22.0.0git
SARIFDiagnostic.cpp
Go to the documentation of this file.
1//===--------- SARIFDiagnostic.cpp - SARIF Diagnostic Formatting ----------===//
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
13#include "clang/Basic/Sarif.h"
16#include "clang/Lex/Lexer.h"
17#include "llvm/ADT/ArrayRef.h"
18#include "llvm/ADT/SmallString.h"
19#include "llvm/ADT/StringExtras.h"
20#include "llvm/ADT/StringRef.h"
21#include "llvm/Support/Casting.h"
22#include "llvm/Support/ConvertUTF.h"
23#include "llvm/Support/ErrorHandling.h"
24#include "llvm/Support/ErrorOr.h"
25#include "llvm/Support/Locale.h"
26#include "llvm/Support/Path.h"
27#include "llvm/Support/raw_ostream.h"
28#include <algorithm>
29#include <string>
30
31namespace clang {
32
37
38// FIXME(llvm-project/issues/57323): Refactor Diagnostic classes.
41 StringRef Message, ArrayRef<clang::CharSourceRange> Ranges,
43
44 const auto *Diag = D.dyn_cast<const Diagnostic *>();
45
46 if (!Diag)
47 return;
48
49 SarifRule Rule = SarifRule::create().setRuleId(std::to_string(Diag->getID()));
50
51 Rule = addDiagnosticLevelToRule(Rule, Level);
52
53 unsigned RuleIdx = Writer->createRule(Rule);
54
57
58 if (Loc.isValid())
59 Result = addLocationToResult(Result, Loc, PLoc, Ranges, *Diag);
60
61 for (auto &[RelLoc, RelPLoc] : RelatedLocationsCache)
62 Result = addRelatedLocationToResult(Result, RelLoc, RelPLoc);
63 RelatedLocationsCache.clear();
64
65 Writer->appendResult(Result);
66}
67
69 // We always emit include location before results, for example:
70 //
71 // In file included from ...
72 // In file included from ...
73 // error: ...
74 //
75 // At this time We cannot peek the SarifRule. But what we
76 // do is to push it into a cache and wait for next time
77 // \ref SARIFDiagnostic::emitDiagnosticMessage to pick it up.
78 RelatedLocationsCache.push_back({Loc, PLoc});
79}
80
82 StringRef ModuleName) {
83 RelatedLocationsCache.push_back({Loc, PLoc});
84}
85
86SarifResult SARIFDiagnostic::addLocationToResult(
89 auto Locations = getSarifLocation(Loc, PLoc, Ranges);
90 return Result.addLocations(Locations);
91}
92
93SarifResult SARIFDiagnostic::addRelatedLocationToResult(SarifResult Result,
94 FullSourceLoc Loc,
95 PresumedLoc PLoc) {
96 auto Locations = getSarifLocation(Loc, PLoc, {});
97 return Result.addRelatedLocations(Locations);
98}
99
101SARIFDiagnostic::getSarifLocation(FullSourceLoc Loc, PresumedLoc PLoc,
103 SmallVector<CharSourceRange> Locations = {};
104
105 if (PLoc.isInvalid()) {
106 // At least add the file name if available:
107 FileID FID = Loc.getFileID();
108 if (FID.isValid()) {
109 if (OptionalFileEntryRef FE = Loc.getFileEntryRef()) {
110 emitFilename(FE->getName(), Loc.getManager());
111 // FIXME(llvm-project/issues/57366): File-only locations
112 }
113 }
114 return {};
115 }
116
117 FileID CaretFileID = Loc.getExpansionLoc().getFileID();
118
119 for (const CharSourceRange Range : Ranges) {
120 // Ignore invalid ranges.
121 if (Range.isInvalid())
122 continue;
123
124 auto &SM = Loc.getManager();
125 SourceLocation B = SM.getExpansionLoc(Range.getBegin());
126 CharSourceRange ERange = SM.getExpansionRange(Range.getEnd());
127 SourceLocation E = ERange.getEnd();
128 bool IsTokenRange = ERange.isTokenRange();
129
130 FileIDAndOffset BInfo = SM.getDecomposedLoc(B);
131 FileIDAndOffset EInfo = SM.getDecomposedLoc(E);
132
133 // If the start or end of the range is in another file, just discard
134 // it.
135 if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
136 continue;
137
138 // Add in the length of the token, so that we cover multi-char
139 // tokens.
140 unsigned TokSize = 0;
141 if (IsTokenRange)
143
144 FullSourceLoc BF(B, SM), EF(E, SM);
145 SourceLocation BeginLoc = SM.translateLineCol(
146 BF.getFileID(), BF.getLineNumber(), BF.getColumnNumber());
147 SourceLocation EndLoc = SM.translateLineCol(
148 EF.getFileID(), EF.getLineNumber(), EF.getColumnNumber() + TokSize);
149
150 Locations.push_back(
151 CharSourceRange{SourceRange{BeginLoc, EndLoc}, /* ITR = */ false});
152 // FIXME: Additional ranges should use presumed location in both
153 // Text and SARIF diagnostics.
154 }
155
156 auto &SM = Loc.getManager();
157 auto FID = PLoc.getFileID();
158 // Visual Studio 2010 or earlier expects column number to be off by one.
159 unsigned int ColNo = (LangOpts.MSCompatibilityVersion &&
160 !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2012))
161 ? PLoc.getColumn() - 1
162 : PLoc.getColumn();
163 SourceLocation DiagLoc = SM.translateLineCol(FID, PLoc.getLine(), ColNo);
164
165 // FIXME(llvm-project/issues/57366): Properly process #line directives.
166 CharSourceRange Range = {SourceRange{DiagLoc, DiagLoc}, /* ITR = */ false};
167 if (Range.isValid())
168 Locations.push_back(std::move(Range));
169
170 return Locations;
171}
172
174SARIFDiagnostic::addDiagnosticLevelToRule(SarifRule Rule,
177
178 switch (Level) {
180 Config = Config.setLevel(SarifResultLevel::Note);
181 break;
183 Config = Config.setLevel(SarifResultLevel::None);
184 break;
186 Config = Config.setLevel(SarifResultLevel::Warning);
187 break;
189 Config = Config.setLevel(SarifResultLevel::Error).setRank(50);
190 break;
192 Config = Config.setLevel(SarifResultLevel::Error).setRank(100);
193 break;
195 assert(false && "Invalid diagnostic type");
196 }
197
198 return Rule.setDefaultConfiguration(Config);
199}
200
201llvm::StringRef SARIFDiagnostic::emitFilename(StringRef Filename,
202 const SourceManager &SM) {
203 if (DiagOpts.AbsolutePath) {
204 auto File = SM.getFileManager().getOptionalFileRef(Filename);
205 if (File) {
206 // We want to print a simplified absolute path, i. e. without "dots".
207 //
208 // The hardest part here are the paths like "<part1>/<link>/../<part2>".
209 // On Unix-like systems, we cannot just collapse "<link>/..", because
210 // paths are resolved sequentially, and, thereby, the path
211 // "<part1>/<part2>" may point to a different location. That is why
212 // we use FileManager::getCanonicalName(), which expands all indirections
213 // with llvm::sys::fs::real_path() and caches the result.
214 //
215 // On the other hand, it would be better to preserve as much of the
216 // original path as possible, because that helps a user to recognize it.
217 // real_path() expands all links, which is sometimes too much. Luckily,
218 // on Windows we can just use llvm::sys::path::remove_dots(), because,
219 // on that system, both aforementioned paths point to the same place.
220#ifdef _WIN32
221 SmallString<256> TmpFilename = File->getName();
222 llvm::sys::fs::make_absolute(TmpFilename);
223 llvm::sys::path::native(TmpFilename);
224 llvm::sys::path::remove_dots(TmpFilename, /* remove_dot_dot */ true);
225 Filename = StringRef(TmpFilename.data(), TmpFilename.size());
226#else
227 Filename = SM.getFileManager().getCanonicalName(*File);
228#endif
229 }
230 }
231
232 return Filename;
233}
234
235/// Print out the file/line/column information and include trace.
236///
237/// This method handlen the emission of the diagnostic location information.
238/// This includes extracting as much location information as is present for
239/// the diagnostic and printing it, as well as any include stack or source
240/// ranges necessary.
244 assert(false && "Not implemented in SARIF mode");
245}
246
248 PresumedLoc PLoc,
249 StringRef ModuleName) {
250 assert(false && "Not implemented in SARIF mode");
251}
252} // namespace clang
Defines the clang::FileManager interface and associated types.
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
#define SM(sm)
Defines clang::SarifDocumentWriter, clang::SarifRule, clang::SarifResult.
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
Options for controlling the compiler diagnostics engine.
const LangOptions & LangOpts
DiagnosticOptions & DiagOpts
DiagnosticRenderer(const LangOptions &LangOpts, DiagnosticOptions &DiagOpts)
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine a...
Level
The level of the diagnostic, after it has been through mapping.
Definition Diagnostic.h:237
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...
static unsigned MeasureTokenLength(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
MeasureTokenLength - Relex the token at the specified location and return its length in bytes in the ...
Definition Lexer.cpp:498
Represents an unpacked "presumed" location which can be presented to the user.
SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts, DiagnosticOptions &DiagOpts, SarifDocumentWriter *Writer)
void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) override
void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, StringRef Message, ArrayRef< CharSourceRange > Ranges, DiagOrStoredDiag D) override
void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, ArrayRef< CharSourceRange > Ranges) override
Print out the file/line/column information and include trace.
void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName) override
void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName) override
This class handles creating a valid SARIF document given various input attributes.
Definition Sarif.h:407
static SarifReportingConfiguration create()
Definition Sarif.h:221
A SARIF result (also called a "reporting item") is a unit of output produced when one of the tool's r...
Definition Sarif.h:315
SarifResult setDiagnosticMessage(llvm::StringRef Message)
Definition Sarif.h:348
static SarifResult create(uint32_t RuleIdx)
Definition Sarif.h:336
A SARIF rule (reportingDescriptor object) contains information that describes a reporting item genera...
Definition Sarif.h:257
SarifRule setRuleId(llvm::StringRef RuleId)
Definition Sarif.h:276
static SarifRule create()
Definition Sarif.h:269
bool isValid() const
Return true if this is a valid SourceLocation object.
This class handles loading and caching of source files into memory.
const Regex Rule("(.+)/(.+)\\.framework/")
The JSON file list parser is used to communicate input to InstallAPI.
CustomizableOptional< FileEntryRef > OptionalFileEntryRef
Definition FileEntry.h:208
llvm::PointerUnion< const Diagnostic *, const StoredDiagnostic * > DiagOrStoredDiag
std::pair< FileID, unsigned > FileIDAndOffset
@ Result
The result type of a method or function.
Definition TypeBase.h:905