1//===- DeclFriend.cpp - C++ Friend Declaration AST Node Implementation ----===//
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 implements the AST classes related to C++ friend
10// declarations.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/AST/DeclFriend.h"
15#include "clang/AST/ASTContext.h"
16#include "clang/AST/DeclCXX.h"
17#include "clang/AST/DeclTemplate.h"
18#include "clang/AST/ExternalASTSource.h"
19#include <cassert>
20
21using namespace clang;
22
23void FriendDecl::anchor() {}
24
25FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
26 FriendUnion Friend, SourceLocation FriendL,
27 SourceLocation EllipsisLoc) {
28#ifndef NDEBUG
29 if (const auto *D = dyn_cast<NamedDecl *>(Friend)) {
30 assert(isa<FunctionDecl>(D) ||
31 isa<CXXRecordDecl>(D) ||
32 isa<FunctionTemplateDecl>(D) ||
33 isa<ClassTemplateDecl>(D));
34
35 // As a temporary hack, we permit template instantiation to point
36 // to the original declaration when instantiating members.
37 assert(D->getFriendObjectKind() ||
38 (cast<CXXRecordDecl>(DC)->getTemplateSpecializationKind()));
39 }
40#endif
41
42 auto *FD =
43 new (C, DC) FriendDecl(Decl::Friend, DC, L, Friend, FriendL, EllipsisLoc);
44 cast<CXXRecordDecl>(Val: DC)->pushFriendDecl(FD);
45 return FD;
46}
47
48FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) {
49 return new (C, ID) FriendDecl(Decl::Friend, EmptyShell());
50}
51
52FriendDecl *FriendDecl::getNextFriendSlowCase() {
53 return cast_or_null<FriendDecl>(
54 Val: NextFriend.get(Source: getASTContext().getExternalSource()));
55}
56
57FriendDecl *CXXRecordDecl::getFirstFriend() const {
58 ExternalASTSource *Source = getParentASTContext().getExternalSource();
59 Decl *First = data().FirstFriend.get(Source);
60 return First ? cast<FriendDecl>(Val: First) : nullptr;
61}
62
63void CXXRecordDecl::loadLazyFriends() {
64 assert(hasDefinition());
65 assert(hasLazyFriends());
66 ExternalASTSource *Source = getParentASTContext().getExternalSource();
67 FriendDecl *Friend = cast_or_null<FriendDecl>(Val: data().FirstFriend.get(Source));
68 while (Friend && Friend->NextFriend.isOffset())
69 Friend = cast_or_null<FriendDecl>(Val: Friend->NextFriend.get(Source));
70}
71
72SourceRange FriendDecl::getSourceRange() const {
73 if (TypeSourceInfo *TInfo = getFriendType()) {
74 SourceLocation EndL =
75 isPackExpansion() ? getEllipsisLoc() : TInfo->getTypeLoc().getEndLoc();
76 return SourceRange(getFriendLoc(), EndL);
77 }
78
79 if (isPackExpansion())
80 return SourceRange(getFriendLoc(), getEllipsisLoc());
81
82 if (NamedDecl *ND = getFriendDecl()) {
83 if (const auto *FD = dyn_cast<FunctionDecl>(Val: ND))
84 return FD->getSourceRange();
85 if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(Val: ND))
86 return FTD->getSourceRange();
87 if (const auto *CTD = dyn_cast<ClassTemplateDecl>(Val: ND))
88 return CTD->getSourceRange();
89 if (const auto *DD = dyn_cast<DeclaratorDecl>(Val: ND)) {
90 if (DD->getOuterLocStart() != DD->getInnerLocStart())
91 return DD->getSourceRange();
92 }
93 return SourceRange(getFriendLoc(), ND->getEndLoc());
94 }
95 return SourceRange(getFriendLoc(), getLocation());
96}
97