brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.2 KiB · ac27d74 Raw
225 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/Frontend/SARIFDiagnostic.h"10#include "clang/Basic/CharInfo.h"11#include "clang/Basic/DiagnosticOptions.h"12#include "clang/Basic/FileManager.h"13#include "clang/Basic/Sarif.h"14#include "clang/Basic/SourceLocation.h"15#include "clang/Basic/SourceManager.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.39void SARIFDiagnostic::emitDiagnosticMessage(40    FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level,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 64SarifResult SARIFDiagnostic::addLocationToResult(65    SarifResult Result, FullSourceLoc Loc, PresumedLoc PLoc,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 locations76      }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    FileIDAndOffset BInfo = SM.getDecomposedLoc(B);95    FileIDAndOffset EInfo = SM.getDecomposedLoc(E);96 97    // If the start or end of the range is in another file, just discard98    // 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-char103    // 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 both117    // 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 &&124                        !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2012))125                           ? PLoc.getColumn() - 1126                           : 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 136SarifRule137SARIFDiagnostic::addDiagnosticLevelToRule(SarifRule Rule,138                                          DiagnosticsEngine::Level Level) {139  auto Config = SarifReportingConfiguration::create();140 141  switch (Level) {142  case DiagnosticsEngine::Note:143    Config = Config.setLevel(SarifResultLevel::Note);144    break;145  case DiagnosticsEngine::Remark:146    Config = Config.setLevel(SarifResultLevel::None);147    break;148  case DiagnosticsEngine::Warning:149    Config = Config.setLevel(SarifResultLevel::Warning);150    break;151  case DiagnosticsEngine::Error:152    Config = Config.setLevel(SarifResultLevel::Error).setRank(50);153    break;154  case DiagnosticsEngine::Fatal:155    Config = Config.setLevel(SarifResultLevel::Error).setRank(100);156    break;157  case DiagnosticsEngine::Ignored:158    assert(false && "Invalid diagnostic type");159  }160 161  return Rule.setDefaultConfiguration(Config);162}163 164llvm::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>/..", because173      // paths are resolved sequentially, and, thereby, the path174      // "<part1>/<part2>" may point to a different location. That is why175      // we use FileManager::getCanonicalName(), which expands all indirections176      // 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 the179      // 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 _WIN32184      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#else190      Filename = SM.getFileManager().getCanonicalName(*File);191#endif192    }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 for202/// the diagnostic and printing it, as well as any include stack or source203/// ranges necessary.204void SARIFDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,205                                        DiagnosticsEngine::Level Level,206                                        ArrayRef<CharSourceRange> Ranges) {207  assert(false && "Not implemented in SARIF mode");208}209 210void SARIFDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) {211  assert(false && "Not implemented in SARIF mode");212}213 214void SARIFDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,215                                         StringRef ModuleName) {216  assert(false && "Not implemented in SARIF mode");217}218 219void SARIFDiagnostic::emitBuildingModuleLocation(FullSourceLoc Loc,220                                                 PresumedLoc PLoc,221                                                 StringRef ModuleName) {222  assert(false && "Not implemented in SARIF mode");223}224} // namespace clang225