brintos

brintos / llvm-project-archived public Read only

0
0
Text · 21.8 KiB · 15f8531 Raw
541 lines · cpp
1//===- ExternalASTMerger.cpp - Merging External AST Interface ---*- 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-exception6//7//===----------------------------------------------------------------------===//8//9//  This file implements the ExternalASTMerger, which vends a combination of10//  ASTs from several different ASTContext/FileManager pairs11//12//===----------------------------------------------------------------------===//13 14#include "clang/AST/ASTContext.h"15#include "clang/AST/Decl.h"16#include "clang/AST/DeclCXX.h"17#include "clang/AST/DeclObjC.h"18#include "clang/AST/DeclTemplate.h"19#include "clang/AST/ExternalASTMerger.h"20 21using namespace clang;22 23namespace {24 25template <typename T> struct Source {26  T t;27  Source(T t) : t(t) {}28  operator T() { return t; }29  template <typename U = T> U &get() { return t; }30  template <typename U = T> const U &get() const { return t; }31  template <typename U> operator Source<U>() { return Source<U>(t); }32};33 34typedef std::pair<Source<NamedDecl *>, ASTImporter *> Candidate;35 36/// For the given DC, return the DC that is safe to perform lookups on.  This is37/// the DC we actually want to work with most of the time.38const DeclContext *CanonicalizeDC(const DeclContext *DC) {39  if (isa<LinkageSpecDecl>(DC))40    return DC->getRedeclContext();41  return DC;42}43 44Source<const DeclContext *>45LookupSameContext(Source<TranslationUnitDecl *> SourceTU, const DeclContext *DC,46                  ASTImporter &ReverseImporter) {47  DC = CanonicalizeDC(DC);48  if (DC->isTranslationUnit()) {49    return SourceTU;50  }51  Source<const DeclContext *> SourceParentDC =52      LookupSameContext(SourceTU, DC->getParent(), ReverseImporter);53  if (!SourceParentDC) {54    // If we couldn't find the parent DC in this TranslationUnit, give up.55    return nullptr;56  }57  auto *ND = cast<NamedDecl>(DC);58  DeclarationName Name = ND->getDeclName();59  auto SourceNameOrErr = ReverseImporter.Import(Name);60  if (!SourceNameOrErr) {61    llvm::consumeError(SourceNameOrErr.takeError());62    return nullptr;63  }64  Source<DeclarationName> SourceName = *SourceNameOrErr;65  DeclContext::lookup_result SearchResult =66      SourceParentDC.get()->lookup(SourceName.get());67 68  // There are two cases here. First, we might not find the name.69  // We might also find multiple copies, in which case we have no70  // guarantee that the one we wanted is the one we pick.  (E.g.,71  // if we have two specializations of the same template it is72  // very hard to determine which is the one you want.)73  //74  // The Origins map fixes this problem by allowing the origin to be75  // explicitly recorded, so we trigger that recording by returning76  // nothing (rather than a possibly-inaccurate guess) here.77  if (SearchResult.isSingleResult()) {78    NamedDecl *SearchResultDecl = SearchResult.front();79    if (isa<DeclContext>(SearchResultDecl) &&80        SearchResultDecl->getKind() == DC->getDeclKind())81      return cast<DeclContext>(SearchResultDecl)->getPrimaryContext();82    return nullptr; // This type of lookup is unsupported83  } else {84    return nullptr;85  }86}87 88/// A custom implementation of ASTImporter, for ExternalASTMerger's purposes.89///90/// There are several modifications:91///92/// - It enables lazy lookup (via the HasExternalLexicalStorage flag and a few93///   others), which instructs Clang to refer to ExternalASTMerger.  Also, it94///   forces MinimalImport to true, which is necessary to make this work.95/// - It maintains a reverse importer for use with names.  This allows lookup of96///   arbitrary names in the source context.97/// - It updates the ExternalASTMerger's origin map as needed whenever a98///   it sees a DeclContext.99class LazyASTImporter : public ASTImporter {100private:101  ExternalASTMerger &Parent;102  ASTImporter Reverse;103  const ExternalASTMerger::OriginMap &FromOrigins;104  /// @see ExternalASTMerger::ImporterSource::Temporary105  bool TemporarySource;106  /// Map of imported declarations back to the declarations they originated107  /// from.108  llvm::DenseMap<Decl *, Decl *> ToOrigin;109  /// @see ExternalASTMerger::ImporterSource::Merger110  ExternalASTMerger *SourceMerger;111  llvm::raw_ostream &logs() { return Parent.logs(); }112public:113  LazyASTImporter(ExternalASTMerger &_Parent, ASTContext &ToContext,114                  FileManager &ToFileManager,115                  const ExternalASTMerger::ImporterSource &S,116                  std::shared_ptr<ASTImporterSharedState> SharedState)117      : ASTImporter(ToContext, ToFileManager, S.getASTContext(),118                    S.getFileManager(),119                    /*MinimalImport=*/true, SharedState),120        Parent(_Parent),121        Reverse(S.getASTContext(), S.getFileManager(), ToContext, ToFileManager,122                /*MinimalImport=*/true),123        FromOrigins(S.getOriginMap()), TemporarySource(S.isTemporary()),124        SourceMerger(S.getMerger()) {}125 126  llvm::Expected<Decl *> ImportImpl(Decl *FromD) override {127    if (!TemporarySource || !SourceMerger)128      return ASTImporter::ImportImpl(FromD);129 130    // If we get here, then this source is importing from a temporary ASTContext131    // that also has another ExternalASTMerger attached. It could be132    // possible that the current ExternalASTMerger and the temporary ASTContext133    // share a common ImporterSource, which means that the temporary134    // AST could contain declarations that were imported from a source135    // that this ExternalASTMerger can access directly. Instead of importing136    // such declarations from the temporary ASTContext, they should instead137    // be directly imported by this ExternalASTMerger from the original138    // source. This way the ExternalASTMerger can safely do a minimal import139    // without creating incomplete declarations originated from a temporary140    // ASTContext. If we would try to complete such declarations later on, we141    // would fail to do so as their temporary AST could be deleted (which means142    // that the missing parts of the minimally imported declaration in that143    // ASTContext were also deleted).144    //145    // The following code tracks back any declaration that needs to be146    // imported from the temporary ASTContext to a persistent ASTContext.147    // Then the ExternalASTMerger tries to import from the persistent148    // ASTContext directly by using the associated ASTImporter. If that149    // succeeds, this ASTImporter just maps the declarations imported by150    // the other (persistent) ASTImporter to this (temporary) ASTImporter.151    // The steps can be visualized like this:152    //153    //  Target AST <--- 3. Indirect import --- Persistent AST154    //       ^            of persistent decl        ^155    //       |                                      |156    // 1. Current import           2. Tracking back to persistent decl157    // 4. Map persistent decl                       |158    //  & pretend we imported.                      |159    //       |                                      |160    // Temporary AST -------------------------------'161 162    // First, ask the ExternalASTMerger of the source where the temporary163    // declaration originated from.164    Decl *Persistent = SourceMerger->FindOriginalDecl(FromD);165    // FromD isn't from a persistent AST, so just do a normal import.166    if (!Persistent)167      return ASTImporter::ImportImpl(FromD);168    // Now ask the current ExternalASTMerger to try import the persistent169    // declaration into the target.170    ASTContext &PersistentCtx = Persistent->getASTContext();171    ASTImporter &OtherImporter = Parent.ImporterForOrigin(PersistentCtx);172    // Check that we never end up in the current Importer again.173    assert((&PersistentCtx != &getFromContext()) && (&OtherImporter != this) &&174           "Delegated to same Importer?");175    auto DeclOrErr = OtherImporter.Import(Persistent);176    // Errors when importing the persistent decl are treated as if we177    // had errors with importing the temporary decl.178    if (!DeclOrErr)179      return DeclOrErr.takeError();180    Decl *D = *DeclOrErr;181    // Tell the current ASTImporter that this has already been imported182    // to prevent any further queries for the temporary decl.183    MapImported(FromD, D);184    return D;185  }186 187  /// Implements the ASTImporter interface for tracking back a declaration188  /// to its original declaration it came from.189  Decl *GetOriginalDecl(Decl *To) override {190    return ToOrigin.lookup(To);191  }192 193  /// Whenever a DeclContext is imported, ensure that ExternalASTSource's origin194  /// map is kept up to date.  Also set the appropriate flags.195  void Imported(Decl *From, Decl *To) override {196    ToOrigin[To] = From;197 198    if (auto *ToDC = dyn_cast<DeclContext>(To)) {199      const bool LoggingEnabled = Parent.LoggingEnabled();200      if (LoggingEnabled)201        logs() << "(ExternalASTMerger*)" << (void*)&Parent202               << " imported (DeclContext*)" << (void*)ToDC203               << ", (ASTContext*)" << (void*)&getToContext()204               << " from (DeclContext*)" << (void*)llvm::cast<DeclContext>(From)205               << ", (ASTContext*)" << (void*)&getFromContext()206               << "\n";207      Source<DeclContext *> FromDC(208          cast<DeclContext>(From)->getPrimaryContext());209      if (auto It = FromOrigins.find(FromDC);210          It != FromOrigins.end() &&211          Parent.HasImporterForOrigin(*It->second.AST)) {212        if (LoggingEnabled)213          logs() << "(ExternalASTMerger*)" << (void *)&Parent214                 << " forced origin (DeclContext*)" << (void *)It->second.DC215                 << ", (ASTContext*)" << (void *)It->second.AST << "\n";216        Parent.ForceRecordOrigin(ToDC, It->second);217      } else {218        if (LoggingEnabled)219          logs() << "(ExternalASTMerger*)" << (void*)&Parent220                 << " maybe recording origin (DeclContext*)" << (void*)FromDC221                 << ", (ASTContext*)" << (void*)&getFromContext()222                 << "\n";223        Parent.MaybeRecordOrigin(ToDC, {FromDC, &getFromContext()});224      }225    }226    if (auto *ToTag = dyn_cast<TagDecl>(To)) {227      ToTag->setHasExternalLexicalStorage();228      ToTag->getPrimaryContext()->setMustBuildLookupTable();229      assert(Parent.CanComplete(ToTag));230    } else if (auto *ToNamespace = dyn_cast<NamespaceDecl>(To)) {231      ToNamespace->setHasExternalVisibleStorage();232      assert(Parent.CanComplete(ToNamespace));233    } else if (auto *ToContainer = dyn_cast<ObjCContainerDecl>(To)) {234      ToContainer->setHasExternalLexicalStorage();235      ToContainer->getPrimaryContext()->setMustBuildLookupTable();236      assert(Parent.CanComplete(ToContainer));237    }238  }239  ASTImporter &GetReverse() { return Reverse; }240};241 242bool HasDeclOfSameType(ArrayRef<Candidate> Decls, const Candidate &C) {243  if (isa<FunctionDecl>(C.first.get()))244    return false;245  return llvm::any_of(Decls, [&](const Candidate &D) {246    return C.first.get()->getKind() == D.first.get()->getKind();247  });248}249 250} // end namespace251 252ASTImporter &ExternalASTMerger::ImporterForOrigin(ASTContext &OriginContext) {253  for (const std::unique_ptr<ASTImporter> &I : Importers)254    if (&I->getFromContext() == &OriginContext)255      return *I;256  llvm_unreachable("We should have an importer for this origin!");257}258 259namespace {260LazyASTImporter &LazyImporterForOrigin(ExternalASTMerger &Merger,261                                   ASTContext &OriginContext) {262  return static_cast<LazyASTImporter &>(263      Merger.ImporterForOrigin(OriginContext));264}265}266 267bool ExternalASTMerger::HasImporterForOrigin(ASTContext &OriginContext) {268  for (const std::unique_ptr<ASTImporter> &I : Importers)269    if (&I->getFromContext() == &OriginContext)270      return true;271  return false;272}273 274template <typename CallbackType>275void ExternalASTMerger::ForEachMatchingDC(const DeclContext *DC,276                                          CallbackType Callback) {277  if (auto It = Origins.find(DC); It != Origins.end()) {278    ExternalASTMerger::DCOrigin Origin = It->second;279    LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST);280    Callback(Importer, Importer.GetReverse(), Origin.DC);281  } else {282    bool DidCallback = false;283    for (const std::unique_ptr<ASTImporter> &Importer : Importers) {284      Source<TranslationUnitDecl *> SourceTU =285          Importer->getFromContext().getTranslationUnitDecl();286      ASTImporter &Reverse =287          static_cast<LazyASTImporter *>(Importer.get())->GetReverse();288      if (auto SourceDC = LookupSameContext(SourceTU, DC, Reverse)) {289        DidCallback = true;290        if (Callback(*Importer, Reverse, SourceDC))291          break;292      }293    }294    if (!DidCallback && LoggingEnabled())295      logs() << "(ExternalASTMerger*)" << (void*)this296             << " asserting for (DeclContext*)" << (const void*)DC297             << ", (ASTContext*)" << (void*)&Target.AST298             << "\n";299    assert(DidCallback && "Couldn't find a source context matching our DC");300  }301}302 303void ExternalASTMerger::CompleteType(TagDecl *Tag) {304  assert(Tag->hasExternalLexicalStorage());305  ForEachMatchingDC(Tag, [&](ASTImporter &Forward, ASTImporter &Reverse,306                             Source<const DeclContext *> SourceDC) -> bool {307    auto *SourceTag = const_cast<TagDecl *>(cast<TagDecl>(SourceDC.get()));308    if (SourceTag->hasExternalLexicalStorage())309      SourceTag->getASTContext().getExternalSource()->CompleteType(SourceTag);310    if (!SourceTag->getDefinition())311      return false;312    Forward.MapImported(SourceTag, Tag);313    if (llvm::Error Err = Forward.ImportDefinition(SourceTag))314      llvm::consumeError(std::move(Err));315    Tag->setCompleteDefinition(SourceTag->isCompleteDefinition());316    return true;317  });318}319 320void ExternalASTMerger::CompleteType(ObjCInterfaceDecl *Interface) {321  assert(Interface->hasExternalLexicalStorage());322  ForEachMatchingDC(323      Interface, [&](ASTImporter &Forward, ASTImporter &Reverse,324                     Source<const DeclContext *> SourceDC) -> bool {325        auto *SourceInterface = const_cast<ObjCInterfaceDecl *>(326            cast<ObjCInterfaceDecl>(SourceDC.get()));327        if (SourceInterface->hasExternalLexicalStorage())328          SourceInterface->getASTContext().getExternalSource()->CompleteType(329              SourceInterface);330        if (!SourceInterface->getDefinition())331          return false;332        Forward.MapImported(SourceInterface, Interface);333        if (llvm::Error Err = Forward.ImportDefinition(SourceInterface))334          llvm::consumeError(std::move(Err));335        return true;336      });337}338 339bool ExternalASTMerger::CanComplete(DeclContext *Interface) {340  assert(Interface->hasExternalLexicalStorage() ||341         Interface->hasExternalVisibleStorage());342  bool FoundMatchingDC = false;343  ForEachMatchingDC(Interface,344                    [&](ASTImporter &Forward, ASTImporter &Reverse,345                        Source<const DeclContext *> SourceDC) -> bool {346                      FoundMatchingDC = true;347                      return true;348                    });349  return FoundMatchingDC;350}351 352namespace {353bool IsSameDC(const DeclContext *D1, const DeclContext *D2) {354  if (isa<ObjCContainerDecl>(D1) && isa<ObjCContainerDecl>(D2))355    return true; // There are many cases where Objective-C is ambiguous.356  if (auto *T1 = dyn_cast<TagDecl>(D1))357    if (auto *T2 = dyn_cast<TagDecl>(D2))358      if (T1->getFirstDecl() == T2->getFirstDecl())359        return true;360  return D1 == D2 || D1 == CanonicalizeDC(D2);361}362}363 364void ExternalASTMerger::MaybeRecordOrigin(const DeclContext *ToDC,365                                          DCOrigin Origin) {366  LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST);367  ASTImporter &Reverse = Importer.GetReverse();368  Source<const DeclContext *> FoundFromDC =369      LookupSameContext(Origin.AST->getTranslationUnitDecl(), ToDC, Reverse);370  const bool DoRecord = !FoundFromDC || !IsSameDC(FoundFromDC.get(), Origin.DC);371  if (DoRecord)372    RecordOriginImpl(ToDC, Origin, Importer);373  if (LoggingEnabled())374    logs() << "(ExternalASTMerger*)" << (void*)this375             << (DoRecord ? " decided " : " decided NOT")376             << " to record origin (DeclContext*)" << (void*)Origin.DC377             << ", (ASTContext*)" << (void*)&Origin.AST378             << "\n";379}380 381void ExternalASTMerger::ForceRecordOrigin(const DeclContext *ToDC,382                                          DCOrigin Origin) {383  RecordOriginImpl(ToDC, Origin, ImporterForOrigin(*Origin.AST));384}385 386void ExternalASTMerger::RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin,387                                         ASTImporter &Importer) {388  Origins[ToDC] = Origin;389  Importer.ASTImporter::MapImported(cast<Decl>(Origin.DC), const_cast<Decl*>(cast<Decl>(ToDC)));390}391 392ExternalASTMerger::ExternalASTMerger(const ImporterTarget &Target,393                                     ArrayRef<ImporterSource> Sources)394    : LogStream(&llvm::nulls()), Target(Target) {395  SharedState = std::make_shared<ASTImporterSharedState>(396      *Target.AST.getTranslationUnitDecl());397  AddSources(Sources);398}399 400Decl *ExternalASTMerger::FindOriginalDecl(Decl *D) {401  assert(&D->getASTContext() == &Target.AST);402  for (const auto &I : Importers)403    if (auto Result = I->GetOriginalDecl(D))404      return Result;405  return nullptr;406}407 408void ExternalASTMerger::AddSources(ArrayRef<ImporterSource> Sources) {409  for (const ImporterSource &S : Sources) {410    assert(&S.getASTContext() != &Target.AST);411    // Check that the associated merger actually imports into the source AST.412    assert(!S.getMerger() || &S.getMerger()->Target.AST == &S.getASTContext());413    Importers.push_back(std::make_unique<LazyASTImporter>(414        *this, Target.AST, Target.FM, S, SharedState));415  }416}417 418void ExternalASTMerger::RemoveSources(ArrayRef<ImporterSource> Sources) {419  if (LoggingEnabled())420    for (const ImporterSource &S : Sources)421      logs() << "(ExternalASTMerger*)" << (void *)this422             << " removing source (ASTContext*)" << (void *)&S.getASTContext()423             << "\n";424  llvm::erase_if(Importers,425                 [&Sources](std::unique_ptr<ASTImporter> &Importer) -> bool {426                   for (const ImporterSource &S : Sources) {427                     if (&Importer->getFromContext() == &S.getASTContext())428                       return true;429                   }430                   return false;431                 });432  for (OriginMap::iterator OI = Origins.begin(), OE = Origins.end(); OI != OE; ) {433    std::pair<const DeclContext *, DCOrigin> Origin = *OI;434    bool Erase = false;435    for (const ImporterSource &S : Sources) {436      if (&S.getASTContext() == Origin.second.AST) {437        Erase = true;438        break;439      }440    }441    if (Erase)442      OI = Origins.erase(OI);443    else444      ++OI;445  }446}447 448template <typename DeclTy>449static bool importSpecializations(DeclTy *D, ASTImporter *Importer) {450  for (auto *Spec : D->specializations()) {451    auto ImportedSpecOrError = Importer->Import(Spec);452    if (!ImportedSpecOrError) {453      llvm::consumeError(ImportedSpecOrError.takeError());454      return true;455    }456  }457  return false;458}459 460/// Imports specializations from template declarations that can be specialized.461static bool importSpecializationsIfNeeded(Decl *D, ASTImporter *Importer) {462  if (!isa<TemplateDecl>(D))463    return false;464  if (auto *FunctionTD = dyn_cast<FunctionTemplateDecl>(D))465    return importSpecializations(FunctionTD, Importer);466  else if (auto *ClassTD = dyn_cast<ClassTemplateDecl>(D))467    return importSpecializations(ClassTD, Importer);468  else if (auto *VarTD = dyn_cast<VarTemplateDecl>(D))469    return importSpecializations(VarTD, Importer);470  return false;471}472 473bool ExternalASTMerger::FindExternalVisibleDeclsByName(474    const DeclContext *DC, DeclarationName Name,475    const DeclContext *OriginalDC) {476  llvm::SmallVector<NamedDecl *, 1> Decls;477  llvm::SmallVector<Candidate, 4> Candidates;478 479  auto FilterFoundDecl = [&Candidates](const Candidate &C) {480   if (!HasDeclOfSameType(Candidates, C))481     Candidates.push_back(C);482  };483 484  ForEachMatchingDC(DC,485                    [&](ASTImporter &Forward, ASTImporter &Reverse,486                        Source<const DeclContext *> SourceDC) -> bool {487                      auto FromNameOrErr = Reverse.Import(Name);488                      if (!FromNameOrErr) {489                        llvm::consumeError(FromNameOrErr.takeError());490                        return false;491                      }492                      DeclContextLookupResult Result =493                          SourceDC.get()->lookup(*FromNameOrErr);494                      for (NamedDecl *FromD : Result) {495                        FilterFoundDecl(std::make_pair(FromD, &Forward));496                      }497                      return false;498                    });499 500  if (Candidates.empty())501    return false;502 503  Decls.reserve(Candidates.size());504  for (const Candidate &C : Candidates) {505    Decl *LookupRes = C.first.get();506    ASTImporter *Importer = C.second;507    auto NDOrErr = Importer->Import(LookupRes);508    NamedDecl *ND = cast<NamedDecl>(llvm::cantFail(std::move(NDOrErr)));509    assert(ND);510    // If we don't import specialization, they are not available via lookup511    // because the lookup result is imported TemplateDecl and it does not512    // reference its specializations until they are imported explicitly.513    bool IsSpecImportFailed =514        importSpecializationsIfNeeded(LookupRes, Importer);515    assert(!IsSpecImportFailed);516    (void)IsSpecImportFailed;517    Decls.push_back(ND);518  }519  SetExternalVisibleDeclsForName(DC, Name, Decls);520  return true;521}522 523void ExternalASTMerger::FindExternalLexicalDecls(524    const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,525    SmallVectorImpl<Decl *> &Result) {526  ForEachMatchingDC(DC, [&](ASTImporter &Forward, ASTImporter &Reverse,527                            Source<const DeclContext *> SourceDC) -> bool {528    for (const Decl *SourceDecl : SourceDC.get()->decls()) {529      if (IsKindWeWant(SourceDecl->getKind())) {530        auto ImportedDeclOrErr = Forward.Import(SourceDecl);531        if (ImportedDeclOrErr)532          assert(!(*ImportedDeclOrErr) ||533                 IsSameDC((*ImportedDeclOrErr)->getDeclContext(), DC));534        else535          llvm::consumeError(ImportedDeclOrErr.takeError());536      }537    }538    return false;539  });540}541