clang 17.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
33SARIFDiagnostic::SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
34 DiagnosticOptions *DiagOpts,
35 SarifDocumentWriter *Writer)
36 : DiagnosticRenderer(LangOpts, DiagOpts), Writer(Writer) {}
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 Writer->appendResult(Result);
62}
63
64SarifResult SARIFDiagnostic::addLocationToResult(
67 SmallVector<CharSourceRange> Locations = {};
68
69 if (PLoc.isInvalid()) {
70 // At least add the file name if available:
71 FileID FID = Loc.getFileID();
72 if (FID.isValid()) {
73 if (const FileEntry *FE = Loc.getFileEntry()) {
74 emitFilename(FE->getName(), Loc.getManager());
75 // FIXME(llvm-project/issues/57366): File-only locations
76 }
77 }
78 return Result;
79 }
80
81 FileID CaretFileID = Loc.getExpansionLoc().getFileID();
82
83 for (const CharSourceRange Range : Ranges) {
84 // Ignore invalid ranges.
85 if (Range.isInvalid())
86 continue;
87
88 auto &SM = Loc.getManager();
89 SourceLocation B = SM.getExpansionLoc(Range.getBegin());
90 CharSourceRange ERange = SM.getExpansionRange(Range.getEnd());
91 SourceLocation E = ERange.getEnd();
92 bool IsTokenRange = ERange.isTokenRange();
93
94 std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
95 std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
96
97 // If the start or end of the range is in another file, just discard
98 // it.
99 if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
100 continue;
101
102 // Add in the length of the token, so that we cover multi-char
103 // tokens.
104 unsigned TokSize = 0;
105 if (IsTokenRange)
107
108 FullSourceLoc BF(B, SM), EF(E, SM);
109 SourceLocation BeginLoc = SM.translateLineCol(
110 BF.getFileID(), BF.getLineNumber(), BF.getColumnNumber());
111 SourceLocation EndLoc = SM.translateLineCol(
112 EF.getFileID(), EF.getLineNumber(), EF.getColumnNumber() + TokSize);
113
114 Locations.push_back(
115 CharSourceRange{SourceRange{BeginLoc, EndLoc}, /* ITR = */ false});
116 // FIXME: Additional ranges should use presumed location in both
117 // Text and SARIF diagnostics.
118 }
119
120 auto &SM = Loc.getManager();
121 auto FID = PLoc.getFileID();
122 // Visual Studio 2010 or earlier expects column number to be off by one.
123 unsigned int ColNo = (LangOpts.MSCompatibilityVersion &&
125 ? PLoc.getColumn() - 1
126 : PLoc.getColumn();
127 SourceLocation DiagLoc = SM.translateLineCol(FID, PLoc.getLine(), ColNo);
128
129 // FIXME(llvm-project/issues/57366): Properly process #line directives.
130 Locations.push_back(
131 CharSourceRange{SourceRange{DiagLoc, DiagLoc}, /* ITR = */ false});
132
133 return Result.setLocations(Locations);
134}
135
136SarifRule
137SARIFDiagnostic::addDiagnosticLevelToRule(SarifRule Rule,
140
141 switch (Level) {
143 Config = Config.setLevel(SarifResultLevel::Note);
144 break;
146 Config = Config.setLevel(SarifResultLevel::None);
147 break;
149 Config = Config.setLevel(SarifResultLevel::Warning);
150 break;
152 Config = Config.setLevel(SarifResultLevel::Error).setRank(50);
153 break;
155 Config = Config.setLevel(SarifResultLevel::Error).setRank(100);
156 break;
158 assert(false && "Invalid diagnostic type");
159 }
160
161 return Rule.setDefaultConfiguration(Config);
162}
163
164llvm::StringRef SARIFDiagnostic::emitFilename(StringRef Filename,
165 const SourceManager &SM) {
166 if (DiagOpts->AbsolutePath) {
167 llvm::ErrorOr<const FileEntry *> File =
168 SM.getFileManager().getFile(Filename);
169 if (File) {
170 // We want to print a simplified absolute path, i. e. without "dots".
171 //
172 // The hardest part here are the paths like "<part1>/<link>/../<part2>".
173 // On Unix-like systems, we cannot just collapse "<link>/..", because
174 // paths are resolved sequentially, and, thereby, the path
175 // "<part1>/<part2>" may point to a different location. That is why
176 // we use FileManager::getCanonicalName(), which expands all indirections
177 // with llvm::sys::fs::real_path() and caches the result.
178 //
179 // On the other hand, it would be better to preserve as much of the
180 // original path as possible, because that helps a user to recognize it.
181 // real_path() expands all links, which is sometimes too much. Luckily,
182 // on Windows we can just use llvm::sys::path::remove_dots(), because,
183 // on that system, both aforementioned paths point to the same place.
184#ifdef _WIN32
185 SmallString<256> TmpFilename = (*File)->getName();
186 llvm::sys::fs::make_absolute(TmpFilename);
187 llvm::sys::path::native(TmpFilename);
188 llvm::sys::path::remove_dots(TmpFilename, /* remove_dot_dot */ true);
189 Filename = StringRef(TmpFilename.data(), TmpFilename.size());
190#else
191 Filename = SM.getFileManager().getCanonicalName(*File);
192#endif
193 }
194 }
195
196 return Filename;
197}
198
199/// Print out the file/line/column information and include trace.
200///
201/// This method handlen the emission of the diagnostic location information.
202/// This includes extracting as much location information as is present for
203/// the diagnostic and printing it, as well as any include stack or source
204/// ranges necessary.
208 assert(false && "Not implemented in SARIF mode");
209}
210
212 assert(false && "Not implemented in SARIF mode");
213}
214
216 StringRef ModuleName) {
217 assert(false && "Not implemented in SARIF mode");
218}
219
221 PresumedLoc PLoc,
222 StringRef ModuleName) {
223 assert(false && "Not implemented in SARIF mode");
224}
225} // namespace clang
#define SM(sm)
Definition: Cuda.cpp:78
Defines the clang::FileManager interface and associated types.
StringRef Filename
Definition: Format.cpp:2774
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.
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.
Class to encapsulate the logic for formatting a diagnostic message.
const LangOptions & LangOpts
IntrusiveRefCntPtr< DiagnosticOptions > DiagOpts
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine) ...
Definition: Diagnostic.h:1566
Level
The level of the diagnostic, after it has been through mapping.
Definition: Diagnostic.h:195
A SourceLocation and its associated SourceManager.
FullSourceLoc getExpansionLoc() const
FileID getFileID() const
const FileEntry * getFileEntry() const
const SourceManager & getManager() const
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:82
bool isCompatibleWithMSVC(MSVCMajorVersion MajorVersion) const
Definition: LangOptions.h:542
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:450
Represents an unpacked "presumed" location which can be presented to the user.
unsigned getColumn() const
Return the presumed column number of this location.
unsigned getLine() const
Return the presumed line number of this location.
bool isInvalid() const
Return true if this object is invalid or uninitialized.
FileID getFileID() const
void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) override
SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts, DiagnosticOptions *DiagOpts, SarifDocumentWriter *Writer)
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:380
size_t createRule(const SarifRule &Rule)
Associate the given rule with the current run.
Definition: Sarif.cpp:377
void appendResult(const SarifResult &SarifResult)
Append a new result to the currently in-flight run.
Definition: Sarif.cpp:383
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:345
static SarifResult create(uint32_t RuleIdx)
Definition: Sarif.h:333
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.
@ Result
The result type of a method or function.
llvm::PointerUnion< const Diagnostic *, const StoredDiagnostic * > DiagOrStoredDiag