aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/Frontend/SARIFDiagnostic.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/Frontend/SARIFDiagnostic.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/Frontend/SARIFDiagnostic.cpp224
1 files changed, 224 insertions, 0 deletions
diff --git a/contrib/llvm-project/clang/lib/Frontend/SARIFDiagnostic.cpp b/contrib/llvm-project/clang/lib/Frontend/SARIFDiagnostic.cpp
new file mode 100644
index 000000000000..4e36153ed539
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Frontend/SARIFDiagnostic.cpp
@@ -0,0 +1,224 @@
+//===--------- SARIFDiagnostic.cpp - SARIF Diagnostic Formatting ----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/SARIFDiagnostic.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/Sarif.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/Locale.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <string>
+
+namespace clang {
+
+SARIFDiagnostic::SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
+ DiagnosticOptions *DiagOpts,
+ SarifDocumentWriter *Writer)
+ : DiagnosticRenderer(LangOpts, DiagOpts), Writer(Writer) {}
+
+// FIXME(llvm-project/issues/57323): Refactor Diagnostic classes.
+void SARIFDiagnostic::emitDiagnosticMessage(
+ FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level,
+ StringRef Message, ArrayRef<clang::CharSourceRange> Ranges,
+ DiagOrStoredDiag D) {
+
+ const auto *Diag = D.dyn_cast<const Diagnostic *>();
+
+ if (!Diag)
+ return;
+
+ SarifRule Rule = SarifRule::create().setRuleId(std::to_string(Diag->getID()));
+
+ Rule = addDiagnosticLevelToRule(Rule, Level);
+
+ unsigned RuleIdx = Writer->createRule(Rule);
+
+ SarifResult Result =
+ SarifResult::create(RuleIdx).setDiagnosticMessage(Message);
+
+ if (Loc.isValid())
+ Result = addLocationToResult(Result, Loc, PLoc, Ranges, *Diag);
+
+ Writer->appendResult(Result);
+}
+
+SarifResult SARIFDiagnostic::addLocationToResult(
+ SarifResult Result, FullSourceLoc Loc, PresumedLoc PLoc,
+ ArrayRef<CharSourceRange> Ranges, const Diagnostic &Diag) {
+ SmallVector<CharSourceRange> Locations = {};
+
+ if (PLoc.isInvalid()) {
+ // At least add the file name if available:
+ FileID FID = Loc.getFileID();
+ if (FID.isValid()) {
+ if (OptionalFileEntryRef FE = Loc.getFileEntryRef()) {
+ emitFilename(FE->getName(), Loc.getManager());
+ // FIXME(llvm-project/issues/57366): File-only locations
+ }
+ }
+ return Result;
+ }
+
+ FileID CaretFileID = Loc.getExpansionLoc().getFileID();
+
+ for (const CharSourceRange Range : Ranges) {
+ // Ignore invalid ranges.
+ if (Range.isInvalid())
+ continue;
+
+ auto &SM = Loc.getManager();
+ SourceLocation B = SM.getExpansionLoc(Range.getBegin());
+ CharSourceRange ERange = SM.getExpansionRange(Range.getEnd());
+ SourceLocation E = ERange.getEnd();
+ bool IsTokenRange = ERange.isTokenRange();
+
+ std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
+ std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
+
+ // If the start or end of the range is in another file, just discard
+ // it.
+ if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
+ continue;
+
+ // Add in the length of the token, so that we cover multi-char
+ // tokens.
+ unsigned TokSize = 0;
+ if (IsTokenRange)
+ TokSize = Lexer::MeasureTokenLength(E, SM, LangOpts);
+
+ FullSourceLoc BF(B, SM), EF(E, SM);
+ SourceLocation BeginLoc = SM.translateLineCol(
+ BF.getFileID(), BF.getLineNumber(), BF.getColumnNumber());
+ SourceLocation EndLoc = SM.translateLineCol(
+ EF.getFileID(), EF.getLineNumber(), EF.getColumnNumber() + TokSize);
+
+ Locations.push_back(
+ CharSourceRange{SourceRange{BeginLoc, EndLoc}, /* ITR = */ false});
+ // FIXME: Additional ranges should use presumed location in both
+ // Text and SARIF diagnostics.
+ }
+
+ auto &SM = Loc.getManager();
+ auto FID = PLoc.getFileID();
+ // Visual Studio 2010 or earlier expects column number to be off by one.
+ unsigned int ColNo = (LangOpts.MSCompatibilityVersion &&
+ !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2012))
+ ? PLoc.getColumn() - 1
+ : PLoc.getColumn();
+ SourceLocation DiagLoc = SM.translateLineCol(FID, PLoc.getLine(), ColNo);
+
+ // FIXME(llvm-project/issues/57366): Properly process #line directives.
+ Locations.push_back(
+ CharSourceRange{SourceRange{DiagLoc, DiagLoc}, /* ITR = */ false});
+
+ return Result.setLocations(Locations);
+}
+
+SarifRule
+SARIFDiagnostic::addDiagnosticLevelToRule(SarifRule Rule,
+ DiagnosticsEngine::Level Level) {
+ auto Config = SarifReportingConfiguration::create();
+
+ switch (Level) {
+ case DiagnosticsEngine::Note:
+ Config = Config.setLevel(SarifResultLevel::Note);
+ break;
+ case DiagnosticsEngine::Remark:
+ Config = Config.setLevel(SarifResultLevel::None);
+ break;
+ case DiagnosticsEngine::Warning:
+ Config = Config.setLevel(SarifResultLevel::Warning);
+ break;
+ case DiagnosticsEngine::Error:
+ Config = Config.setLevel(SarifResultLevel::Error).setRank(50);
+ break;
+ case DiagnosticsEngine::Fatal:
+ Config = Config.setLevel(SarifResultLevel::Error).setRank(100);
+ break;
+ case DiagnosticsEngine::Ignored:
+ assert(false && "Invalid diagnostic type");
+ }
+
+ return Rule.setDefaultConfiguration(Config);
+}
+
+llvm::StringRef SARIFDiagnostic::emitFilename(StringRef Filename,
+ const SourceManager &SM) {
+ if (DiagOpts->AbsolutePath) {
+ auto File = SM.getFileManager().getOptionalFileRef(Filename);
+ if (File) {
+ // We want to print a simplified absolute path, i. e. without "dots".
+ //
+ // The hardest part here are the paths like "<part1>/<link>/../<part2>".
+ // On Unix-like systems, we cannot just collapse "<link>/..", because
+ // paths are resolved sequentially, and, thereby, the path
+ // "<part1>/<part2>" may point to a different location. That is why
+ // we use FileManager::getCanonicalName(), which expands all indirections
+ // with llvm::sys::fs::real_path() and caches the result.
+ //
+ // On the other hand, it would be better to preserve as much of the
+ // original path as possible, because that helps a user to recognize it.
+ // real_path() expands all links, which is sometimes too much. Luckily,
+ // on Windows we can just use llvm::sys::path::remove_dots(), because,
+ // on that system, both aforementioned paths point to the same place.
+#ifdef _WIN32
+ SmallString<256> TmpFilename = File->getName();
+ llvm::sys::fs::make_absolute(TmpFilename);
+ llvm::sys::path::native(TmpFilename);
+ llvm::sys::path::remove_dots(TmpFilename, /* remove_dot_dot */ true);
+ Filename = StringRef(TmpFilename.data(), TmpFilename.size());
+#else
+ Filename = SM.getFileManager().getCanonicalName(*File);
+#endif
+ }
+ }
+
+ return Filename;
+}
+
+/// Print out the file/line/column information and include trace.
+///
+/// This method handlen the emission of the diagnostic location information.
+/// This includes extracting as much location information as is present for
+/// the diagnostic and printing it, as well as any include stack or source
+/// ranges necessary.
+void SARIFDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges) {
+ assert(false && "Not implemented in SARIF mode");
+}
+
+void SARIFDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) {
+ assert(false && "Not implemented in SARIF mode");
+}
+
+void SARIFDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
+ StringRef ModuleName) {
+ assert(false && "Not implemented in SARIF mode");
+}
+
+void SARIFDiagnostic::emitBuildingModuleLocation(FullSourceLoc Loc,
+ PresumedLoc PLoc,
+ StringRef ModuleName) {
+ assert(false && "Not implemented in SARIF mode");
+}
+} // namespace clang