ASTImporterLookupTable.cpp revision 355940
1//===- ASTImporterLookupTable.cpp - ASTImporter specific lookup -----------===//
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 ASTImporterLookupTable class which implements a
10//  lookup procedure for the import mechanism.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/AST/ASTImporterLookupTable.h"
15#include "clang/AST/Decl.h"
16#include "clang/AST/RecursiveASTVisitor.h"
17
18namespace clang {
19
20namespace {
21
22struct Builder : RecursiveASTVisitor<Builder> {
23  ASTImporterLookupTable &LT;
24  Builder(ASTImporterLookupTable &LT) : LT(LT) {}
25  bool VisitNamedDecl(NamedDecl *D) {
26    LT.add(D);
27    return true;
28  }
29  // In most cases the FriendDecl contains the declaration of the befriended
30  // class as a child node, so it is discovered during the recursive
31  // visitation. However, there are cases when the befriended class is not a
32  // child, thus it must be fetched explicitly from the FriendDecl, and only
33  // then can we add it to the lookup table.
34  bool VisitFriendDecl(FriendDecl *D) {
35    if (D->getFriendType()) {
36      QualType Ty = D->getFriendType()->getType();
37      if (isa<ElaboratedType>(Ty))
38        Ty = cast<ElaboratedType>(Ty)->getNamedType();
39      // A FriendDecl with a dependent type (e.g. ClassTemplateSpecialization)
40      // always has that decl as child node.
41      // However, there are non-dependent cases which does not have the
42      // type as a child node. We have to dig up that type now.
43      if (!Ty->isDependentType()) {
44        if (const auto *RTy = dyn_cast<RecordType>(Ty))
45          LT.add(RTy->getAsCXXRecordDecl());
46        else if (const auto *SpecTy = dyn_cast<TemplateSpecializationType>(Ty))
47          LT.add(SpecTy->getAsCXXRecordDecl());
48        else if (isa<TypedefType>(Ty)) {
49          // We do not put friend typedefs to the lookup table because
50          // ASTImporter does not organize typedefs into redecl chains.
51        } else {
52          llvm_unreachable("Unhandled type of friend class");
53        }
54      }
55    }
56    return true;
57  }
58
59  // Override default settings of base.
60  bool shouldVisitTemplateInstantiations() const { return true; }
61  bool shouldVisitImplicitCode() const { return true; }
62};
63
64} // anonymous namespace
65
66ASTImporterLookupTable::ASTImporterLookupTable(TranslationUnitDecl &TU) {
67  Builder B(*this);
68  B.TraverseDecl(&TU);
69}
70
71void ASTImporterLookupTable::add(DeclContext *DC, NamedDecl *ND) {
72  DeclList &Decls = LookupTable[DC][ND->getDeclName()];
73  // Inserts if and only if there is no element in the container equal to it.
74  Decls.insert(ND);
75}
76
77void ASTImporterLookupTable::remove(DeclContext *DC, NamedDecl *ND) {
78  DeclList &Decls = LookupTable[DC][ND->getDeclName()];
79  bool EraseResult = Decls.remove(ND);
80  (void)EraseResult;
81  assert(EraseResult == true && "Trying to remove not contained Decl");
82}
83
84void ASTImporterLookupTable::add(NamedDecl *ND) {
85  assert(ND);
86  DeclContext *DC = ND->getDeclContext()->getPrimaryContext();
87  add(DC, ND);
88  DeclContext *ReDC = DC->getRedeclContext()->getPrimaryContext();
89  if (DC != ReDC)
90    add(ReDC, ND);
91}
92
93void ASTImporterLookupTable::remove(NamedDecl *ND) {
94  assert(ND);
95  DeclContext *DC = ND->getDeclContext()->getPrimaryContext();
96  remove(DC, ND);
97  DeclContext *ReDC = DC->getRedeclContext()->getPrimaryContext();
98  if (DC != ReDC)
99    remove(ReDC, ND);
100}
101
102ASTImporterLookupTable::LookupResult
103ASTImporterLookupTable::lookup(DeclContext *DC, DeclarationName Name) const {
104  auto DCI = LookupTable.find(DC->getPrimaryContext());
105  if (DCI == LookupTable.end())
106    return {};
107
108  const auto &FoundNameMap = DCI->second;
109  auto NamesI = FoundNameMap.find(Name);
110  if (NamesI == FoundNameMap.end())
111    return {};
112
113  return NamesI->second;
114}
115
116void ASTImporterLookupTable::dump(DeclContext *DC) const {
117  auto DCI = LookupTable.find(DC->getPrimaryContext());
118  if (DCI == LookupTable.end())
119    llvm::errs() << "empty\n";
120  const auto &FoundNameMap = DCI->second;
121  for (const auto &Entry : FoundNameMap) {
122    DeclarationName Name = Entry.first;
123    llvm::errs() << "==== Name: ";
124    Name.dump();
125    const DeclList& List = Entry.second;
126    for (NamedDecl *ND : List) {
127      ND->dump();
128    }
129  }
130}
131
132void ASTImporterLookupTable::dump() const {
133  for (const auto &Entry : LookupTable) {
134    DeclContext *DC = Entry.first;
135    StringRef Primary = DC->getPrimaryContext() ? " primary" : "";
136    llvm::errs() << "== DC:" << cast<Decl>(DC) << Primary << "\n";
137    dump(DC);
138  }
139}
140
141} // namespace clang
142