Path: blob/main/contrib/llvm-project/clang/lib/Frontend/SARIFDiagnostic.cpp
35233 views
//===--------- SARIFDiagnostic.cpp - SARIF Diagnostic Formatting ----------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "clang/Frontend/SARIFDiagnostic.h"9#include "clang/Basic/CharInfo.h"10#include "clang/Basic/DiagnosticOptions.h"11#include "clang/Basic/FileManager.h"12#include "clang/Basic/Sarif.h"13#include "clang/Basic/SourceLocation.h"14#include "clang/Basic/SourceManager.h"15#include "clang/Lex/Lexer.h"16#include "llvm/ADT/ArrayRef.h"17#include "llvm/ADT/SmallString.h"18#include "llvm/ADT/StringExtras.h"19#include "llvm/ADT/StringRef.h"20#include "llvm/Support/Casting.h"21#include "llvm/Support/ConvertUTF.h"22#include "llvm/Support/ErrorHandling.h"23#include "llvm/Support/ErrorOr.h"24#include "llvm/Support/Locale.h"25#include "llvm/Support/Path.h"26#include "llvm/Support/raw_ostream.h"27#include <algorithm>28#include <string>2930namespace clang {3132SARIFDiagnostic::SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,33DiagnosticOptions *DiagOpts,34SarifDocumentWriter *Writer)35: DiagnosticRenderer(LangOpts, DiagOpts), Writer(Writer) {}3637// FIXME(llvm-project/issues/57323): Refactor Diagnostic classes.38void SARIFDiagnostic::emitDiagnosticMessage(39FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level,40StringRef Message, ArrayRef<clang::CharSourceRange> Ranges,41DiagOrStoredDiag D) {4243const auto *Diag = D.dyn_cast<const Diagnostic *>();4445if (!Diag)46return;4748SarifRule Rule = SarifRule::create().setRuleId(std::to_string(Diag->getID()));4950Rule = addDiagnosticLevelToRule(Rule, Level);5152unsigned RuleIdx = Writer->createRule(Rule);5354SarifResult Result =55SarifResult::create(RuleIdx).setDiagnosticMessage(Message);5657if (Loc.isValid())58Result = addLocationToResult(Result, Loc, PLoc, Ranges, *Diag);5960Writer->appendResult(Result);61}6263SarifResult SARIFDiagnostic::addLocationToResult(64SarifResult Result, FullSourceLoc Loc, PresumedLoc PLoc,65ArrayRef<CharSourceRange> Ranges, const Diagnostic &Diag) {66SmallVector<CharSourceRange> Locations = {};6768if (PLoc.isInvalid()) {69// At least add the file name if available:70FileID FID = Loc.getFileID();71if (FID.isValid()) {72if (OptionalFileEntryRef FE = Loc.getFileEntryRef()) {73emitFilename(FE->getName(), Loc.getManager());74// FIXME(llvm-project/issues/57366): File-only locations75}76}77return Result;78}7980FileID CaretFileID = Loc.getExpansionLoc().getFileID();8182for (const CharSourceRange Range : Ranges) {83// Ignore invalid ranges.84if (Range.isInvalid())85continue;8687auto &SM = Loc.getManager();88SourceLocation B = SM.getExpansionLoc(Range.getBegin());89CharSourceRange ERange = SM.getExpansionRange(Range.getEnd());90SourceLocation E = ERange.getEnd();91bool IsTokenRange = ERange.isTokenRange();9293std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);94std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);9596// If the start or end of the range is in another file, just discard97// it.98if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)99continue;100101// Add in the length of the token, so that we cover multi-char102// tokens.103unsigned TokSize = 0;104if (IsTokenRange)105TokSize = Lexer::MeasureTokenLength(E, SM, LangOpts);106107FullSourceLoc BF(B, SM), EF(E, SM);108SourceLocation BeginLoc = SM.translateLineCol(109BF.getFileID(), BF.getLineNumber(), BF.getColumnNumber());110SourceLocation EndLoc = SM.translateLineCol(111EF.getFileID(), EF.getLineNumber(), EF.getColumnNumber() + TokSize);112113Locations.push_back(114CharSourceRange{SourceRange{BeginLoc, EndLoc}, /* ITR = */ false});115// FIXME: Additional ranges should use presumed location in both116// Text and SARIF diagnostics.117}118119auto &SM = Loc.getManager();120auto FID = PLoc.getFileID();121// Visual Studio 2010 or earlier expects column number to be off by one.122unsigned int ColNo = (LangOpts.MSCompatibilityVersion &&123!LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2012))124? PLoc.getColumn() - 1125: PLoc.getColumn();126SourceLocation DiagLoc = SM.translateLineCol(FID, PLoc.getLine(), ColNo);127128// FIXME(llvm-project/issues/57366): Properly process #line directives.129Locations.push_back(130CharSourceRange{SourceRange{DiagLoc, DiagLoc}, /* ITR = */ false});131132return Result.setLocations(Locations);133}134135SarifRule136SARIFDiagnostic::addDiagnosticLevelToRule(SarifRule Rule,137DiagnosticsEngine::Level Level) {138auto Config = SarifReportingConfiguration::create();139140switch (Level) {141case DiagnosticsEngine::Note:142Config = Config.setLevel(SarifResultLevel::Note);143break;144case DiagnosticsEngine::Remark:145Config = Config.setLevel(SarifResultLevel::None);146break;147case DiagnosticsEngine::Warning:148Config = Config.setLevel(SarifResultLevel::Warning);149break;150case DiagnosticsEngine::Error:151Config = Config.setLevel(SarifResultLevel::Error).setRank(50);152break;153case DiagnosticsEngine::Fatal:154Config = Config.setLevel(SarifResultLevel::Error).setRank(100);155break;156case DiagnosticsEngine::Ignored:157assert(false && "Invalid diagnostic type");158}159160return Rule.setDefaultConfiguration(Config);161}162163llvm::StringRef SARIFDiagnostic::emitFilename(StringRef Filename,164const SourceManager &SM) {165if (DiagOpts->AbsolutePath) {166auto File = SM.getFileManager().getOptionalFileRef(Filename);167if (File) {168// We want to print a simplified absolute path, i. e. without "dots".169//170// The hardest part here are the paths like "<part1>/<link>/../<part2>".171// On Unix-like systems, we cannot just collapse "<link>/..", because172// paths are resolved sequentially, and, thereby, the path173// "<part1>/<part2>" may point to a different location. That is why174// we use FileManager::getCanonicalName(), which expands all indirections175// with llvm::sys::fs::real_path() and caches the result.176//177// On the other hand, it would be better to preserve as much of the178// original path as possible, because that helps a user to recognize it.179// real_path() expands all links, which is sometimes too much. Luckily,180// on Windows we can just use llvm::sys::path::remove_dots(), because,181// on that system, both aforementioned paths point to the same place.182#ifdef _WIN32183SmallString<256> TmpFilename = File->getName();184llvm::sys::fs::make_absolute(TmpFilename);185llvm::sys::path::native(TmpFilename);186llvm::sys::path::remove_dots(TmpFilename, /* remove_dot_dot */ true);187Filename = StringRef(TmpFilename.data(), TmpFilename.size());188#else189Filename = SM.getFileManager().getCanonicalName(*File);190#endif191}192}193194return Filename;195}196197/// Print out the file/line/column information and include trace.198///199/// This method handlen the emission of the diagnostic location information.200/// This includes extracting as much location information as is present for201/// the diagnostic and printing it, as well as any include stack or source202/// ranges necessary.203void SARIFDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,204DiagnosticsEngine::Level Level,205ArrayRef<CharSourceRange> Ranges) {206assert(false && "Not implemented in SARIF mode");207}208209void SARIFDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) {210assert(false && "Not implemented in SARIF mode");211}212213void SARIFDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,214StringRef ModuleName) {215assert(false && "Not implemented in SARIF mode");216}217218void SARIFDiagnostic::emitBuildingModuleLocation(FullSourceLoc Loc,219PresumedLoc PLoc,220StringRef ModuleName) {221assert(false && "Not implemented in SARIF mode");222}223} // namespace clang224225226