Home | History | Annotate | Line # | Download | only in AST
      1 //===- DeclFriend.h - Classes for C++ friend declarations -------*- 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 the section of the AST representing C++ friend
     10 // declarations.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #ifndef LLVM_CLANG_AST_DECLFRIEND_H
     15 #define LLVM_CLANG_AST_DECLFRIEND_H
     16 
     17 #include "clang/AST/Decl.h"
     18 #include "clang/AST/DeclBase.h"
     19 #include "clang/AST/DeclCXX.h"
     20 #include "clang/AST/DeclTemplate.h"
     21 #include "clang/AST/ExternalASTSource.h"
     22 #include "clang/AST/TypeLoc.h"
     23 #include "clang/Basic/LLVM.h"
     24 #include "clang/Basic/SourceLocation.h"
     25 #include "llvm/ADT/ArrayRef.h"
     26 #include "llvm/ADT/None.h"
     27 #include "llvm/ADT/PointerUnion.h"
     28 #include "llvm/Support/Casting.h"
     29 #include "llvm/Support/Compiler.h"
     30 #include "llvm/Support/TrailingObjects.h"
     31 #include <cassert>
     32 #include <iterator>
     33 
     34 namespace clang {
     35 
     36 class ASTContext;
     37 
     38 /// FriendDecl - Represents the declaration of a friend entity,
     39 /// which can be a function, a type, or a templated function or type.
     40 /// For example:
     41 ///
     42 /// @code
     43 /// template <typename T> class A {
     44 ///   friend int foo(T);
     45 ///   friend class B;
     46 ///   friend T; // only in C++0x
     47 ///   template <typename U> friend class C;
     48 ///   template <typename U> friend A& operator+=(A&, const U&) { ... }
     49 /// };
     50 /// @endcode
     51 ///
     52 /// The semantic context of a friend decl is its declaring class.
     53 class FriendDecl final
     54     : public Decl,
     55       private llvm::TrailingObjects<FriendDecl, TemplateParameterList *> {
     56   virtual void anchor();
     57 
     58 public:
     59   using FriendUnion = llvm::PointerUnion<NamedDecl *, TypeSourceInfo *>;
     60 
     61 private:
     62   friend class CXXRecordDecl;
     63   friend class CXXRecordDecl::friend_iterator;
     64 
     65   // The declaration that's a friend of this class.
     66   FriendUnion Friend;
     67 
     68   // A pointer to the next friend in the sequence.
     69   LazyDeclPtr NextFriend;
     70 
     71   // Location of the 'friend' specifier.
     72   SourceLocation FriendLoc;
     73 
     74   /// True if this 'friend' declaration is unsupported.  Eventually we
     75   /// will support every possible friend declaration, but for now we
     76   /// silently ignore some and set this flag to authorize all access.
     77   unsigned UnsupportedFriend : 1;
     78 
     79   // The number of "outer" template parameter lists in non-templatic
     80   // (currently unsupported) friend type declarations, such as
     81   //     template <class T> friend class A<T>::B;
     82   unsigned NumTPLists : 31;
     83 
     84   FriendDecl(DeclContext *DC, SourceLocation L, FriendUnion Friend,
     85              SourceLocation FriendL,
     86              ArrayRef<TemplateParameterList *> FriendTypeTPLists)
     87       : Decl(Decl::Friend, DC, L), Friend(Friend), FriendLoc(FriendL),
     88         UnsupportedFriend(false), NumTPLists(FriendTypeTPLists.size()) {
     89     for (unsigned i = 0; i < NumTPLists; ++i)
     90       getTrailingObjects<TemplateParameterList *>()[i] = FriendTypeTPLists[i];
     91   }
     92 
     93   FriendDecl(EmptyShell Empty, unsigned NumFriendTypeTPLists)
     94       : Decl(Decl::Friend, Empty), UnsupportedFriend(false),
     95         NumTPLists(NumFriendTypeTPLists) {}
     96 
     97   FriendDecl *getNextFriend() {
     98     if (!NextFriend.isOffset())
     99       return cast_or_null<FriendDecl>(NextFriend.get(nullptr));
    100     return getNextFriendSlowCase();
    101   }
    102 
    103   FriendDecl *getNextFriendSlowCase();
    104 
    105 public:
    106   friend class ASTDeclReader;
    107   friend class ASTDeclWriter;
    108   friend class ASTNodeImporter;
    109   friend TrailingObjects;
    110 
    111   static FriendDecl *Create(ASTContext &C, DeclContext *DC,
    112                             SourceLocation L, FriendUnion Friend_,
    113                             SourceLocation FriendL,
    114                             ArrayRef<TemplateParameterList*> FriendTypeTPLists
    115                             = None);
    116   static FriendDecl *CreateDeserialized(ASTContext &C, unsigned ID,
    117                                         unsigned FriendTypeNumTPLists);
    118 
    119   /// If this friend declaration names an (untemplated but possibly
    120   /// dependent) type, return the type; otherwise return null.  This
    121   /// is used for elaborated-type-specifiers and, in C++0x, for
    122   /// arbitrary friend type declarations.
    123   TypeSourceInfo *getFriendType() const {
    124     return Friend.dyn_cast<TypeSourceInfo*>();
    125   }
    126 
    127   unsigned getFriendTypeNumTemplateParameterLists() const {
    128     return NumTPLists;
    129   }
    130 
    131   TemplateParameterList *getFriendTypeTemplateParameterList(unsigned N) const {
    132     assert(N < NumTPLists);
    133     return getTrailingObjects<TemplateParameterList *>()[N];
    134   }
    135 
    136   /// If this friend declaration doesn't name a type, return the inner
    137   /// declaration.
    138   NamedDecl *getFriendDecl() const {
    139     return Friend.dyn_cast<NamedDecl *>();
    140   }
    141 
    142   /// Retrieves the location of the 'friend' keyword.
    143   SourceLocation getFriendLoc() const {
    144     return FriendLoc;
    145   }
    146 
    147   /// Retrieves the source range for the friend declaration.
    148   SourceRange getSourceRange() const override LLVM_READONLY {
    149     if (NamedDecl *ND = getFriendDecl()) {
    150       if (const auto *FD = dyn_cast<FunctionDecl>(ND))
    151         return FD->getSourceRange();
    152       if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(ND))
    153         return FTD->getSourceRange();
    154       if (const auto *CTD = dyn_cast<ClassTemplateDecl>(ND))
    155         return CTD->getSourceRange();
    156       if (const auto *DD = dyn_cast<DeclaratorDecl>(ND)) {
    157         if (DD->getOuterLocStart() != DD->getInnerLocStart())
    158           return DD->getSourceRange();
    159       }
    160       return SourceRange(getFriendLoc(), ND->getEndLoc());
    161     }
    162     else if (TypeSourceInfo *TInfo = getFriendType()) {
    163       SourceLocation StartL =
    164           (NumTPLists == 0) ? getFriendLoc()
    165                             : getTrailingObjects<TemplateParameterList *>()[0]
    166                                   ->getTemplateLoc();
    167       return SourceRange(StartL, TInfo->getTypeLoc().getEndLoc());
    168     }
    169     else
    170       return SourceRange(getFriendLoc(), getLocation());
    171   }
    172 
    173   /// Determines if this friend kind is unsupported.
    174   bool isUnsupportedFriend() const {
    175     return UnsupportedFriend;
    176   }
    177   void setUnsupportedFriend(bool Unsupported) {
    178     UnsupportedFriend = Unsupported;
    179   }
    180 
    181   // Implement isa/cast/dyncast/etc.
    182   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
    183   static bool classofKind(Kind K) { return K == Decl::Friend; }
    184 };
    185 
    186 /// An iterator over the friend declarations of a class.
    187 class CXXRecordDecl::friend_iterator {
    188   friend class CXXRecordDecl;
    189 
    190   FriendDecl *Ptr;
    191 
    192   explicit friend_iterator(FriendDecl *Ptr) : Ptr(Ptr) {}
    193 
    194 public:
    195   friend_iterator() = default;
    196 
    197   using value_type = FriendDecl *;
    198   using reference = FriendDecl *;
    199   using pointer = FriendDecl *;
    200   using difference_type = int;
    201   using iterator_category = std::forward_iterator_tag;
    202 
    203   reference operator*() const { return Ptr; }
    204 
    205   friend_iterator &operator++() {
    206     assert(Ptr && "attempt to increment past end of friend list");
    207     Ptr = Ptr->getNextFriend();
    208     return *this;
    209   }
    210 
    211   friend_iterator operator++(int) {
    212     friend_iterator tmp = *this;
    213     ++*this;
    214     return tmp;
    215   }
    216 
    217   bool operator==(const friend_iterator &Other) const {
    218     return Ptr == Other.Ptr;
    219   }
    220 
    221   bool operator!=(const friend_iterator &Other) const {
    222     return Ptr != Other.Ptr;
    223   }
    224 
    225   friend_iterator &operator+=(difference_type N) {
    226     assert(N >= 0 && "cannot rewind a CXXRecordDecl::friend_iterator");
    227     while (N--)
    228       ++*this;
    229     return *this;
    230   }
    231 
    232   friend_iterator operator+(difference_type N) const {
    233     friend_iterator tmp = *this;
    234     tmp += N;
    235     return tmp;
    236   }
    237 };
    238 
    239 inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_begin() const {
    240   return friend_iterator(getFirstFriend());
    241 }
    242 
    243 inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_end() const {
    244   return friend_iterator(nullptr);
    245 }
    246 
    247 inline CXXRecordDecl::friend_range CXXRecordDecl::friends() const {
    248   return friend_range(friend_begin(), friend_end());
    249 }
    250 
    251 inline void CXXRecordDecl::pushFriendDecl(FriendDecl *FD) {
    252   assert(!FD->NextFriend && "friend already has next friend?");
    253   FD->NextFriend = data().FirstFriend;
    254   data().FirstFriend = FD;
    255 }
    256 
    257 } // namespace clang
    258 
    259 #endif // LLVM_CLANG_AST_DECLFRIEND_H
    260