clang 19.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()) {
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 auto File = SM.getFileManager().getOptionalFileRef(Filename);
168 if (File) {
169 // We want to print a simplified absolute path, i. e. without "dots".
170 //
171 // The hardest part here are the paths like "<part1>/<link>/../<part2>".
172 // On Unix-like systems, we cannot just collapse "<link>/..", because
173 // paths are resolved sequentially, and, thereby, the path
174 // "<part1>/<part2>" may point to a different location. That is why
175 // we use FileManager::getCanonicalName(), which expands all indirections
176 // with llvm::sys::fs::real_path() and caches the result.
177 //
178 // On the other hand, it would be better to preserve as much of the
179 // original path as possible, because that helps a user to recognize it.
180 // real_path() expands all links, which is sometimes too much. Luckily,
181 // on Windows we can just use llvm::sys::path::remove_dots(), because,
182 // on that system, both aforementioned paths point to the same place.
183#ifdef _WIN32
184 SmallString<256> TmpFilename = File->getName();
185 llvm::sys::fs::make_absolute(TmpFilename);
186 llvm::sys::path::native(TmpFilename);
187 llvm::sys::path::remove_dots(TmpFilename, /* remove_dot_dot */ true);
188 Filename = StringRef(TmpFilename.data(), TmpFilename.size());
189#else
190 Filename = SM.getFileManager().getCanonicalName(*File);
191#endif
192 }
193 }
194
195 return Filename;
196}
197
198/// Print out the file/line/column information and include trace.
199///
200/// This method handlen the emission of the diagnostic location information.
201/// This includes extracting as much location information as is present for
202/// the diagnostic and printing it, as well as any include stack or source
203/// ranges necessary.
207 assert(false && "Not implemented in SARIF mode");
208}
209
211 assert(false && "Not implemented in SARIF mode");
212}
213
215 StringRef ModuleName) {
216 assert(false && "Not implemented in SARIF mode");
217}
218
220 PresumedLoc PLoc,
221 StringRef ModuleName) {
222 assert(false && "Not implemented in SARIF mode");
223}
224} // namespace clang
#define SM(sm)
Definition: Cuda.cpp:82
Defines the clang::FileManager interface and associated types.
StringRef Filename
Definition: Format.cpp:2975
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:1571
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
OptionalFileEntryRef getFileEntryRef() 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:461
bool isCompatibleWithMSVC(MSVCMajorVersion MajorVersion) const
Definition: LangOptions.h:625
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:499
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:379
void appendResult(const SarifResult &SarifResult)
Append a new result to the currently in-flight run.
Definition: Sarif.cpp:385
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.
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
llvm::PointerUnion< const Diagnostic *, const StoredDiagnostic * > DiagOrStoredDiag
CustomizableOptional< FileEntryRef > OptionalFileEntryRef
Definition: FileEntry.h:202