clang 20.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 (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)
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;