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 
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(
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 (OptionalFileEntryRef FE = Loc.getFileEntryRef()) {
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  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.
206  ArrayRef<CharSourceRange> Ranges) {
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:83
Defines the clang::FileManager interface and associated types.
StringRef Filename
Definition: Format.cpp:2976
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.
SourceRange Range
Definition: SemaObjC.cpp:754
SourceLocation Loc
Definition: SemaObjC.cpp:755
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:1577
Level
The level of the diagnostic, after it has been through mapping.
Definition: Diagnostic.h:196
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...
Definition: LangOptions.h:482
bool isCompatibleWithMSVC(MSVCMajorVersion MajorVersion) const
Definition: LangOptions.h:666
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
The JSON file list parser is used to communicate input to InstallAPI.
llvm::PointerUnion< const Diagnostic *, const StoredDiagnostic * > DiagOrStoredDiag
CustomizableOptional< FileEntryRef > OptionalFileEntryRef
Definition: FileEntry.h:202