177 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			177 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C++
		
	
	
	
//===- ASTImporterLookupTable.cpp - ASTImporter specific lookup -----------===//
 | 
						|
//
 | 
						|
// 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 the ASTImporterLookupTable class which implements a
 | 
						|
//  lookup procedure for the import mechanism.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "clang/AST/ASTImporterLookupTable.h"
 | 
						|
#include "clang/AST/Decl.h"
 | 
						|
#include "clang/AST/RecursiveASTVisitor.h"
 | 
						|
 | 
						|
namespace clang {
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
struct Builder : RecursiveASTVisitor<Builder> {
 | 
						|
  ASTImporterLookupTable <
 | 
						|
  Builder(ASTImporterLookupTable <) : LT(LT) {}
 | 
						|
 | 
						|
  bool VisitTypedefNameDecl(TypedefNameDecl *D) {
 | 
						|
    QualType Ty = D->getUnderlyingType();
 | 
						|
    Ty = Ty.getCanonicalType();
 | 
						|
    if (const auto *RTy = dyn_cast<RecordType>(Ty)) {
 | 
						|
      LT.add(RTy->getAsRecordDecl());
 | 
						|
      // iterate over the field decls, adding them
 | 
						|
      for (auto *it : RTy->getAsRecordDecl()->fields()) {
 | 
						|
        LT.add(it);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  bool VisitNamedDecl(NamedDecl *D) {
 | 
						|
    LT.add(D);
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
  // In most cases the FriendDecl contains the declaration of the befriended
 | 
						|
  // class as a child node, so it is discovered during the recursive
 | 
						|
  // visitation. However, there are cases when the befriended class is not a
 | 
						|
  // child, thus it must be fetched explicitly from the FriendDecl, and only
 | 
						|
  // then can we add it to the lookup table.
 | 
						|
  bool VisitFriendDecl(FriendDecl *D) {
 | 
						|
    if (D->getFriendType()) {
 | 
						|
      QualType Ty = D->getFriendType()->getType();
 | 
						|
      if (isa<ElaboratedType>(Ty))
 | 
						|
        Ty = cast<ElaboratedType>(Ty)->getNamedType();
 | 
						|
      // A FriendDecl with a dependent type (e.g. ClassTemplateSpecialization)
 | 
						|
      // always has that decl as child node.
 | 
						|
      // However, there are non-dependent cases which does not have the
 | 
						|
      // type as a child node. We have to dig up that type now.
 | 
						|
      if (!Ty->isDependentType()) {
 | 
						|
        if (const auto *RTy = dyn_cast<RecordType>(Ty))
 | 
						|
          LT.add(RTy->getAsCXXRecordDecl());
 | 
						|
        else if (const auto *SpecTy = dyn_cast<TemplateSpecializationType>(Ty))
 | 
						|
          LT.add(SpecTy->getAsCXXRecordDecl());
 | 
						|
        else if (const auto *SubstTy =
 | 
						|
                     dyn_cast<SubstTemplateTypeParmType>(Ty)) {
 | 
						|
          if (SubstTy->getAsCXXRecordDecl())
 | 
						|
            LT.add(SubstTy->getAsCXXRecordDecl());
 | 
						|
        } else if (isa<TypedefType>(Ty)) {
 | 
						|
          // We do not put friend typedefs to the lookup table because
 | 
						|
          // ASTImporter does not organize typedefs into redecl chains.
 | 
						|
        } else {
 | 
						|
          llvm_unreachable("Unhandled type of friend class");
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  // Override default settings of base.
 | 
						|
  bool shouldVisitTemplateInstantiations() const { return true; }
 | 
						|
  bool shouldVisitImplicitCode() const { return true; }
 | 
						|
};
 | 
						|
 | 
						|
} // anonymous namespace
 | 
						|
 | 
						|
ASTImporterLookupTable::ASTImporterLookupTable(TranslationUnitDecl &TU) {
 | 
						|
  Builder B(*this);
 | 
						|
  B.TraverseDecl(&TU);
 | 
						|
}
 | 
						|
 | 
						|
void ASTImporterLookupTable::add(DeclContext *DC, NamedDecl *ND) {
 | 
						|
  DeclList &Decls = LookupTable[DC][ND->getDeclName()];
 | 
						|
  // Inserts if and only if there is no element in the container equal to it.
 | 
						|
  Decls.insert(ND);
 | 
						|
}
 | 
						|
 | 
						|
void ASTImporterLookupTable::remove(DeclContext *DC, NamedDecl *ND) {
 | 
						|
  DeclList &Decls = LookupTable[DC][ND->getDeclName()];
 | 
						|
  bool EraseResult = Decls.remove(ND);
 | 
						|
  (void)EraseResult;
 | 
						|
  assert(EraseResult == true && "Trying to remove not contained Decl");
 | 
						|
}
 | 
						|
 | 
						|
void ASTImporterLookupTable::add(NamedDecl *ND) {
 | 
						|
  assert(ND);
 | 
						|
  DeclContext *DC = ND->getDeclContext()->getPrimaryContext();
 | 
						|
  add(DC, ND);
 | 
						|
  DeclContext *ReDC = DC->getRedeclContext()->getPrimaryContext();
 | 
						|
  if (DC != ReDC)
 | 
						|
    add(ReDC, ND);
 | 
						|
}
 | 
						|
 | 
						|
void ASTImporterLookupTable::remove(NamedDecl *ND) {
 | 
						|
  assert(ND);
 | 
						|
  DeclContext *DC = ND->getDeclContext()->getPrimaryContext();
 | 
						|
  remove(DC, ND);
 | 
						|
  DeclContext *ReDC = DC->getRedeclContext()->getPrimaryContext();
 | 
						|
  if (DC != ReDC)
 | 
						|
    remove(ReDC, ND);
 | 
						|
}
 | 
						|
 | 
						|
void ASTImporterLookupTable::update(NamedDecl *ND, DeclContext *OldDC) {
 | 
						|
  assert(OldDC != ND->getDeclContext() &&
 | 
						|
         "DeclContext should be changed before update");
 | 
						|
  if (contains(ND->getDeclContext(), ND)) {
 | 
						|
    assert(!contains(OldDC, ND) &&
 | 
						|
           "Decl should not be found in the old context if already in the new");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  remove(OldDC, ND);
 | 
						|
  add(ND);
 | 
						|
}
 | 
						|
 | 
						|
ASTImporterLookupTable::LookupResult
 | 
						|
ASTImporterLookupTable::lookup(DeclContext *DC, DeclarationName Name) const {
 | 
						|
  auto DCI = LookupTable.find(DC->getPrimaryContext());
 | 
						|
  if (DCI == LookupTable.end())
 | 
						|
    return {};
 | 
						|
 | 
						|
  const auto &FoundNameMap = DCI->second;
 | 
						|
  auto NamesI = FoundNameMap.find(Name);
 | 
						|
  if (NamesI == FoundNameMap.end())
 | 
						|
    return {};
 | 
						|
 | 
						|
  return NamesI->second;
 | 
						|
}
 | 
						|
 | 
						|
bool ASTImporterLookupTable::contains(DeclContext *DC, NamedDecl *ND) const {
 | 
						|
  return lookup(DC, ND->getDeclName()).contains(ND);
 | 
						|
}
 | 
						|
 | 
						|
void ASTImporterLookupTable::dump(DeclContext *DC) const {
 | 
						|
  auto DCI = LookupTable.find(DC->getPrimaryContext());
 | 
						|
  if (DCI == LookupTable.end())
 | 
						|
    llvm::errs() << "empty\n";
 | 
						|
  const auto &FoundNameMap = DCI->second;
 | 
						|
  for (const auto &Entry : FoundNameMap) {
 | 
						|
    DeclarationName Name = Entry.first;
 | 
						|
    llvm::errs() << "==== Name: ";
 | 
						|
    Name.dump();
 | 
						|
    const DeclList& List = Entry.second;
 | 
						|
    for (NamedDecl *ND : List) {
 | 
						|
      ND->dump();
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ASTImporterLookupTable::dump() const {
 | 
						|
  for (const auto &Entry : LookupTable) {
 | 
						|
    DeclContext *DC = Entry.first;
 | 
						|
    StringRef Primary = DC->getPrimaryContext() ? " primary" : "";
 | 
						|
    llvm::errs() << "== DC:" << cast<Decl>(DC) << Primary << "\n";
 | 
						|
    dump(DC);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
} // namespace clang
 |