Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:50

0001 //===- PartialDiagnostic.h - Diagnostic "closures" --------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 /// \file
0010 /// Implements a partial diagnostic that can be emitted anwyhere
0011 /// in a DiagnosticBuilder stream.
0012 //
0013 //===----------------------------------------------------------------------===//
0014 
0015 #ifndef LLVM_CLANG_BASIC_PARTIALDIAGNOSTIC_H
0016 #define LLVM_CLANG_BASIC_PARTIALDIAGNOSTIC_H
0017 
0018 #include "clang/Basic/Diagnostic.h"
0019 #include "clang/Basic/LLVM.h"
0020 #include "clang/Basic/SourceLocation.h"
0021 #include "llvm/ADT/SmallVector.h"
0022 #include "llvm/ADT/StringRef.h"
0023 #include <cassert>
0024 #include <cstdint>
0025 #include <string>
0026 #include <type_traits>
0027 #include <utility>
0028 
0029 namespace clang {
0030 
0031 class PartialDiagnostic : public StreamingDiagnostic {
0032 private:
0033   // NOTE: Sema assumes that PartialDiagnostic is location-invariant
0034   // in the sense that its bits can be safely memcpy'ed and destructed
0035   // in the new location.
0036 
0037   /// The diagnostic ID.
0038   mutable unsigned DiagID = 0;
0039 public:
0040   struct NullDiagnostic {};
0041 
0042   /// Create a null partial diagnostic, which cannot carry a payload,
0043   /// and only exists to be swapped with a real partial diagnostic.
0044   PartialDiagnostic(NullDiagnostic) {}
0045 
0046   PartialDiagnostic(unsigned DiagID, DiagStorageAllocator &Allocator_)
0047       : StreamingDiagnostic(Allocator_), DiagID(DiagID) {}
0048 
0049   PartialDiagnostic(const PartialDiagnostic &Other)
0050       : StreamingDiagnostic(), DiagID(Other.DiagID) {
0051     Allocator = Other.Allocator;
0052     if (Other.DiagStorage) {
0053       DiagStorage = getStorage();
0054       *DiagStorage = *Other.DiagStorage;
0055     }
0056   }
0057 
0058   template <typename T> const PartialDiagnostic &operator<<(const T &V) const {
0059     const StreamingDiagnostic &DB = *this;
0060     DB << V;
0061     return *this;
0062   }
0063 
0064   // It is necessary to limit this to rvalue reference to avoid calling this
0065   // function with a bitfield lvalue argument since non-const reference to
0066   // bitfield is not allowed.
0067   template <typename T,
0068             typename = std::enable_if_t<!std::is_lvalue_reference<T>::value>>
0069   const PartialDiagnostic &operator<<(T &&V) const {
0070     const StreamingDiagnostic &DB = *this;
0071     DB << std::move(V);
0072     return *this;
0073   }
0074 
0075   PartialDiagnostic(PartialDiagnostic &&Other) : DiagID(Other.DiagID) {
0076     Allocator = Other.Allocator;
0077     DiagStorage = Other.DiagStorage;
0078     Other.DiagStorage = nullptr;
0079   }
0080 
0081   PartialDiagnostic(const PartialDiagnostic &Other,
0082                     DiagnosticStorage *DiagStorage_)
0083       : DiagID(Other.DiagID) {
0084     Allocator = reinterpret_cast<DiagStorageAllocator *>(~uintptr_t(0));
0085     DiagStorage = DiagStorage_;
0086     if (Other.DiagStorage)
0087       *this->DiagStorage = *Other.DiagStorage;
0088   }
0089 
0090   PartialDiagnostic(const Diagnostic &Other, DiagStorageAllocator &Allocator_)
0091       : DiagID(Other.getID()) {
0092     Allocator = &Allocator_;
0093     // Copy arguments.
0094     for (unsigned I = 0, N = Other.getNumArgs(); I != N; ++I) {
0095       if (Other.getArgKind(I) == DiagnosticsEngine::ak_std_string)
0096         AddString(Other.getArgStdStr(I));
0097       else
0098         AddTaggedVal(Other.getRawArg(I), Other.getArgKind(I));
0099     }
0100 
0101     // Copy source ranges.
0102     for (unsigned I = 0, N = Other.getNumRanges(); I != N; ++I)
0103       AddSourceRange(Other.getRange(I));
0104 
0105     // Copy fix-its.
0106     for (unsigned I = 0, N = Other.getNumFixItHints(); I != N; ++I)
0107       AddFixItHint(Other.getFixItHint(I));
0108   }
0109 
0110   PartialDiagnostic &operator=(const PartialDiagnostic &Other) {
0111     DiagID = Other.DiagID;
0112     if (Other.DiagStorage) {
0113       if (!DiagStorage)
0114         DiagStorage = getStorage();
0115 
0116       *DiagStorage = *Other.DiagStorage;
0117     } else {
0118       freeStorage();
0119     }
0120 
0121     return *this;
0122   }
0123 
0124   PartialDiagnostic &operator=(PartialDiagnostic &&Other) {
0125     freeStorage();
0126 
0127     DiagID = Other.DiagID;
0128     DiagStorage = Other.DiagStorage;
0129     Allocator = Other.Allocator;
0130 
0131     Other.DiagStorage = nullptr;
0132     return *this;
0133   }
0134 
0135   void swap(PartialDiagnostic &PD) {
0136     std::swap(DiagID, PD.DiagID);
0137     std::swap(DiagStorage, PD.DiagStorage);
0138     std::swap(Allocator, PD.Allocator);
0139   }
0140 
0141   unsigned getDiagID() const { return DiagID; }
0142   void setDiagID(unsigned ID) { DiagID = ID; }
0143 
0144   void Emit(const DiagnosticBuilder &DB) const {
0145     if (!DiagStorage)
0146       return;
0147 
0148     // Add all arguments.
0149     for (unsigned i = 0, e = DiagStorage->NumDiagArgs; i != e; ++i) {
0150       if ((DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i]
0151             == DiagnosticsEngine::ak_std_string)
0152         DB.AddString(DiagStorage->DiagArgumentsStr[i]);
0153       else
0154         DB.AddTaggedVal(DiagStorage->DiagArgumentsVal[i],
0155             (DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i]);
0156     }
0157 
0158     // Add all ranges.
0159     for (const CharSourceRange &Range : DiagStorage->DiagRanges)
0160       DB.AddSourceRange(Range);
0161 
0162     // Add all fix-its.
0163     for (const FixItHint &Fix : DiagStorage->FixItHints)
0164       DB.AddFixItHint(Fix);
0165   }
0166 
0167   void EmitToString(DiagnosticsEngine &Diags,
0168                     SmallVectorImpl<char> &Buf) const {
0169     DiagnosticBuilder DB(Diags.Report(getDiagID()));
0170     Emit(DB);
0171     Diagnostic(&Diags, DB).FormatDiagnostic(Buf);
0172     DB.Clear();
0173   }
0174 
0175   /// Clear out this partial diagnostic, giving it a new diagnostic ID
0176   /// and removing all of its arguments, ranges, and fix-it hints.
0177   void Reset(unsigned DiagID = 0) {
0178     this->DiagID = DiagID;
0179     freeStorage();
0180   }
0181 
0182   bool hasStorage() const { return DiagStorage != nullptr; }
0183 
0184   /// Retrieve the string argument at the given index.
0185   StringRef getStringArg(unsigned I) {
0186     assert(DiagStorage && "No diagnostic storage?");
0187     assert(I < DiagStorage->NumDiagArgs && "Not enough diagnostic args");
0188     assert(DiagStorage->DiagArgumentsKind[I]
0189              == DiagnosticsEngine::ak_std_string && "Not a string arg");
0190     return DiagStorage->DiagArgumentsStr[I];
0191   }
0192 };
0193 
0194 inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
0195                                            const PartialDiagnostic &PD) {
0196   PD.Emit(DB);
0197   return DB;
0198 }
0199 
0200 /// A partial diagnostic along with the source location where this
0201 /// diagnostic occurs.
0202 using PartialDiagnosticAt = std::pair<SourceLocation, PartialDiagnostic>;
0203 
0204 } // namespace clang
0205 
0206 #endif // LLVM_CLANG_BASIC_PARTIALDIAGNOSTIC_H