1//==- DependentDiagnostic.h - Dependently-generated diagnostics --*- 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//  This file defines interfaces for diagnostics which may or may
10//  fire based on how a template is instantiated.
11//
12//  At the moment, the only consumer of this interface is access
13//  control.
14//
15//===----------------------------------------------------------------------===//
16
17#ifndef LLVM_CLANG_AST_DEPENDENTDIAGNOSTIC_H
18#define LLVM_CLANG_AST_DEPENDENTDIAGNOSTIC_H
19
20#include "clang/AST/DeclBase.h"
21#include "clang/AST/DeclContextInternals.h"
22#include "clang/AST/Type.h"
23#include "clang/Basic/PartialDiagnostic.h"
24#include "clang/Basic/SourceLocation.h"
25#include "clang/Basic/Specifiers.h"
26#include <cassert>
27#include <iterator>
28
29namespace clang {
30
31class ASTContext;
32class CXXRecordDecl;
33class NamedDecl;
34
35/// A dependently-generated diagnostic.
36class DependentDiagnostic {
37public:
38  enum AccessNonce { Access = 0 };
39
40  static DependentDiagnostic *Create(ASTContext &Context,
41                                     DeclContext *Parent,
42                                     AccessNonce _,
43                                     SourceLocation Loc,
44                                     bool IsMemberAccess,
45                                     AccessSpecifier AS,
46                                     NamedDecl *TargetDecl,
47                                     CXXRecordDecl *NamingClass,
48                                     QualType BaseObjectType,
49                                     const PartialDiagnostic &PDiag) {
50    DependentDiagnostic *DD = Create(Context, Parent, PDiag);
51    DD->AccessData.Loc = Loc;
52    DD->AccessData.IsMember = IsMemberAccess;
53    DD->AccessData.Access = AS;
54    DD->AccessData.TargetDecl = TargetDecl;
55    DD->AccessData.NamingClass = NamingClass;
56    DD->AccessData.BaseObjectType = BaseObjectType.getAsOpaquePtr();
57    return DD;
58  }
59
60  unsigned getKind() const {
61    return Access;
62  }
63
64  bool isAccessToMember() const {
65    assert(getKind() == Access);
66    return AccessData.IsMember;
67  }
68
69  AccessSpecifier getAccess() const {
70    assert(getKind() == Access);
71    return AccessSpecifier(AccessData.Access);
72  }
73
74  SourceLocation getAccessLoc() const {
75    assert(getKind() == Access);
76    return AccessData.Loc;
77  }
78
79  NamedDecl *getAccessTarget() const {
80    assert(getKind() == Access);
81    return AccessData.TargetDecl;
82  }
83
84  NamedDecl *getAccessNamingClass() const {
85    assert(getKind() == Access);
86    return AccessData.NamingClass;
87  }
88
89  QualType getAccessBaseObjectType() const {
90    assert(getKind() == Access);
91    return QualType::getFromOpaquePtr(AccessData.BaseObjectType);
92  }
93
94  const PartialDiagnostic &getDiagnostic() const {
95    return Diag;
96  }
97
98private:
99  friend class DeclContext::ddiag_iterator;
100  friend class DependentStoredDeclsMap;
101
102  DependentDiagnostic(const PartialDiagnostic &PDiag,
103                      DiagnosticStorage *Storage)
104      : Diag(PDiag, Storage) {}
105
106  static DependentDiagnostic *Create(ASTContext &Context,
107                                     DeclContext *Parent,
108                                     const PartialDiagnostic &PDiag);
109
110  DependentDiagnostic *NextDiagnostic;
111
112  PartialDiagnostic Diag;
113
114  struct {
115    SourceLocation Loc;
116    unsigned Access : 2;
117    unsigned IsMember : 1;
118    NamedDecl *TargetDecl;
119    CXXRecordDecl *NamingClass;
120    void *BaseObjectType;
121  } AccessData;
122};
123
124/// An iterator over the dependent diagnostics in a dependent context.
125class DeclContext::ddiag_iterator {
126public:
127  ddiag_iterator() = default;
128  explicit ddiag_iterator(DependentDiagnostic *Ptr) : Ptr(Ptr) {}
129
130  using value_type = DependentDiagnostic *;
131  using reference = DependentDiagnostic *;
132  using pointer = DependentDiagnostic *;
133  using difference_type = int;
134  using iterator_category = std::forward_iterator_tag;
135
136  reference operator*() const { return Ptr; }
137
138  ddiag_iterator &operator++() {
139    assert(Ptr && "attempt to increment past end of diag list");
140    Ptr = Ptr->NextDiagnostic;
141    return *this;
142  }
143
144  ddiag_iterator operator++(int) {
145    ddiag_iterator tmp = *this;
146    ++*this;
147    return tmp;
148  }
149
150  bool operator==(ddiag_iterator Other) const {
151    return Ptr == Other.Ptr;
152  }
153
154  bool operator!=(ddiag_iterator Other) const {
155    return Ptr != Other.Ptr;
156  }
157
158  ddiag_iterator &operator+=(difference_type N) {
159    assert(N >= 0 && "cannot rewind a DeclContext::ddiag_iterator");
160    while (N--)
161      ++*this;
162    return *this;
163  }
164
165  ddiag_iterator operator+(difference_type N) const {
166    ddiag_iterator tmp = *this;
167    tmp += N;
168    return tmp;
169  }
170
171private:
172  DependentDiagnostic *Ptr = nullptr;
173};
174
175inline DeclContext::ddiag_range DeclContext::ddiags() const {
176  assert(isDependentContext()
177         && "cannot iterate dependent diagnostics of non-dependent context");
178  const DependentStoredDeclsMap *Map
179    = static_cast<DependentStoredDeclsMap*>(getPrimaryContext()->getLookupPtr());
180
181  if (!Map)
182    // Return an empty range using the always-end default constructor.
183    return ddiag_range(ddiag_iterator(), ddiag_iterator());
184
185  return ddiag_range(ddiag_iterator(Map->FirstDiagnostic), ddiag_iterator());
186}
187
188} // namespace clang
189
190#endif // LLVM_CLANG_AST_DEPENDENTDIAGNOSTIC_H
191