clang 23.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 const auto &DiagnosticIDs = *(Diag->getDiags()->getDiagnosticIDs());
50 std::string StableID = DiagnosticIDs.getStableID(Diag->getID());
51 auto LegacyStableIDs = DiagnosticIDs.getLegacyStableIDs(Diag->getID());
52 SarifRule Rule =
53 SarifRule::create().setRuleId(StableID).setDeprecatedIds(LegacyStableIDs);
54
55 Rule = addDiagnosticLevelToRule(Rule, Level);
56
57 unsigned RuleIdx = Writer->createRule(Rule);
58
61
62 if (Loc.isValid())
63 Result = addLocationToResult(Result, Loc, PLoc, Ranges, *Diag);
64
65 for (auto &[RelLoc, RelPLoc] : RelatedLocationsCache)
66 Result = addRelatedLocationToResult(Result, RelLoc, RelPLoc);
67 RelatedLocationsCache.clear();
68
69 Writer->appendResult(Result);
70}
71
73 // We always emit include location before results, for example:
74 //
75 // In file included from ...
76 // In file included from ...
77 // error: ...
78 //
79 // At this time We cannot peek the SarifRule. But what we
80 // do is to push it into a cache and wait for next time
81 // \ref SARIFDiagnostic::emitDiagnosticMessage to pick it up.
82 RelatedLocationsCache.push_back({Loc, PLoc});
83}
84
86 StringRef ModuleName) {
87 RelatedLocationsCache.push_back({Loc, PLoc});
88}
89
90SarifResult SARIFDiagnostic::addLocationToResult(
93 auto Locations = getSarifLocation(Loc, PLoc, Ranges);
94 return Result.addLocations(Locations);
95}
96
97SarifResult SARIFDiagnostic::addRelatedLocationToResult(SarifResult Result,
98 FullSourceLoc Loc,
99 PresumedLoc PLoc) {
100 auto Locations = getSarifLocation(Loc, PLoc, {});
101 return Result.addRelatedLocations(Locations);
102}
103
105SARIFDiagnostic::getSarifLocation(FullSourceLoc Loc, PresumedLoc PLoc,
107 SmallVector<CharSourceRange> Locations = {};
108
109 if (PLoc.isInvalid()) {
110 // At least add the file name if available:
111 FileID FID = Loc.getFileID();
112 if (FID.isValid()) {
113 if (OptionalFileEntryRef FE = Loc.getFileEntryRef()) {
114 emitFilename(FE->getName(), Loc.getManager());
115 // FIXME(llvm-project/issues/57366): File-only locations
116 }
117 }
118 return {};
119 }
120
121 FileID CaretFileID = Loc.getExpansionLoc().getFileID();
122
123 for (const CharSourceRange Range : Ranges) {
124 // Ignore invalid ranges.
125 if (Range.isInvalid())
126 continue;
127
128 auto &SM = Loc.getManager();
129 SourceLocation B = SM.getExpansionLoc(Range.getBegin());
130 CharSourceRange ERange = SM.getExpansionRange(Range.getEnd());
131 SourceLocation E = ERange.getEnd();
132 bool IsTokenRange = ERange.isTokenRange();
133
134 FileIDAndOffset BInfo = SM.getDecomposedLoc(B);
135 FileIDAndOffset EInfo = SM.getDecomposedLoc(E);
136
137 // If the start or end of the range is in another file, just discard
138 // it.
139 if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
140 continue;
141
142 // Add in the length of the token, so that we cover multi-char
143 // tokens.
144 unsigned TokSize = 0;
145 if (IsTokenRange)
147
148 FullSourceLoc BF(B, SM), EF(E, SM);
149 SourceLocation BeginLoc = SM.translateLineCol(
150 BF.getFileID(), BF.getLineNumber(), BF.getColumnNumber());
151 SourceLocation EndLoc = SM.translateLineCol(
152 EF.getFileID(), EF.getLineNumber(), EF.getColumnNumber() + TokSize);
153
154 Locations.push_back(
155 CharSourceRange{SourceRange{BeginLoc, EndLoc}, /* ITR = */ false});
156 // FIXME: Additional ranges should use presumed location in both
157 // Text and SARIF diagnostics.
158 }
159
160 auto &SM = Loc.getManager();
161 auto FID = PLoc.getFileID();
162 // Visual Studio 2010 or earlier expects column number to be off by one.
163 unsigned int ColNo = (LangOpts.MSCompatibilityVersion &&
164 !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2012))
165 ? PLoc.getColumn() - 1
166 : PLoc.getColumn();
167 SourceLocation DiagLoc = SM.translateLineCol(FID, PLoc.getLine(), ColNo);
168
169 // FIXME(llvm-project/issues/57366): Properly process #line directives.
170 CharSourceRange Range = {SourceRange{DiagLoc, DiagLoc}, /* ITR = */ false};
171 if (Range.isValid())
172 Locations.push_back(std::move(Range));
173
174 return Locations;
175}
176
178SARIFDiagnostic::addDiagnosticLevelToRule(SarifRule Rule,
181
182 switch (Level) {
184 Config = Config.setLevel(SarifResultLevel::Note);
185 break;
187 Config = Config.setLevel(SarifResultLevel::None);
188 break;
190 Config = Config.setLevel(SarifResultLevel::Warning);
191 break;
193 Config = Config.setLevel(SarifResultLevel::Error).setRank(50);
194 break;
196 Config = Config.setLevel(SarifResultLevel::Error).setRank(100);
197 break;
199 assert(false && "Invalid diagnostic type");
200 }
201
202 return Rule.setDefaultConfiguration(Config);
203}
204
205llvm::StringRef SARIFDiagnostic::emitFilename(StringRef Filename,
206 const SourceManager &SM) {
207 if (DiagOpts.AbsolutePath) {
208 auto File = SM.getFileManager().getOptionalFileRef(Filename);
209 if (File) {
210 // We want to print a simplified absolute path, i. e. without "dots".
211 //
212 // The hardest part here are the paths like "<part1>/<link>/../<part2>".
213 // On Unix-like systems, we cannot just collapse "<link>/..", because
214 // paths are resolved sequentially, and, thereby, the path
215 // "<part1>/<part2>" may point to a different location. That is why
216 // we use FileManager::getCanonicalName(), which expands all indirections
217 // with llvm::sys::fs::real_path() and caches the result.
218 //
219 // On the other hand, it would be better to preserve as much of the
220 // original path as possible, because that helps a user to recognize it.
221 // real_path() expands all links, which is sometimes too much. Luckily,
222 // on Windows we can just use llvm::sys::path::remove_dots(), because,
223 // on that system, both aforementioned paths point to the same place.
224#ifdef _WIN32
225 SmallString<256> TmpFilename = File->getName();
226 SM.getFileManager().makeAbsolutePath(TmpFilename);
227 llvm::sys::path::native(TmpFilename);
228 llvm::sys::path::remove_dots(TmpFilename, /* remove_dot_dot */ true);
229 Filename = StringRef(TmpFilename.data(), TmpFilename.size());
230#else
231 Filename = SM.getFileManager().getCanonicalName(*File);
232#endif
233 }
234 }
235
236 return Filename;
237}
238
239/// Print out the file/line/column information and include trace.
240///
241/// This method handlen the emission of the diagnostic location information.
242/// This includes extracting as much location information as is present for
243/// the diagnostic and printing it, as well as any include stack or source
244/// ranges necessary.
248 assert(false && "Not implemented in SARIF mode");
249}
250
252 PresumedLoc PLoc,
253 StringRef ModuleName) {
254 assert(false && "Not implemented in SARIF mode");
255}
256} // 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.
Used for handling and querying diagnostic IDs.
std::string getStableID(unsigned DiagID) const
Given a diagnostic ID, return the stable ID of the diagnostic.
llvm::SmallVector< StringRef, 4 > getLegacyStableIDs(unsigned DiagID) const
Given a diagnostic ID, return the previous stable IDs of the diagnostic.
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:508
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:414
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:322
SarifResult setDiagnosticMessage(llvm::StringRef Message)
Definition Sarif.h:355
static SarifResult create(uint32_t RuleIdx)
Definition Sarif.h:343
A SARIF rule (reportingDescriptor object) contains information that describes a reporting item genera...
Definition Sarif.h:257
SarifRule setDeprecatedIds(llvm::ArrayRef< llvm::StringRef > RuleDeprecatedIds)
Definition Sarif.h:293
SarifRule setRuleId(llvm::StringRef RuleId)
Definition Sarif.h:277
static SarifRule create()
Definition Sarif.h:270
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