blob: 18276d54d540471473c736d8b64b2f045c428d32 [file] [log] [blame]
//==- DependentDiagnostic.h - Dependently-generated diagnostics --*- C++ -*-==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines interfaces for diagnostics which may or may
// fire based on how a template is instantiated.
//
// At the moment, the only consumer of this interface is access
// control.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_DEPENDENTDIAGNOSTIC_H
#define LLVM_CLANG_AST_DEPENDENTDIAGNOSTIC_H
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/Type.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include <cassert>
#include <iterator>
namespace clang {
class ASTContext;
class CXXRecordDecl;
class NamedDecl;
/// A dependently-generated diagnostic.
class DependentDiagnostic {
public:
enum AccessNonce { Access = 0 };
static DependentDiagnostic *Create(ASTContext &Context,
DeclContext *Parent,
AccessNonce _,
SourceLocation Loc,
bool IsMemberAccess,
AccessSpecifier AS,
NamedDecl *TargetDecl,
CXXRecordDecl *NamingClass,
QualType BaseObjectType,
const PartialDiagnostic &PDiag) {
DependentDiagnostic *DD = Create(Context, Parent, PDiag);
DD->AccessData.Loc = Loc;
DD->AccessData.IsMember = IsMemberAccess;
DD->AccessData.Access = AS;
DD->AccessData.TargetDecl = TargetDecl;
DD->AccessData.NamingClass = NamingClass;
DD->AccessData.BaseObjectType = BaseObjectType.getAsOpaquePtr();
return DD;
}
unsigned getKind() const {
return Access;
}
bool isAccessToMember() const {
assert(getKind() == Access);
return AccessData.IsMember;
}
AccessSpecifier getAccess() const {
assert(getKind() == Access);
return AccessSpecifier(AccessData.Access);
}
SourceLocation getAccessLoc() const {
assert(getKind() == Access);
return AccessData.Loc;
}
NamedDecl *getAccessTarget() const {
assert(getKind() == Access);
return AccessData.TargetDecl;
}
NamedDecl *getAccessNamingClass() const {
assert(getKind() == Access);
return AccessData.NamingClass;
}
QualType getAccessBaseObjectType() const {
assert(getKind() == Access);
return QualType::getFromOpaquePtr(AccessData.BaseObjectType);
}
const PartialDiagnostic &getDiagnostic() const {
return Diag;
}
private:
friend class DeclContext::ddiag_iterator;
friend class DependentStoredDeclsMap;
DependentDiagnostic(const PartialDiagnostic &PDiag,
DiagnosticStorage *Storage)
: Diag(PDiag, Storage) {}
static DependentDiagnostic *Create(ASTContext &Context,
DeclContext *Parent,
const PartialDiagnostic &PDiag);
DependentDiagnostic *NextDiagnostic;
PartialDiagnostic Diag;
struct {
SourceLocation Loc;
unsigned Access : 2;
unsigned IsMember : 1;
NamedDecl *TargetDecl;
CXXRecordDecl *NamingClass;
void *BaseObjectType;
} AccessData;
};
/// An iterator over the dependent diagnostics in a dependent context.
class DeclContext::ddiag_iterator {
public:
ddiag_iterator() = default;
explicit ddiag_iterator(DependentDiagnostic *Ptr) : Ptr(Ptr) {}
using value_type = DependentDiagnostic *;
using reference = DependentDiagnostic *;
using pointer = DependentDiagnostic *;
using difference_type = int;
using iterator_category = std::forward_iterator_tag;
reference operator*() const { return Ptr; }
ddiag_iterator &operator++() {
assert(Ptr && "attempt to increment past end of diag list");
Ptr = Ptr->NextDiagnostic;
return *this;
}
ddiag_iterator operator++(int) {
ddiag_iterator tmp = *this;
++*this;
return tmp;
}
bool operator==(ddiag_iterator Other) const {
return Ptr == Other.Ptr;
}
bool operator!=(ddiag_iterator Other) const {
return Ptr != Other.Ptr;
}
ddiag_iterator &operator+=(difference_type N) {
assert(N >= 0 && "cannot rewind a DeclContext::ddiag_iterator");
while (N--)
++*this;
return *this;
}
ddiag_iterator operator+(difference_type N) const {
ddiag_iterator tmp = *this;
tmp += N;
return tmp;
}
private:
DependentDiagnostic *Ptr = nullptr;
};
inline DeclContext::ddiag_range DeclContext::ddiags() const {
assert(isDependentContext()
&& "cannot iterate dependent diagnostics of non-dependent context");
const DependentStoredDeclsMap *Map
= static_cast<DependentStoredDeclsMap*>(getPrimaryContext()->getLookupPtr());
if (!Map)
// Return an empty range using the always-end default constructor.
return ddiag_range(ddiag_iterator(), ddiag_iterator());
return ddiag_range(ddiag_iterator(Map->FirstDiagnostic), ddiag_iterator());
}
} // namespace clang
#endif // LLVM_CLANG_AST_DEPENDENTDIAGNOSTIC_H