brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.2 KiB · d37597e Raw
469 lines · cpp
1//===- CIndexDiagnostic.cpp - Diagnostics C Interface ---------------------===//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// Implements the diagnostic functions of the Clang C interface.10//11//===----------------------------------------------------------------------===//12 13#include "CIndexDiagnostic.h"14#include "CIndexer.h"15#include "CXTranslationUnit.h"16#include "CXSourceLocation.h"17#include "CXString.h"18 19#include "clang/Basic/DiagnosticOptions.h"20#include "clang/Frontend/ASTUnit.h"21#include "clang/Frontend/DiagnosticRenderer.h"22#include "llvm/ADT/SmallString.h"23#include "llvm/Support/raw_ostream.h"24 25using namespace clang;26using namespace clang::cxloc;27using namespace clang::cxdiag;28using namespace llvm;29 30CXDiagnosticSetImpl::~CXDiagnosticSetImpl() {}31 32void33CXDiagnosticSetImpl::appendDiagnostic(std::unique_ptr<CXDiagnosticImpl> D) {34  Diagnostics.push_back(std::move(D));35}36 37CXDiagnosticImpl::~CXDiagnosticImpl() {}38 39namespace {40class CXDiagnosticCustomNoteImpl : public CXDiagnosticImpl {41  std::string Message;42  CXSourceLocation Loc;43public:44  CXDiagnosticCustomNoteImpl(StringRef Msg, CXSourceLocation L)45      : CXDiagnosticImpl(CustomNoteDiagnosticKind), Message(std::string(Msg)),46        Loc(L) {}47 48  ~CXDiagnosticCustomNoteImpl() override {}49 50  CXDiagnosticSeverity getSeverity() const override {51    return CXDiagnostic_Note;52  }53 54  CXSourceLocation getLocation() const override { return Loc; }55 56  CXString getSpelling() const override {57    return cxstring::createRef(Message.c_str());58  }59 60  CXString getDiagnosticOption(CXString *Disable) const override {61    if (Disable)62      *Disable = cxstring::createEmpty();63    return cxstring::createEmpty();64  }65 66  unsigned getCategory() const override { return 0; }67  CXString getCategoryText() const override { return cxstring::createEmpty(); }68 69  unsigned getNumRanges() const override { return 0; }70  CXSourceRange getRange(unsigned Range) const override {71    return clang_getNullRange();72  }73  unsigned getNumFixIts() const override { return 0; }74  CXString getFixIt(unsigned FixIt,75                    CXSourceRange *ReplacementRange) const override {76    if (ReplacementRange)77      *ReplacementRange = clang_getNullRange();78    return cxstring::createEmpty();79  }80};    81    82class CXDiagnosticRenderer : public DiagnosticNoteRenderer {83public:84  CXDiagnosticRenderer(const LangOptions &LangOpts, DiagnosticOptions &DiagOpts,85                       CXDiagnosticSetImpl *mainSet)86      : DiagnosticNoteRenderer(LangOpts, DiagOpts), CurrentSet(mainSet),87        MainSet(mainSet) {}88 89  ~CXDiagnosticRenderer() override {}90 91  void beginDiagnostic(DiagOrStoredDiag D,92                       DiagnosticsEngine::Level Level) override {93 94    const StoredDiagnostic *SD =95        dyn_cast_if_present<const StoredDiagnostic *>(D);96    if (!SD)97      return;98    99    if (Level != DiagnosticsEngine::Note)100      CurrentSet = MainSet;101 102    auto Owner = std::make_unique<CXStoredDiagnostic>(*SD, LangOpts);103    CXStoredDiagnostic &CD = *Owner;104    CurrentSet->appendDiagnostic(std::move(Owner));105 106    if (Level != DiagnosticsEngine::Note)107      CurrentSet = &CD.getChildDiagnostics();108  }109 110  void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,111                             DiagnosticsEngine::Level Level, StringRef Message,112                             ArrayRef<CharSourceRange> Ranges,113                             DiagOrStoredDiag D) override {114    if (!D.isNull())115      return;116    117    CXSourceLocation L;118    if (Loc.hasManager())119      L = translateSourceLocation(Loc.getManager(), LangOpts, Loc);120    else121      L = clang_getNullLocation();122    CurrentSet->appendDiagnostic(123        std::make_unique<CXDiagnosticCustomNoteImpl>(Message, L));124  }125 126  void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,127                         DiagnosticsEngine::Level Level,128                         ArrayRef<CharSourceRange> Ranges) override {}129 130  void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level,131                       SmallVectorImpl<CharSourceRange> &Ranges,132                       ArrayRef<FixItHint> Hints) override {}133 134  void emitNote(FullSourceLoc Loc, StringRef Message) override {135    CXSourceLocation L;136    if (Loc.hasManager())137      L = translateSourceLocation(Loc.getManager(), LangOpts, Loc);138    else139      L = clang_getNullLocation();140    CurrentSet->appendDiagnostic(141        std::make_unique<CXDiagnosticCustomNoteImpl>(Message, L));142  }143 144  CXDiagnosticSetImpl *CurrentSet;145  CXDiagnosticSetImpl *MainSet;146};  147}148 149CXDiagnosticSetImpl *cxdiag::lazyCreateDiags(CXTranslationUnit TU,150                                             bool checkIfChanged) {151  ASTUnit *AU = cxtu::getASTUnit(TU);152 153  if (TU->Diagnostics && checkIfChanged) {154    // In normal use, ASTUnit's diagnostics should not change unless we reparse.155    // Currently they can only change by using the internal testing flag156    // '-error-on-deserialized-decl' which will error during deserialization of157    // a declaration. What will happen is:158    //159    //  -c-index-test gets a CXTranslationUnit160    //  -checks the diagnostics, the diagnostics set is lazily created,161    //     no errors are reported162    //  -later does an operation, like annotation of tokens, that triggers163    //     -error-on-deserialized-decl, that will emit a diagnostic error,164    //     that ASTUnit will catch and add to its stored diagnostics vector.165    //  -c-index-test wants to check whether an error occurred after performing166    //     the operation but can only query the lazily created set.167    //168    // We check here if a new diagnostic was appended since the last time the169    // diagnostic set was created, in which case we reset it.170 171    CXDiagnosticSetImpl *172      Set = static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics);173    if (AU->stored_diag_size() != Set->getNumDiagnostics()) {174      // Diagnostics in the ASTUnit were updated, reset the associated175      // diagnostics.176      delete Set;177      TU->Diagnostics = nullptr;178    }179  }180 181  if (!TU->Diagnostics) {182    CXDiagnosticSetImpl *Set = new CXDiagnosticSetImpl();183    TU->Diagnostics = Set;184    DiagnosticOptions DOpts;185    CXDiagnosticRenderer Renderer(AU->getASTContext().getLangOpts(), DOpts,186                                  Set);187 188    for (ASTUnit::stored_diag_iterator it = AU->stored_diag_begin(),189         ei = AU->stored_diag_end(); it != ei; ++it) {190      Renderer.emitStoredDiagnostic(*it);191    }192  }193  return static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics);194}195 196//-----------------------------------------------------------------------------197// C Interface Routines198//-----------------------------------------------------------------------------199unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) {200  if (cxtu::isNotUsableTU(Unit)) {201    LOG_BAD_TU(Unit);202    return 0;203  }204  if (!cxtu::getASTUnit(Unit))205    return 0;206  return lazyCreateDiags(Unit, /*checkIfChanged=*/true)->getNumDiagnostics();207}208 209CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) {210  if (cxtu::isNotUsableTU(Unit)) {211    LOG_BAD_TU(Unit);212    return nullptr;213  }214 215  CXDiagnosticSet D = clang_getDiagnosticSetFromTU(Unit);216  if (!D)217    return nullptr;218 219  CXDiagnosticSetImpl *Diags = static_cast<CXDiagnosticSetImpl*>(D);220  if (Index >= Diags->getNumDiagnostics())221    return nullptr;222 223  return Diags->getDiagnostic(Index);224}225 226CXDiagnosticSet clang_getDiagnosticSetFromTU(CXTranslationUnit Unit) {227  if (cxtu::isNotUsableTU(Unit)) {228    LOG_BAD_TU(Unit);229    return nullptr;230  }231  if (!cxtu::getASTUnit(Unit))232    return nullptr;233  return static_cast<CXDiagnostic>(lazyCreateDiags(Unit));234}235 236void clang_disposeDiagnostic(CXDiagnostic Diagnostic) {237  // No-op.  Kept as a legacy API.  CXDiagnostics are now managed238  // by the enclosing CXDiagnosticSet.239}240 241CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {242  if (!Diagnostic)243    return cxstring::createEmpty();244 245  CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic);246 247  SmallString<256> Str;248  llvm::raw_svector_ostream Out(Str);249  250  if (Options & CXDiagnostic_DisplaySourceLocation) {251    // Print source location (file:line), along with optional column252    // and source ranges.253    CXFile File;254    unsigned Line, Column;255    clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic),256                              &File, &Line, &Column, nullptr);257    if (File) {258      CXString FName = clang_getFileName(File);259      Out << clang_getCString(FName) << ":" << Line << ":";260      clang_disposeString(FName);261      if (Options & CXDiagnostic_DisplayColumn)262        Out << Column << ":";263 264      if (Options & CXDiagnostic_DisplaySourceRanges) {265        unsigned N = clang_getDiagnosticNumRanges(Diagnostic);266        bool PrintedRange = false;267        for (unsigned I = 0; I != N; ++I) {268          CXFile StartFile, EndFile;269          CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I);270          271          unsigned StartLine, StartColumn, EndLine, EndColumn;272          clang_getSpellingLocation(clang_getRangeStart(Range),273                                    &StartFile, &StartLine, &StartColumn,274                                    nullptr);275          clang_getSpellingLocation(clang_getRangeEnd(Range),276                                    &EndFile, &EndLine, &EndColumn, nullptr);277 278          if (StartFile != EndFile || StartFile != File)279            continue;280          281          Out << "{" << StartLine << ":" << StartColumn << "-"282              << EndLine << ":" << EndColumn << "}";283          PrintedRange = true;284        }285        if (PrintedRange)286          Out << ":";287      }288      289      Out << " ";290    }291  }292 293  /* Print warning/error/etc. */294  switch (Severity) {295  case CXDiagnostic_Ignored: llvm_unreachable("impossible");296  case CXDiagnostic_Note: Out << "note: "; break;297  case CXDiagnostic_Warning: Out << "warning: "; break;298  case CXDiagnostic_Error: Out << "error: "; break;299  case CXDiagnostic_Fatal: Out << "fatal error: "; break;300  }301 302  CXString Text = clang_getDiagnosticSpelling(Diagnostic);303  if (clang_getCString(Text))304    Out << clang_getCString(Text);305  else306    Out << "<no diagnostic text>";307  clang_disposeString(Text);308  309  if (Options & (CXDiagnostic_DisplayOption | CXDiagnostic_DisplayCategoryId |310                 CXDiagnostic_DisplayCategoryName)) {311    bool NeedBracket = true;312    bool NeedComma = false;313 314    if (Options & CXDiagnostic_DisplayOption) {315      CXString OptionName = clang_getDiagnosticOption(Diagnostic, nullptr);316      if (const char *OptionText = clang_getCString(OptionName)) {317        if (OptionText[0]) {318          Out << " [" << OptionText;319          NeedBracket = false;320          NeedComma = true;321        }322      }323      clang_disposeString(OptionName);324    }325    326    if (Options & (CXDiagnostic_DisplayCategoryId | 327                   CXDiagnostic_DisplayCategoryName)) {328      if (unsigned CategoryID = clang_getDiagnosticCategory(Diagnostic)) {329        if (Options & CXDiagnostic_DisplayCategoryId) {330          if (NeedBracket)331            Out << " [";332          if (NeedComma)333            Out << ", ";334          Out << CategoryID;335          NeedBracket = false;336          NeedComma = true;337        }338        339        if (Options & CXDiagnostic_DisplayCategoryName) {340          CXString CategoryName = clang_getDiagnosticCategoryText(Diagnostic);341          if (NeedBracket)342            Out << " [";343          if (NeedComma)344            Out << ", ";345          Out << clang_getCString(CategoryName);346          NeedBracket = false;347          NeedComma = true;348          clang_disposeString(CategoryName);349        }350      }351    }352 353    (void) NeedComma; // Silence dead store warning.354    if (!NeedBracket)355      Out << "]";356  }357  358  return cxstring::createDup(Out.str());359}360 361unsigned clang_defaultDiagnosticDisplayOptions() {362  return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn |363         CXDiagnostic_DisplayOption;364}365 366enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) {367  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag))368    return D->getSeverity();369  return CXDiagnostic_Ignored;370}371 372CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) {373  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag))374    return D->getLocation();375  return clang_getNullLocation();376}377 378CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) {379  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))380    return D->getSpelling();381  return cxstring::createEmpty();382}383 384CXString clang_getDiagnosticOption(CXDiagnostic Diag, CXString *Disable) {385  if (Disable)386    *Disable = cxstring::createEmpty();387 388  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))389    return D->getDiagnosticOption(Disable);390 391  return cxstring::createEmpty();392}393 394unsigned clang_getDiagnosticCategory(CXDiagnostic Diag) {395  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))396    return D->getCategory();397  return 0;398}399  400CXString clang_getDiagnosticCategoryName(unsigned Category) {401  // Kept for backward compatibility.402  return cxstring::createRef(DiagnosticIDs::getCategoryNameFromID(Category));403}404  405CXString clang_getDiagnosticCategoryText(CXDiagnostic Diag) {406  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))407    return D->getCategoryText();408  return cxstring::createEmpty();409}410  411unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) {412  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))413    return D->getNumRanges();414  return 0;415}416 417CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) {418  CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag);  419  if (!D || Range >= D->getNumRanges())420    return clang_getNullRange();421  return D->getRange(Range);422}423 424unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) {425  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))426    return D->getNumFixIts();427  return 0;428}429 430CXString clang_getDiagnosticFixIt(CXDiagnostic Diag, unsigned FixIt,431                                  CXSourceRange *ReplacementRange) {432  CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag);433  if (!D || FixIt >= D->getNumFixIts()) {434    if (ReplacementRange)435      *ReplacementRange = clang_getNullRange();436    return cxstring::createEmpty();437  }438  return D->getFixIt(FixIt, ReplacementRange);439}440 441void clang_disposeDiagnosticSet(CXDiagnosticSet Diags) {442  if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl *>(Diags)) {443    if (D->isExternallyManaged())444      delete D;445  }446}447  448CXDiagnostic clang_getDiagnosticInSet(CXDiagnosticSet Diags,449                                      unsigned Index) {450  if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags))451    if (Index < D->getNumDiagnostics())452      return D->getDiagnostic(Index);453  return nullptr;454}455  456CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic Diag) {457  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) {458    CXDiagnosticSetImpl &ChildDiags = D->getChildDiagnostics();459    return ChildDiags.empty() ? nullptr : (CXDiagnosticSet) &ChildDiags;460  }461  return nullptr;462}463 464unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags) {465  if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags))466    return D->getNumDiagnostics();467  return 0;468}469