123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- PartialDiagnostic.h - Diagnostic "closures" --------------*- C++ -*-===//
- //
- // 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
- //
- //===----------------------------------------------------------------------===//
- //
- /// \file
- /// Implements a partial diagnostic that can be emitted anwyhere
- /// in a DiagnosticBuilder stream.
- //
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_CLANG_BASIC_PARTIALDIAGNOSTIC_H
- #define LLVM_CLANG_BASIC_PARTIALDIAGNOSTIC_H
- #include "clang/Basic/Diagnostic.h"
- #include "clang/Basic/LLVM.h"
- #include "clang/Basic/SourceLocation.h"
- #include "llvm/ADT/SmallVector.h"
- #include "llvm/ADT/StringRef.h"
- #include <cassert>
- #include <cstdint>
- #include <string>
- #include <type_traits>
- #include <utility>
- namespace clang {
- class PartialDiagnostic : public StreamingDiagnostic {
- private:
- // NOTE: Sema assumes that PartialDiagnostic is location-invariant
- // in the sense that its bits can be safely memcpy'ed and destructed
- // in the new location.
- /// The diagnostic ID.
- mutable unsigned DiagID = 0;
- public:
- struct NullDiagnostic {};
- /// Create a null partial diagnostic, which cannot carry a payload,
- /// and only exists to be swapped with a real partial diagnostic.
- PartialDiagnostic(NullDiagnostic) {}
- PartialDiagnostic(unsigned DiagID, DiagStorageAllocator &Allocator_)
- : StreamingDiagnostic(Allocator_), DiagID(DiagID) {}
- PartialDiagnostic(const PartialDiagnostic &Other)
- : StreamingDiagnostic(), DiagID(Other.DiagID) {
- Allocator = Other.Allocator;
- if (Other.DiagStorage) {
- DiagStorage = getStorage();
- *DiagStorage = *Other.DiagStorage;
- }
- }
- template <typename T> const PartialDiagnostic &operator<<(const T &V) const {
- const StreamingDiagnostic &DB = *this;
- DB << V;
- return *this;
- }
- // It is necessary to limit this to rvalue reference to avoid calling this
- // function with a bitfield lvalue argument since non-const reference to
- // bitfield is not allowed.
- template <typename T, typename = typename std::enable_if<
- !std::is_lvalue_reference<T>::value>::type>
- const PartialDiagnostic &operator<<(T &&V) const {
- const StreamingDiagnostic &DB = *this;
- DB << std::move(V);
- return *this;
- }
- PartialDiagnostic(PartialDiagnostic &&Other) : DiagID(Other.DiagID) {
- Allocator = Other.Allocator;
- DiagStorage = Other.DiagStorage;
- Other.DiagStorage = nullptr;
- }
- PartialDiagnostic(const PartialDiagnostic &Other,
- DiagnosticStorage *DiagStorage_)
- : DiagID(Other.DiagID) {
- Allocator = reinterpret_cast<DiagStorageAllocator *>(~uintptr_t(0));
- DiagStorage = DiagStorage_;
- if (Other.DiagStorage)
- *this->DiagStorage = *Other.DiagStorage;
- }
- PartialDiagnostic(const Diagnostic &Other, DiagStorageAllocator &Allocator_)
- : DiagID(Other.getID()) {
- Allocator = &Allocator_;
- // Copy arguments.
- for (unsigned I = 0, N = Other.getNumArgs(); I != N; ++I) {
- if (Other.getArgKind(I) == DiagnosticsEngine::ak_std_string)
- AddString(Other.getArgStdStr(I));
- else
- AddTaggedVal(Other.getRawArg(I), Other.getArgKind(I));
- }
- // Copy source ranges.
- for (unsigned I = 0, N = Other.getNumRanges(); I != N; ++I)
- AddSourceRange(Other.getRange(I));
- // Copy fix-its.
- for (unsigned I = 0, N = Other.getNumFixItHints(); I != N; ++I)
- AddFixItHint(Other.getFixItHint(I));
- }
- PartialDiagnostic &operator=(const PartialDiagnostic &Other) {
- DiagID = Other.DiagID;
- if (Other.DiagStorage) {
- if (!DiagStorage)
- DiagStorage = getStorage();
- *DiagStorage = *Other.DiagStorage;
- } else {
- freeStorage();
- }
- return *this;
- }
- PartialDiagnostic &operator=(PartialDiagnostic &&Other) {
- freeStorage();
- DiagID = Other.DiagID;
- DiagStorage = Other.DiagStorage;
- Allocator = Other.Allocator;
- Other.DiagStorage = nullptr;
- return *this;
- }
- void swap(PartialDiagnostic &PD) {
- std::swap(DiagID, PD.DiagID);
- std::swap(DiagStorage, PD.DiagStorage);
- std::swap(Allocator, PD.Allocator);
- }
- unsigned getDiagID() const { return DiagID; }
- void setDiagID(unsigned ID) { DiagID = ID; }
- void Emit(const DiagnosticBuilder &DB) const {
- if (!DiagStorage)
- return;
- // Add all arguments.
- for (unsigned i = 0, e = DiagStorage->NumDiagArgs; i != e; ++i) {
- if ((DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i]
- == DiagnosticsEngine::ak_std_string)
- DB.AddString(DiagStorage->DiagArgumentsStr[i]);
- else
- DB.AddTaggedVal(DiagStorage->DiagArgumentsVal[i],
- (DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i]);
- }
- // Add all ranges.
- for (const CharSourceRange &Range : DiagStorage->DiagRanges)
- DB.AddSourceRange(Range);
- // Add all fix-its.
- for (const FixItHint &Fix : DiagStorage->FixItHints)
- DB.AddFixItHint(Fix);
- }
- void EmitToString(DiagnosticsEngine &Diags,
- SmallVectorImpl<char> &Buf) const {
- // FIXME: It should be possible to render a diagnostic to a string without
- // messing with the state of the diagnostics engine.
- DiagnosticBuilder DB(Diags.Report(getDiagID()));
- Emit(DB);
- Diagnostic(&Diags).FormatDiagnostic(Buf);
- DB.Clear();
- Diags.Clear();
- }
- /// Clear out this partial diagnostic, giving it a new diagnostic ID
- /// and removing all of its arguments, ranges, and fix-it hints.
- void Reset(unsigned DiagID = 0) {
- this->DiagID = DiagID;
- freeStorage();
- }
- bool hasStorage() const { return DiagStorage != nullptr; }
- /// Retrieve the string argument at the given index.
- StringRef getStringArg(unsigned I) {
- assert(DiagStorage && "No diagnostic storage?");
- assert(I < DiagStorage->NumDiagArgs && "Not enough diagnostic args");
- assert(DiagStorage->DiagArgumentsKind[I]
- == DiagnosticsEngine::ak_std_string && "Not a string arg");
- return DiagStorage->DiagArgumentsStr[I];
- }
- };
- inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
- const PartialDiagnostic &PD) {
- PD.Emit(DB);
- return DB;
- }
- /// A partial diagnostic along with the source location where this
- /// diagnostic occurs.
- using PartialDiagnosticAt = std::pair<SourceLocation, PartialDiagnostic>;
- } // namespace clang
- #endif // LLVM_CLANG_BASIC_PARTIALDIAGNOSTIC_H
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|