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