123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- //===--------- 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 (const FileEntry *FE = Loc.getFileEntry()) {
- 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) {
- llvm::ErrorOr<const FileEntry *> File =
- SM.getFileManager().getFile(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
|