Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 pmbaty 1
//===- PartialDiagnostic.h - Diagnostic "closures" --------------*- C++ -*-===//
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-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
/// \file
10
/// Implements a partial diagnostic that can be emitted anwyhere
11
/// in a DiagnosticBuilder stream.
12
//
13
//===----------------------------------------------------------------------===//
14
 
15
#ifndef LLVM_CLANG_BASIC_PARTIALDIAGNOSTIC_H
16
#define LLVM_CLANG_BASIC_PARTIALDIAGNOSTIC_H
17
 
18
#include "clang/Basic/Diagnostic.h"
19
#include "clang/Basic/LLVM.h"
20
#include "clang/Basic/SourceLocation.h"
21
#include "llvm/ADT/SmallVector.h"
22
#include "llvm/ADT/StringRef.h"
23
#include <cassert>
24
#include <cstdint>
25
#include <string>
26
#include <type_traits>
27
#include <utility>
28
 
29
namespace clang {
30
 
31
class PartialDiagnostic : public StreamingDiagnostic {
32
private:
33
  // NOTE: Sema assumes that PartialDiagnostic is location-invariant
34
  // in the sense that its bits can be safely memcpy'ed and destructed
35
  // in the new location.
36
 
37
  /// The diagnostic ID.
38
  mutable unsigned DiagID = 0;
39
public:
40
  struct NullDiagnostic {};
41
 
42
  /// Create a null partial diagnostic, which cannot carry a payload,
43
  /// and only exists to be swapped with a real partial diagnostic.
44
  PartialDiagnostic(NullDiagnostic) {}
45
 
46
  PartialDiagnostic(unsigned DiagID, DiagStorageAllocator &Allocator_)
47
      : StreamingDiagnostic(Allocator_), DiagID(DiagID) {}
48
 
49
  PartialDiagnostic(const PartialDiagnostic &Other)
50
      : StreamingDiagnostic(), DiagID(Other.DiagID) {
51
    Allocator = Other.Allocator;
52
    if (Other.DiagStorage) {
53
      DiagStorage = getStorage();
54
      *DiagStorage = *Other.DiagStorage;
55
    }
56
  }
57
 
58
  template <typename T> const PartialDiagnostic &operator<<(const T &V) const {
59
    const StreamingDiagnostic &DB = *this;
60
    DB << V;
61
    return *this;
62
  }
63
 
64
  // It is necessary to limit this to rvalue reference to avoid calling this
65
  // function with a bitfield lvalue argument since non-const reference to
66
  // bitfield is not allowed.
67
  template <typename T,
68
            typename = std::enable_if_t<!std::is_lvalue_reference<T>::value>>
69
  const PartialDiagnostic &operator<<(T &&V) const {
70
    const StreamingDiagnostic &DB = *this;
71
    DB << std::move(V);
72
    return *this;
73
  }
74
 
75
  PartialDiagnostic(PartialDiagnostic &&Other) : DiagID(Other.DiagID) {
76
    Allocator = Other.Allocator;
77
    DiagStorage = Other.DiagStorage;
78
    Other.DiagStorage = nullptr;
79
  }
80
 
81
  PartialDiagnostic(const PartialDiagnostic &Other,
82
                    DiagnosticStorage *DiagStorage_)
83
      : DiagID(Other.DiagID) {
84
    Allocator = reinterpret_cast<DiagStorageAllocator *>(~uintptr_t(0));
85
    DiagStorage = DiagStorage_;
86
    if (Other.DiagStorage)
87
      *this->DiagStorage = *Other.DiagStorage;
88
  }
89
 
90
  PartialDiagnostic(const Diagnostic &Other, DiagStorageAllocator &Allocator_)
91
      : DiagID(Other.getID()) {
92
    Allocator = &Allocator_;
93
    // Copy arguments.
94
    for (unsigned I = 0, N = Other.getNumArgs(); I != N; ++I) {
95
      if (Other.getArgKind(I) == DiagnosticsEngine::ak_std_string)
96
        AddString(Other.getArgStdStr(I));
97
      else
98
        AddTaggedVal(Other.getRawArg(I), Other.getArgKind(I));
99
    }
100
 
101
    // Copy source ranges.
102
    for (unsigned I = 0, N = Other.getNumRanges(); I != N; ++I)
103
      AddSourceRange(Other.getRange(I));
104
 
105
    // Copy fix-its.
106
    for (unsigned I = 0, N = Other.getNumFixItHints(); I != N; ++I)
107
      AddFixItHint(Other.getFixItHint(I));
108
  }
109
 
110
  PartialDiagnostic &operator=(const PartialDiagnostic &Other) {
111
    DiagID = Other.DiagID;
112
    if (Other.DiagStorage) {
113
      if (!DiagStorage)
114
        DiagStorage = getStorage();
115
 
116
      *DiagStorage = *Other.DiagStorage;
117
    } else {
118
      freeStorage();
119
    }
120
 
121
    return *this;
122
  }
123
 
124
  PartialDiagnostic &operator=(PartialDiagnostic &&Other) {
125
    freeStorage();
126
 
127
    DiagID = Other.DiagID;
128
    DiagStorage = Other.DiagStorage;
129
    Allocator = Other.Allocator;
130
 
131
    Other.DiagStorage = nullptr;
132
    return *this;
133
  }
134
 
135
  void swap(PartialDiagnostic &PD) {
136
    std::swap(DiagID, PD.DiagID);
137
    std::swap(DiagStorage, PD.DiagStorage);
138
    std::swap(Allocator, PD.Allocator);
139
  }
140
 
141
  unsigned getDiagID() const { return DiagID; }
142
  void setDiagID(unsigned ID) { DiagID = ID; }
143
 
144
  void Emit(const DiagnosticBuilder &DB) const {
145
    if (!DiagStorage)
146
      return;
147
 
148
    // Add all arguments.
149
    for (unsigned i = 0, e = DiagStorage->NumDiagArgs; i != e; ++i) {
150
      if ((DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i]
151
            == DiagnosticsEngine::ak_std_string)
152
        DB.AddString(DiagStorage->DiagArgumentsStr[i]);
153
      else
154
        DB.AddTaggedVal(DiagStorage->DiagArgumentsVal[i],
155
            (DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i]);
156
    }
157
 
158
    // Add all ranges.
159
    for (const CharSourceRange &Range : DiagStorage->DiagRanges)
160
      DB.AddSourceRange(Range);
161
 
162
    // Add all fix-its.
163
    for (const FixItHint &Fix : DiagStorage->FixItHints)
164
      DB.AddFixItHint(Fix);
165
  }
166
 
167
  void EmitToString(DiagnosticsEngine &Diags,
168
                    SmallVectorImpl<char> &Buf) const {
169
    // FIXME: It should be possible to render a diagnostic to a string without
170
    //        messing with the state of the diagnostics engine.
171
    DiagnosticBuilder DB(Diags.Report(getDiagID()));
172
    Emit(DB);
173
    Diagnostic(&Diags).FormatDiagnostic(Buf);
174
    DB.Clear();
175
    Diags.Clear();
176
  }
177
 
178
  /// Clear out this partial diagnostic, giving it a new diagnostic ID
179
  /// and removing all of its arguments, ranges, and fix-it hints.
180
  void Reset(unsigned DiagID = 0) {
181
    this->DiagID = DiagID;
182
    freeStorage();
183
  }
184
 
185
  bool hasStorage() const { return DiagStorage != nullptr; }
186
 
187
  /// Retrieve the string argument at the given index.
188
  StringRef getStringArg(unsigned I) {
189
    assert(DiagStorage && "No diagnostic storage?");
190
    assert(I < DiagStorage->NumDiagArgs && "Not enough diagnostic args");
191
    assert(DiagStorage->DiagArgumentsKind[I]
192
             == DiagnosticsEngine::ak_std_string && "Not a string arg");
193
    return DiagStorage->DiagArgumentsStr[I];
194
  }
195
};
196
 
197
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
198
                                           const PartialDiagnostic &PD) {
199
  PD.Emit(DB);
200
  return DB;
201
}
202
 
203
/// A partial diagnostic along with the source location where this
204
/// diagnostic occurs.
205
using PartialDiagnosticAt = std::pair<SourceLocation, PartialDiagnostic>;
206
 
207
} // namespace clang
208
 
209
#endif // LLVM_CLANG_BASIC_PARTIALDIAGNOSTIC_H