clang  16.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 
10 #include "clang/Basic/CharInfo.h"
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 
31 namespace clang {
32 
33 SARIFDiagnostic::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,
42  DiagOrStoredDiag D) {
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 
55  SarifResult Result =
56  SarifResult::create(RuleIdx).setDiagnosticMessage(Message);
57 
58  if (Loc.isValid())
59  Result = addLocationToResult(Result, Loc, PLoc, Ranges, *Diag);
60 
61  Writer->appendResult(Result);
62 }
63 
64 SarifResult SARIFDiagnostic::addLocationToResult(
65  SarifResult Result, FullSourceLoc Loc, PresumedLoc PLoc,
66  ArrayRef<CharSourceRange> Ranges, const Diagnostic &Diag) {
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)
106  TokSize = Lexer::MeasureTokenLength(E, SM, LangOpts);
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 
136 SarifRule
137 SARIFDiagnostic::addDiagnosticLevelToRule(SarifRule Rule,
139  auto Config = SarifReportingConfiguration::create();
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 
164 llvm::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.
207  ArrayRef<CharSourceRange> Ranges) {
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
clang::DiagnosticsEngine::Level
Level
The level of the diagnostic, after it has been through mapping.
Definition: Diagnostic.h:195
clang::FullSourceLoc::getManager
const SourceManager & getManager() const
Definition: SourceLocation.h:382
clang::SarifResultLevel::Warning
@ Warning
clang::FullSourceLoc::getFileEntry
const FileEntry * getFileEntry() const
Definition: SourceLocation.cpp:225
clang::FullSourceLoc
A SourceLocation and its associated SourceManager.
Definition: SourceLocation.h:368
clang::DeclaratorContext::File
@ File
clang::PresumedLoc::getLine
unsigned getLine() const
Return the presumed line number of this location.
Definition: SourceLocation.h:337
Diag
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.
Definition: LiteralSupport.cpp:79
llvm::SmallVector
Definition: LLVM.h:38
Filename
StringRef Filename
Definition: Format.cpp:2715
clang::SarifResult::create
static SarifResult create(uint32_t RuleIdx)
Definition: Sarif.h:333
clang::DiagOrStoredDiag
llvm::PointerUnion< const Diagnostic *, const StoredDiagnostic * > DiagOrStoredDiag
Definition: DiagnosticRenderer.h:33
SourceManager.h
clang::DiagnosticRenderer
Class to encapsulate the logic for formatting a diagnostic message.
Definition: DiagnosticRenderer.h:47
clang::SarifResultLevel::Error
@ Error
clang::Lexer::MeasureTokenLength
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:451
clang::SARIFDiagnostic::emitIncludeLocation
void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) override
Definition: SARIFDiagnostic.cpp:211
SARIFDiagnostic.h
clang::Diagnostic
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine) ...
Definition: Diagnostic.h:1561
clang::LangOptions::isCompatibleWithMSVC
bool isCompatibleWithMSVC(MSVCMajorVersion MajorVersion) const
Definition: LangOptions.h:539
clang::PresumedLoc::getFileID
FileID getFileID() const
Definition: SourceLocation.h:329
clang::DiagnosticRenderer::LangOpts
const LangOptions & LangOpts
Definition: DiagnosticRenderer.h:49
clang::SarifResultLevel::None
@ None
clang::SARIFDiagnostic::emitBuildingModuleLocation
void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName) override
Definition: SARIFDiagnostic.cpp:220
clang::SarifDocumentWriter::createRule
size_t createRule(const SarifRule &Rule)
Associate the given rule with the current run.
Definition: Sarif.cpp:376
clang::SarifResult
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
clang::DiagnosticsEngine::Remark
@ Remark
Definition: Diagnostic.h:198
clang::SarifRule::create
static SarifRule create()
Definition: Sarif.h:269
clang::DiagnosticsEngine::Error
@ Error
Definition: Diagnostic.h:200
clang::SarifReportingConfiguration::create
static SarifReportingConfiguration create()
Definition: Sarif.h:221
clang::PresumedLoc::getColumn
unsigned getColumn() const
Return the presumed column number of this location.
Definition: SourceLocation.h:345
clang::DiagnosticRenderer::DiagOpts
IntrusiveRefCntPtr< DiagnosticOptions > DiagOpts
Definition: DiagnosticRenderer.h:50
clang::SarifRule
A SARIF rule (reportingDescriptor object) contains information that describes a reporting item genera...
Definition: Sarif.h:257
clang::transformer::EditKind::Range
@ Range
clang::PresumedLoc::isInvalid
bool isInvalid() const
Return true if this object is invalid or uninitialized.
Definition: SourceLocation.h:318
SourceLocation.h
clang::SARIFDiagnostic::emitImportLocation
void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName) override
Definition: SARIFDiagnostic.cpp:215
clang::SARIFDiagnostic::emitDiagnosticMessage
void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, StringRef Message, ArrayRef< CharSourceRange > Ranges, DiagOrStoredDiag D) override
Definition: SARIFDiagnostic.cpp:39
CharInfo.h
clang::FullSourceLoc::getExpansionLoc
FullSourceLoc getExpansionLoc() const
Definition: SourceLocation.cpp:164
clang::SARIFDiagnostic::emitDiagnosticLoc
void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, ArrayRef< CharSourceRange > Ranges) override
Print out the file/line/column information and include trace.
Definition: SARIFDiagnostic.cpp:205
clang::DiagnosticsEngine::Ignored
@ Ignored
Definition: Diagnostic.h:196
llvm::ArrayRef
Definition: LLVM.h:34
Lexer.h
clang::SarifRule::setRuleId
SarifRule setRuleId(llvm::StringRef RuleId)
Definition: Sarif.h:276
clang::SarifResult::setDiagnosticMessage
SarifResult setDiagnosticMessage(llvm::StringRef Message)
Definition: Sarif.h:345
clang::FullSourceLoc::getFileID
FileID getFileID() const
Definition: SourceLocation.cpp:159
clang::LangOptions
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:81
clang::SarifResultLevel::Note
@ Note
clang::SarifDocumentWriter
This class handles creating a valid SARIF document given various input attributes.
Definition: Sarif.h:380
clang
Definition: CalledOnceCheck.h:17
clang::SARIFDiagnostic::SARIFDiagnostic
SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts, DiagnosticOptions *DiagOpts, SarifDocumentWriter *Writer)
Definition: SARIFDiagnostic.cpp:33
clang::prec::Level
Level
Definition: OperatorPrecedence.h:26
Sarif.h
clang::SourceLocation::isValid
bool isValid() const
Return true if this is a valid SourceLocation object.
Definition: SourceLocation.h:110
DiagnosticOptions.h
clang::SarifDocumentWriter::appendResult
void appendResult(const SarifResult &SarifResult)
Append a new result to the currently in-flight run.
Definition: Sarif.cpp:382
clang::DiagnosticsEngine::Fatal
@ Fatal
Definition: Diagnostic.h:201
clang::DiagnosticsEngine::Note
@ Note
Definition: Diagnostic.h:197
clang::PresumedLoc
Represents an unpacked "presumed" location which can be presented to the user.
Definition: SourceLocation.h:302
FileManager.h
SM
#define SM(sm)
Definition: Cuda.cpp:79
clang::DiagnosticsEngine::Warning
@ Warning
Definition: Diagnostic.h:199
clang::DiagnosticOptions
Options for controlling the compiler diagnostics engine.
Definition: DiagnosticOptions.h:70
clang::LangOptions::MSVC2012
@ MSVC2012
Definition: LangOptions.h:143