18b00be55606207c255cf3d3bd529143e93ff9c31Sebastian Redl//===--- PartialDiagnostic.h - Diagnostic "closures" ------------*- C++ -*-===// 221c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson// 321c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson// The LLVM Compiler Infrastructure 421c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson// 521c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson// This file is distributed under the University of Illinois Open Source 621c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson// License. See LICENSE.TXT for details. 721c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson// 821c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson//===----------------------------------------------------------------------===// 92f7f5b1f5ff023cb8c4008ae53a12b09e3ea2622James Dennett/// 102f7f5b1f5ff023cb8c4008ae53a12b09e3ea2622James Dennett/// \file 112f7f5b1f5ff023cb8c4008ae53a12b09e3ea2622James Dennett/// \brief Implements a partial diagnostic that can be emitted anwyhere 122f7f5b1f5ff023cb8c4008ae53a12b09e3ea2622James Dennett/// in a DiagnosticBuilder stream. 132f7f5b1f5ff023cb8c4008ae53a12b09e3ea2622James Dennett/// 1421c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson//===----------------------------------------------------------------------===// 1521c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson 16b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson#ifndef LLVM_CLANG_PARTIALDIAGNOSTIC_H 17b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson#define LLVM_CLANG_PARTIALDIAGNOSTIC_H 18b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson 19b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson#include "clang/Basic/Diagnostic.h" 20b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson#include "clang/Basic/SourceLocation.h" 21d5a423b279e787e9fdd8309fe52cb515388c54eaDouglas Gregor#include "llvm/ADT/STLExtras.h" 22407a82fb22acad58be27f096748e74c83a295c40Benjamin Kramer#include "llvm/Support/Compiler.h" 2303013fa9a0bf1ef4b907f5fec006c8f4000fdd21Michael J. Spencer#include "llvm/Support/DataTypes.h" 24b836518bfc0a2ad5e22a670c82fa070ed83ea909Douglas Gregor#include <cassert> 25b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson 26b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlssonnamespace clang { 27b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson 28d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramerclass PartialDiagnostic { 29d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramerpublic: 30d3891e9fb7eb25436e5c537189030bed0d5a1dcfDouglas Gregor enum { 31d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer // The MaxArguments and MaxFixItHints member enum values from 32d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer // DiagnosticsEngine are private but DiagnosticsEngine declares 33d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer // PartialDiagnostic a friend. These enum values are redeclared 34d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer // here so that the nested Storage class below can access them. 35cbf46a0b2bb2b47d6e13437e0d52cc583c5ce539Argyrios Kyrtzidis MaxArguments = DiagnosticsEngine::MaxArguments 36d3891e9fb7eb25436e5c537189030bed0d5a1dcfDouglas Gregor }; 37d3891e9fb7eb25436e5c537189030bed0d5a1dcfDouglas Gregor 38d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer struct Storage { 396bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines Storage() : NumDiagArgs(0) { } 40d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer 41d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer enum { 42af50aab0c317462129d73ae8000c6394c718598dJames Dennett /// \brief The maximum number of arguments we can hold. We 43d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer /// currently only support up to 10 arguments (%0-%9). 44af50aab0c317462129d73ae8000c6394c718598dJames Dennett /// 45d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer /// A single diagnostic with more than that almost certainly has to 46d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer /// be simplified anyway. 47d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer MaxArguments = PartialDiagnostic::MaxArguments 48d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer }; 49d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer 50af50aab0c317462129d73ae8000c6394c718598dJames Dennett /// \brief The number of entries in Arguments. 51d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer unsigned char NumDiagArgs; 52d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer 53af50aab0c317462129d73ae8000c6394c718598dJames Dennett /// \brief Specifies for each argument whether it is in DiagArgumentsStr 54af50aab0c317462129d73ae8000c6394c718598dJames Dennett /// or in DiagArguments. 55d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer unsigned char DiagArgumentsKind[MaxArguments]; 56d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer 57af50aab0c317462129d73ae8000c6394c718598dJames Dennett /// \brief The values for the various substitution positions. 58af50aab0c317462129d73ae8000c6394c718598dJames Dennett /// 59d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer /// This is used when the argument is not an std::string. The specific value 60d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer /// is mangled into an intptr_t and the interpretation depends on exactly 61d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer /// what sort of argument kind it is. 62d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer intptr_t DiagArgumentsVal[MaxArguments]; 63d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer 64d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer /// \brief The values for the various substitution positions that have 65d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer /// string arguments. 66d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer std::string DiagArgumentsStr[MaxArguments]; 67d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer 68af50aab0c317462129d73ae8000c6394c718598dJames Dennett /// \brief The list of ranges added to this diagnostic. 696bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines SmallVector<CharSourceRange, 8> DiagRanges; 70d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer 71af50aab0c317462129d73ae8000c6394c718598dJames Dennett /// \brief If valid, provides a hint with some code to insert, remove, or 72af50aab0c317462129d73ae8000c6394c718598dJames Dennett /// modify at a particular position. 73d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer SmallVector<FixItHint, 6> FixItHints; 74d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer }; 75b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson 76d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer /// \brief An allocator for Storage objects, which uses a small cache to 77d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer /// objects, used to reduce malloc()/free() traffic for partial diagnostics. 78d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer class StorageAllocator { 79d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer static const unsigned NumCached = 16; 80d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer Storage Cached[NumCached]; 81d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer Storage *FreeList[NumCached]; 82d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer unsigned NumFreeListEntries; 83d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer 84d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer public: 85d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer StorageAllocator(); 86d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer ~StorageAllocator(); 87d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer 88d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer /// \brief Allocate new storage. 89d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer Storage *Allocate() { 90d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer if (NumFreeListEntries == 0) 91d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer return new Storage; 92d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer 93d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer Storage *Result = FreeList[--NumFreeListEntries]; 94d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer Result->NumDiagArgs = 0; 956bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines Result->DiagRanges.clear(); 96d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer Result->FixItHints.clear(); 97d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer return Result; 98fe6b2d481d91140923f4541f273b253291884214Douglas Gregor } 9970042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 100d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer /// \brief Free the given storage object. 101d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer void Deallocate(Storage *S) { 102d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer if (S >= Cached && S <= Cached + NumCached) { 103d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer FreeList[NumFreeListEntries++] = S; 104d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer return; 105d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer } 10670042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 107d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer delete S; 108d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer } 109d7a3e2c5f61cd4893f95b69a424fe4def3aa0f69Benjamin Kramer }; 11070042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 111fe6b2d481d91140923f4541f273b253291884214Douglas Gregorprivate: 11258e6f34e4d2c668562e1c391162ee9de7b05fbb2John McCall // NOTE: Sema assumes that PartialDiagnostic is location-invariant 11358e6f34e4d2c668562e1c391162ee9de7b05fbb2John McCall // in the sense that its bits can be safely memcpy'ed and destructed 11458e6f34e4d2c668562e1c391162ee9de7b05fbb2John McCall // in the new location. 11558e6f34e4d2c668562e1c391162ee9de7b05fbb2John McCall 116af50aab0c317462129d73ae8000c6394c718598dJames Dennett /// \brief The diagnostic ID. 11721c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson mutable unsigned DiagID; 11870042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 119af50aab0c317462129d73ae8000c6394c718598dJames Dennett /// \brief Storage for args and ranges. 120b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson mutable Storage *DiagStorage; 121b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson 122fe6b2d481d91140923f4541f273b253291884214Douglas Gregor /// \brief Allocator used to allocate storage for this diagnostic. 123fe6b2d481d91140923f4541f273b253291884214Douglas Gregor StorageAllocator *Allocator; 12470042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 125fe6b2d481d91140923f4541f273b253291884214Douglas Gregor /// \brief Retrieve storage for this particular diagnostic. 126fe6b2d481d91140923f4541f273b253291884214Douglas Gregor Storage *getStorage() const { 127fe6b2d481d91140923f4541f273b253291884214Douglas Gregor if (DiagStorage) 128fe6b2d481d91140923f4541f273b253291884214Douglas Gregor return DiagStorage; 12970042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 130fe6b2d481d91140923f4541f273b253291884214Douglas Gregor if (Allocator) 131fe6b2d481d91140923f4541f273b253291884214Douglas Gregor DiagStorage = Allocator->Allocate(); 132b836518bfc0a2ad5e22a670c82fa070ed83ea909Douglas Gregor else { 133b836518bfc0a2ad5e22a670c82fa070ed83ea909Douglas Gregor assert(Allocator != reinterpret_cast<StorageAllocator *>(~uintptr_t(0))); 134fe6b2d481d91140923f4541f273b253291884214Douglas Gregor DiagStorage = new Storage; 135b836518bfc0a2ad5e22a670c82fa070ed83ea909Douglas Gregor } 136fe6b2d481d91140923f4541f273b253291884214Douglas Gregor return DiagStorage; 137fe6b2d481d91140923f4541f273b253291884214Douglas Gregor } 13870042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 13970042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie void freeStorage() { 140fe6b2d481d91140923f4541f273b253291884214Douglas Gregor if (!DiagStorage) 141fe6b2d481d91140923f4541f273b253291884214Douglas Gregor return; 14270042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 14354e1c41b31c0bc5acad4473f802215bcd6a3206bDaniel Dunbar // The hot path for PartialDiagnostic is when we just used it to wrap an ID 14454e1c41b31c0bc5acad4473f802215bcd6a3206bDaniel Dunbar // (typically so we have the flexibility of passing a more complex 14554e1c41b31c0bc5acad4473f802215bcd6a3206bDaniel Dunbar // diagnostic into the callee, but that does not commonly occur). 14654e1c41b31c0bc5acad4473f802215bcd6a3206bDaniel Dunbar // 14754e1c41b31c0bc5acad4473f802215bcd6a3206bDaniel Dunbar // Split this out into a slow function for silly compilers (*cough*) which 14854e1c41b31c0bc5acad4473f802215bcd6a3206bDaniel Dunbar // can't do decent partial inlining. 14954e1c41b31c0bc5acad4473f802215bcd6a3206bDaniel Dunbar freeStorageSlow(); 15054e1c41b31c0bc5acad4473f802215bcd6a3206bDaniel Dunbar } 15154e1c41b31c0bc5acad4473f802215bcd6a3206bDaniel Dunbar 15254e1c41b31c0bc5acad4473f802215bcd6a3206bDaniel Dunbar void freeStorageSlow() { 153fe6b2d481d91140923f4541f273b253291884214Douglas Gregor if (Allocator) 154fe6b2d481d91140923f4541f273b253291884214Douglas Gregor Allocator->Deallocate(DiagStorage); 155b836518bfc0a2ad5e22a670c82fa070ed83ea909Douglas Gregor else if (Allocator != reinterpret_cast<StorageAllocator *>(~uintptr_t(0))) 156fe6b2d481d91140923f4541f273b253291884214Douglas Gregor delete DiagStorage; 1576bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines DiagStorage = nullptr; 158fe6b2d481d91140923f4541f273b253291884214Douglas Gregor } 15970042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 1600a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner void AddSourceRange(const CharSourceRange &R) const { 16121c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson if (!DiagStorage) 162fe6b2d481d91140923f4541f273b253291884214Douglas Gregor DiagStorage = getStorage(); 16321c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson 1646bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines DiagStorage->DiagRanges.push_back(R); 16570042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie } 166b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson 167849b243d4065f56742a4677d6dc8277609a151f8Douglas Gregor void AddFixItHint(const FixItHint &Hint) const { 168d1e4d9bfd57f643d950eb1373f582bda4dfb8dc7Douglas Gregor if (Hint.isNull()) 169d1e4d9bfd57f643d950eb1373f582bda4dfb8dc7Douglas Gregor return; 17070042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 171d1e4d9bfd57f643d950eb1373f582bda4dfb8dc7Douglas Gregor if (!DiagStorage) 172fe6b2d481d91140923f4541f273b253291884214Douglas Gregor DiagStorage = getStorage(); 173d1e4d9bfd57f643d950eb1373f582bda4dfb8dc7Douglas Gregor 174cbf46a0b2bb2b47d6e13437e0d52cc583c5ce539Argyrios Kyrtzidis DiagStorage->FixItHints.push_back(Hint); 175d1e4d9bfd57f643d950eb1373f582bda4dfb8dc7Douglas Gregor } 17670042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 177b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlssonpublic: 178b8590f3572158bde97f14037c4cc8f4a57c8d810Richard Smith struct NullDiagnostic {}; 179b8590f3572158bde97f14037c4cc8f4a57c8d810Richard Smith /// \brief Create a null partial diagnostic, which cannot carry a payload, 180b8590f3572158bde97f14037c4cc8f4a57c8d810Richard Smith /// and only exists to be swapped with a real partial diagnostic. 181b8590f3572158bde97f14037c4cc8f4a57c8d810Richard Smith PartialDiagnostic(NullDiagnostic) 1826bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines : DiagID(0), DiagStorage(nullptr), Allocator(nullptr) { } 183b8590f3572158bde97f14037c4cc8f4a57c8d810Richard Smith 184fe6b2d481d91140923f4541f273b253291884214Douglas Gregor PartialDiagnostic(unsigned DiagID, StorageAllocator &Allocator) 1856bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines : DiagID(DiagID), DiagStorage(nullptr), Allocator(&Allocator) { } 18670042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 18770042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie PartialDiagnostic(const PartialDiagnostic &Other) 1886bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines : DiagID(Other.DiagID), DiagStorage(nullptr), Allocator(Other.Allocator) 189a63d40f85c4621f5ad2362e0d00879933625404bDouglas Gregor { 190fe6b2d481d91140923f4541f273b253291884214Douglas Gregor if (Other.DiagStorage) { 191fe6b2d481d91140923f4541f273b253291884214Douglas Gregor DiagStorage = getStorage(); 192fe6b2d481d91140923f4541f273b253291884214Douglas Gregor *DiagStorage = *Other.DiagStorage; 193fe6b2d481d91140923f4541f273b253291884214Douglas Gregor } 194a63d40f85c4621f5ad2362e0d00879933625404bDouglas Gregor } 195a63d40f85c4621f5ad2362e0d00879933625404bDouglas Gregor 196407a82fb22acad58be27f096748e74c83a295c40Benjamin Kramer PartialDiagnostic(PartialDiagnostic &&Other) 197407a82fb22acad58be27f096748e74c83a295c40Benjamin Kramer : DiagID(Other.DiagID), DiagStorage(Other.DiagStorage), 198407a82fb22acad58be27f096748e74c83a295c40Benjamin Kramer Allocator(Other.Allocator) { 1996bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines Other.DiagStorage = nullptr; 200407a82fb22acad58be27f096748e74c83a295c40Benjamin Kramer } 201407a82fb22acad58be27f096748e74c83a295c40Benjamin Kramer 20270042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie PartialDiagnostic(const PartialDiagnostic &Other, Storage *DiagStorage) 20370042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie : DiagID(Other.DiagID), DiagStorage(DiagStorage), 204b836518bfc0a2ad5e22a670c82fa070ed83ea909Douglas Gregor Allocator(reinterpret_cast<StorageAllocator *>(~uintptr_t(0))) 205b836518bfc0a2ad5e22a670c82fa070ed83ea909Douglas Gregor { 206b836518bfc0a2ad5e22a670c82fa070ed83ea909Douglas Gregor if (Other.DiagStorage) 207b836518bfc0a2ad5e22a670c82fa070ed83ea909Douglas Gregor *this->DiagStorage = *Other.DiagStorage; 208b836518bfc0a2ad5e22a670c82fa070ed83ea909Douglas Gregor } 20970042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 21040847cfb58acc3cac7d68727df9455ac45f2e118David Blaikie PartialDiagnostic(const Diagnostic &Other, StorageAllocator &Allocator) 2116bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines : DiagID(Other.getID()), DiagStorage(nullptr), Allocator(&Allocator) 2129b623639378d53a675921ddfa7316034d571881eDouglas Gregor { 2139b623639378d53a675921ddfa7316034d571881eDouglas Gregor // Copy arguments. 2149b623639378d53a675921ddfa7316034d571881eDouglas Gregor for (unsigned I = 0, N = Other.getNumArgs(); I != N; ++I) { 215d6471f7c1921c7802804ce3ff6fe9768310f72b9David Blaikie if (Other.getArgKind(I) == DiagnosticsEngine::ak_std_string) 2169b623639378d53a675921ddfa7316034d571881eDouglas Gregor AddString(Other.getArgStdStr(I)); 2179b623639378d53a675921ddfa7316034d571881eDouglas Gregor else 2189b623639378d53a675921ddfa7316034d571881eDouglas Gregor AddTaggedVal(Other.getRawArg(I), Other.getArgKind(I)); 2199b623639378d53a675921ddfa7316034d571881eDouglas Gregor } 22070042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 2219b623639378d53a675921ddfa7316034d571881eDouglas Gregor // Copy source ranges. 2229b623639378d53a675921ddfa7316034d571881eDouglas Gregor for (unsigned I = 0, N = Other.getNumRanges(); I != N; ++I) 2239b623639378d53a675921ddfa7316034d571881eDouglas Gregor AddSourceRange(Other.getRange(I)); 22470042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 2259b623639378d53a675921ddfa7316034d571881eDouglas Gregor // Copy fix-its. 2269b623639378d53a675921ddfa7316034d571881eDouglas Gregor for (unsigned I = 0, N = Other.getNumFixItHints(); I != N; ++I) 2279b623639378d53a675921ddfa7316034d571881eDouglas Gregor AddFixItHint(Other.getFixItHint(I)); 2289b623639378d53a675921ddfa7316034d571881eDouglas Gregor } 22970042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 230a63d40f85c4621f5ad2362e0d00879933625404bDouglas Gregor PartialDiagnostic &operator=(const PartialDiagnostic &Other) { 231a63d40f85c4621f5ad2362e0d00879933625404bDouglas Gregor DiagID = Other.DiagID; 232a63d40f85c4621f5ad2362e0d00879933625404bDouglas Gregor if (Other.DiagStorage) { 233fe6b2d481d91140923f4541f273b253291884214Douglas Gregor if (!DiagStorage) 234fe6b2d481d91140923f4541f273b253291884214Douglas Gregor DiagStorage = getStorage(); 23570042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 236fe6b2d481d91140923f4541f273b253291884214Douglas Gregor *DiagStorage = *Other.DiagStorage; 237a63d40f85c4621f5ad2362e0d00879933625404bDouglas Gregor } else { 238fe6b2d481d91140923f4541f273b253291884214Douglas Gregor freeStorage(); 239a63d40f85c4621f5ad2362e0d00879933625404bDouglas Gregor } 240a63d40f85c4621f5ad2362e0d00879933625404bDouglas Gregor 241a63d40f85c4621f5ad2362e0d00879933625404bDouglas Gregor return *this; 242b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson } 243b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson 244407a82fb22acad58be27f096748e74c83a295c40Benjamin Kramer PartialDiagnostic &operator=(PartialDiagnostic &&Other) { 245b283da20cb2ad5e386ae04e004fbe80576f508fbBenjamin Kramer freeStorage(); 246407a82fb22acad58be27f096748e74c83a295c40Benjamin Kramer 247b283da20cb2ad5e386ae04e004fbe80576f508fbBenjamin Kramer DiagID = Other.DiagID; 248b283da20cb2ad5e386ae04e004fbe80576f508fbBenjamin Kramer DiagStorage = Other.DiagStorage; 249b283da20cb2ad5e386ae04e004fbe80576f508fbBenjamin Kramer Allocator = Other.Allocator; 250407a82fb22acad58be27f096748e74c83a295c40Benjamin Kramer 2516bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines Other.DiagStorage = nullptr; 252407a82fb22acad58be27f096748e74c83a295c40Benjamin Kramer return *this; 253407a82fb22acad58be27f096748e74c83a295c40Benjamin Kramer } 254407a82fb22acad58be27f096748e74c83a295c40Benjamin Kramer 255b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson ~PartialDiagnostic() { 256fe6b2d481d91140923f4541f273b253291884214Douglas Gregor freeStorage(); 257b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson } 258b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson 259b8590f3572158bde97f14037c4cc8f4a57c8d810Richard Smith void swap(PartialDiagnostic &PD) { 260b8590f3572158bde97f14037c4cc8f4a57c8d810Richard Smith std::swap(DiagID, PD.DiagID); 261b8590f3572158bde97f14037c4cc8f4a57c8d810Richard Smith std::swap(DiagStorage, PD.DiagStorage); 262b8590f3572158bde97f14037c4cc8f4a57c8d810Richard Smith std::swap(Allocator, PD.Allocator); 263b8590f3572158bde97f14037c4cc8f4a57c8d810Richard Smith } 264b8590f3572158bde97f14037c4cc8f4a57c8d810Richard Smith 26521c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson unsigned getDiagID() const { return DiagID; } 26621c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson 267d6471f7c1921c7802804ce3ff6fe9768310f72b9David Blaikie void AddTaggedVal(intptr_t V, DiagnosticsEngine::ArgumentKind Kind) const { 26847c24b1d94f446c43e3a64732867eabed7d9c961Chandler Carruth if (!DiagStorage) 26947c24b1d94f446c43e3a64732867eabed7d9c961Chandler Carruth DiagStorage = getStorage(); 27047c24b1d94f446c43e3a64732867eabed7d9c961Chandler Carruth 27147c24b1d94f446c43e3a64732867eabed7d9c961Chandler Carruth assert(DiagStorage->NumDiagArgs < Storage::MaxArguments && 27247c24b1d94f446c43e3a64732867eabed7d9c961Chandler Carruth "Too many arguments to diagnostic!"); 27347c24b1d94f446c43e3a64732867eabed7d9c961Chandler Carruth DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] = Kind; 27447c24b1d94f446c43e3a64732867eabed7d9c961Chandler Carruth DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V; 27547c24b1d94f446c43e3a64732867eabed7d9c961Chandler Carruth } 27647c24b1d94f446c43e3a64732867eabed7d9c961Chandler Carruth 277686775deca8b8685eb90801495880e3abdd844c2Chris Lattner void AddString(StringRef V) const { 2789b623639378d53a675921ddfa7316034d571881eDouglas Gregor if (!DiagStorage) 2799b623639378d53a675921ddfa7316034d571881eDouglas Gregor DiagStorage = getStorage(); 28070042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 2819b623639378d53a675921ddfa7316034d571881eDouglas Gregor assert(DiagStorage->NumDiagArgs < Storage::MaxArguments && 2829b623639378d53a675921ddfa7316034d571881eDouglas Gregor "Too many arguments to diagnostic!"); 2839b623639378d53a675921ddfa7316034d571881eDouglas Gregor DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] 284d6471f7c1921c7802804ce3ff6fe9768310f72b9David Blaikie = DiagnosticsEngine::ak_std_string; 2859b623639378d53a675921ddfa7316034d571881eDouglas Gregor DiagStorage->DiagArgumentsStr[DiagStorage->NumDiagArgs++] = V; 2869b623639378d53a675921ddfa7316034d571881eDouglas Gregor } 2879b623639378d53a675921ddfa7316034d571881eDouglas Gregor 28821c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson void Emit(const DiagnosticBuilder &DB) const { 28921c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson if (!DiagStorage) 29021c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson return; 29170042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 29221c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson // Add all arguments. 29321c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson for (unsigned i = 0, e = DiagStorage->NumDiagArgs; i != e; ++i) { 294d6471f7c1921c7802804ce3ff6fe9768310f72b9David Blaikie if ((DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i] 295d6471f7c1921c7802804ce3ff6fe9768310f72b9David Blaikie == DiagnosticsEngine::ak_std_string) 2969b623639378d53a675921ddfa7316034d571881eDouglas Gregor DB.AddString(DiagStorage->DiagArgumentsStr[i]); 2979b623639378d53a675921ddfa7316034d571881eDouglas Gregor else 2989b623639378d53a675921ddfa7316034d571881eDouglas Gregor DB.AddTaggedVal(DiagStorage->DiagArgumentsVal[i], 299d6471f7c1921c7802804ce3ff6fe9768310f72b9David Blaikie (DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i]); 30021c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson } 30170042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 30221c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson // Add all ranges. 3036bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines for (const CharSourceRange &Range : DiagStorage->DiagRanges) 3046bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines DB.AddSourceRange(Range); 30570042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 3069b623639378d53a675921ddfa7316034d571881eDouglas Gregor // Add all fix-its. 3076bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines for (const FixItHint &Fix : DiagStorage->FixItHints) 3086bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines DB.AddFixItHint(Fix); 30921c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson } 31070042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 311b8590f3572158bde97f14037c4cc8f4a57c8d810Richard Smith void EmitToString(DiagnosticsEngine &Diags, 312cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri Gribenko SmallVectorImpl<char> &Buf) const { 313b8590f3572158bde97f14037c4cc8f4a57c8d810Richard Smith // FIXME: It should be possible to render a diagnostic to a string without 314b8590f3572158bde97f14037c4cc8f4a57c8d810Richard Smith // messing with the state of the diagnostics engine. 315b8590f3572158bde97f14037c4cc8f4a57c8d810Richard Smith DiagnosticBuilder DB(Diags.Report(getDiagID())); 316b8590f3572158bde97f14037c4cc8f4a57c8d810Richard Smith Emit(DB); 317b8590f3572158bde97f14037c4cc8f4a57c8d810Richard Smith DB.FlushCounts(); 318b8590f3572158bde97f14037c4cc8f4a57c8d810Richard Smith Diagnostic(&Diags).FormatDiagnostic(Buf); 319b8590f3572158bde97f14037c4cc8f4a57c8d810Richard Smith DB.Clear(); 320b8590f3572158bde97f14037c4cc8f4a57c8d810Richard Smith Diags.Clear(); 321b8590f3572158bde97f14037c4cc8f4a57c8d810Richard Smith } 322b8590f3572158bde97f14037c4cc8f4a57c8d810Richard Smith 323fe6b2d481d91140923f4541f273b253291884214Douglas Gregor /// \brief Clear out this partial diagnostic, giving it a new diagnostic ID 324fe6b2d481d91140923f4541f273b253291884214Douglas Gregor /// and removing all of its arguments, ranges, and fix-it hints. 325fe6b2d481d91140923f4541f273b253291884214Douglas Gregor void Reset(unsigned DiagID = 0) { 326fe6b2d481d91140923f4541f273b253291884214Douglas Gregor this->DiagID = DiagID; 327fe6b2d481d91140923f4541f273b253291884214Douglas Gregor freeStorage(); 328fe6b2d481d91140923f4541f273b253291884214Douglas Gregor } 32970042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 3306bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines bool hasStorage() const { return DiagStorage != nullptr; } 33170042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 332b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, 333a6ec7ad25a137fd42d84e6b6d44b32976cae440cAnders Carlsson unsigned I) { 334d6471f7c1921c7802804ce3ff6fe9768310f72b9David Blaikie PD.AddTaggedVal(I, DiagnosticsEngine::ak_uint); 335a6ec7ad25a137fd42d84e6b6d44b32976cae440cAnders Carlsson return PD; 336a6ec7ad25a137fd42d84e6b6d44b32976cae440cAnders Carlsson } 3376b169accbb182d328ad41746c4071d8e7f90a628Sebastian Redl 3386b169accbb182d328ad41746c4071d8e7f90a628Sebastian Redl friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, 3396b169accbb182d328ad41746c4071d8e7f90a628Sebastian Redl int I) { 340d6471f7c1921c7802804ce3ff6fe9768310f72b9David Blaikie PD.AddTaggedVal(I, DiagnosticsEngine::ak_sint); 3416b169accbb182d328ad41746c4071d8e7f90a628Sebastian Redl return PD; 3426b169accbb182d328ad41746c4071d8e7f90a628Sebastian Redl } 3436b169accbb182d328ad41746c4071d8e7f90a628Sebastian Redl 3446b169accbb182d328ad41746c4071d8e7f90a628Sebastian Redl friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, 3456b169accbb182d328ad41746c4071d8e7f90a628Sebastian Redl const char *S) { 346d6471f7c1921c7802804ce3ff6fe9768310f72b9David Blaikie PD.AddTaggedVal(reinterpret_cast<intptr_t>(S), 347d6471f7c1921c7802804ce3ff6fe9768310f72b9David Blaikie DiagnosticsEngine::ak_c_string); 3486b169accbb182d328ad41746c4071d8e7f90a628Sebastian Redl return PD; 3496b169accbb182d328ad41746c4071d8e7f90a628Sebastian Redl } 3506b169accbb182d328ad41746c4071d8e7f90a628Sebastian Redl 351b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, 352686775deca8b8685eb90801495880e3abdd844c2Chris Lattner StringRef S) { 35370042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 3549b623639378d53a675921ddfa7316034d571881eDouglas Gregor PD.AddString(S); 3559b623639378d53a675921ddfa7316034d571881eDouglas Gregor return PD; 3569b623639378d53a675921ddfa7316034d571881eDouglas Gregor } 3572d67097ad41f4c2fe82ebce3f587e06498f1bd71Richard Smith 3582d67097ad41f4c2fe82ebce3f587e06498f1bd71Richard Smith friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, 3592d67097ad41f4c2fe82ebce3f587e06498f1bd71Richard Smith const IdentifierInfo *II) { 3602d67097ad41f4c2fe82ebce3f587e06498f1bd71Richard Smith PD.AddTaggedVal(reinterpret_cast<intptr_t>(II), 3612d67097ad41f4c2fe82ebce3f587e06498f1bd71Richard Smith DiagnosticsEngine::ak_identifierinfo); 3622d67097ad41f4c2fe82ebce3f587e06498f1bd71Richard Smith return PD; 3632d67097ad41f4c2fe82ebce3f587e06498f1bd71Richard Smith } 3642d67097ad41f4c2fe82ebce3f587e06498f1bd71Richard Smith 3652d67097ad41f4c2fe82ebce3f587e06498f1bd71Richard Smith // Adds a DeclContext to the diagnostic. The enable_if template magic is here 3662d67097ad41f4c2fe82ebce3f587e06498f1bd71Richard Smith // so that we only match those arguments that are (statically) DeclContexts; 3672d67097ad41f4c2fe82ebce3f587e06498f1bd71Richard Smith // other arguments that derive from DeclContext (e.g., RecordDecls) will not 3682d67097ad41f4c2fe82ebce3f587e06498f1bd71Richard Smith // match. 3692d67097ad41f4c2fe82ebce3f587e06498f1bd71Richard Smith template<typename T> 3702d67097ad41f4c2fe82ebce3f587e06498f1bd71Richard Smith friend inline 371651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines typename std::enable_if<std::is_same<T, DeclContext>::value, 372651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines const PartialDiagnostic &>::type 3732d67097ad41f4c2fe82ebce3f587e06498f1bd71Richard Smith operator<<(const PartialDiagnostic &PD, T *DC) { 3742d67097ad41f4c2fe82ebce3f587e06498f1bd71Richard Smith PD.AddTaggedVal(reinterpret_cast<intptr_t>(DC), 3752d67097ad41f4c2fe82ebce3f587e06498f1bd71Richard Smith DiagnosticsEngine::ak_declcontext); 3762d67097ad41f4c2fe82ebce3f587e06498f1bd71Richard Smith return PD; 3772d67097ad41f4c2fe82ebce3f587e06498f1bd71Richard Smith } 37870042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 3799b623639378d53a675921ddfa7316034d571881eDouglas Gregor friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, 380b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson const SourceRange &R) { 3810a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner PD.AddSourceRange(CharSourceRange::getTokenRange(R)); 382b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson return PD; 383b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson } 3846b169accbb182d328ad41746c4071d8e7f90a628Sebastian Redl 3850a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, 3860a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner const CharSourceRange &R) { 3870a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner PD.AddSourceRange(R); 3880a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner return PD; 3890a76aae8c03cb7dd7bdbe683485560afaf695959Chris Lattner } 39070042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 391d5a423b279e787e9fdd8309fe52cb515388c54eaDouglas Gregor friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, 392849b243d4065f56742a4677d6dc8277609a151f8Douglas Gregor const FixItHint &Hint) { 393849b243d4065f56742a4677d6dc8277609a151f8Douglas Gregor PD.AddFixItHint(Hint); 394d1e4d9bfd57f643d950eb1373f582bda4dfb8dc7Douglas Gregor return PD; 395d1e4d9bfd57f643d950eb1373f582bda4dfb8dc7Douglas Gregor } 39670042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 397b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson}; 398b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson 39921c2e20a00c2215d297470e6b657ede366b147d3Anders Carlssoninline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, 40021c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson const PartialDiagnostic &PD) { 40121c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson PD.Emit(DB); 40221c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson return DB; 40321c2e20a00c2215d297470e6b657ede366b147d3Anders Carlsson} 40470042f5d1ca378138f90b7b9384023701f5d03d8David Blaikie 4059b623639378d53a675921ddfa7316034d571881eDouglas Gregor/// \brief A partial diagnostic along with the source location where this 4069b623639378d53a675921ddfa7316034d571881eDouglas Gregor/// diagnostic occurs. 4079b623639378d53a675921ddfa7316034d571881eDouglas Gregortypedef std::pair<SourceLocation, PartialDiagnostic> PartialDiagnosticAt; 408b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson 409b2153946fff330e54abfdc740c0a83aedd485b33Anders Carlsson} // end namespace clang 410b836518bfc0a2ad5e22a670c82fa070ed83ea909Douglas Gregor#endif 411