Viewing file: PartialDiagnostic.h (6.47 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
//===- 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 = std::enable_if_t<!std::is_lvalue_reference<T>::value>> 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
|