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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements the ExternalASTMerger, which vends a combination of 10 // ASTs from several different ASTContext/FileManager pairs 11 // 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 21 using namespace clang; 22 23 namespace { 24 25 template <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 34 typedef std::pair<Source<NamedDecl *>, ASTImporter *> Candidate; 35 36 /// For the given DC, return the DC that is safe to perform lookups on. This is 37 /// the DC we actually want to work with most of the time. 38 const DeclContext *CanonicalizeDC(const DeclContext *DC) { 39 if (isa<LinkageSpecDecl>(DC)) 40 return DC->getRedeclContext(); 41 return DC; 42 } 43 44 Source<const DeclContext *> 45 LookupSameContext(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 size_t SearchResultSize = SearchResult.size(); 68 if (SearchResultSize == 0 || SearchResultSize > 1) { 69 // There are two cases here. First, we might not find the name. 70 // We might also find multiple copies, in which case we have no 71 // guarantee that the one we wanted is the one we pick. (E.g., 72 // if we have two specializations of the same template it is 73 // very hard to determine which is the one you want.) 74 // 75 // The Origins map fixes this problem by allowing the origin to be 76 // explicitly recorded, so we trigger that recording by returning 77 // nothing (rather than a possibly-inaccurate guess) here. 78 return nullptr; 79 } else { 80 NamedDecl *SearchResultDecl = SearchResult[0]; 81 if (isa<DeclContext>(SearchResultDecl) && 82 SearchResultDecl->getKind() == DC->getDeclKind()) 83 return cast<DeclContext>(SearchResultDecl)->getPrimaryContext(); 84 return nullptr; // This type of lookup is unsupported 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 few 93 /// others), which instructs Clang to refer to ExternalASTMerger. Also, it 94 /// forces MinimalImport to true, which is necessary to make this work. 95 /// - It maintains a reverse importer for use with names. This allows lookup of 96 /// arbitrary names in the source context. 97 /// - It updates the ExternalASTMerger's origin map as needed whenever a 98 /// it sees a DeclContext. 99 class LazyASTImporter : public ASTImporter { 100 private: 101 ExternalASTMerger &Parent; 102 ASTImporter Reverse; 103 const ExternalASTMerger::OriginMap &FromOrigins; 104 105 llvm::raw_ostream &logs() { return Parent.logs(); } 106 public: 107 LazyASTImporter(ExternalASTMerger &_Parent, ASTContext &ToContext, 108 FileManager &ToFileManager, 109 const ExternalASTMerger::ImporterSource &_Source, 110 std::shared_ptr<ASTImporterSharedState> SharedState) 111 : ASTImporter(ToContext, ToFileManager, _Source.getASTContext(), 112 _Source.getFileManager(), 113 /*MinimalImport=*/true, SharedState), 114 Parent(_Parent), 115 Reverse(_Source.getASTContext(), _Source.getFileManager(), ToContext, 116 ToFileManager, /*MinimalImport=*/true), 117 FromOrigins(_Source.getOriginMap()) {} 118 119 /// Whenever a DeclContext is imported, ensure that ExternalASTSource's origin 120 /// map is kept up to date. Also set the appropriate flags. 121 void Imported(Decl *From, Decl *To) override { 122 if (auto *ToDC = dyn_cast<DeclContext>(To)) { 123 const bool LoggingEnabled = Parent.LoggingEnabled(); 124 if (LoggingEnabled) 125 logs() << "(ExternalASTMerger*)" << (void*)&Parent 126 << " imported (DeclContext*)" << (void*)ToDC 127 << ", (ASTContext*)" << (void*)&getToContext() 128 << " from (DeclContext*)" << (void*)llvm::cast<DeclContext>(From) 129 << ", (ASTContext*)" << (void*)&getFromContext() 130 << "\n"; 131 Source<DeclContext *> FromDC( 132 cast<DeclContext>(From)->getPrimaryContext()); 133 if (FromOrigins.count(FromDC) && 134 Parent.HasImporterForOrigin(*FromOrigins.at(FromDC).AST)) { 135 if (LoggingEnabled) 136 logs() << "(ExternalASTMerger*)" << (void*)&Parent 137 << " forced origin (DeclContext*)" 138 << (void*)FromOrigins.at(FromDC).DC 139 << ", (ASTContext*)" 140 << (void*)FromOrigins.at(FromDC).AST 141 << "\n"; 142 Parent.ForceRecordOrigin(ToDC, FromOrigins.at(FromDC)); 143 } else { 144 if (LoggingEnabled) 145 logs() << "(ExternalASTMerger*)" << (void*)&Parent 146 << " maybe recording origin (DeclContext*)" << (void*)FromDC 147 << ", (ASTContext*)" << (void*)&getFromContext() 148 << "\n"; 149 Parent.MaybeRecordOrigin(ToDC, {FromDC, &getFromContext()}); 150 } 151 } 152 if (auto *ToTag = dyn_cast<TagDecl>(To)) { 153 ToTag->setHasExternalLexicalStorage(); 154 ToTag->getPrimaryContext()->setMustBuildLookupTable(); 155 assert(Parent.CanComplete(ToTag)); 156 } else if (auto *ToNamespace = dyn_cast<NamespaceDecl>(To)) { 157 ToNamespace->setHasExternalVisibleStorage(); 158 assert(Parent.CanComplete(ToNamespace)); 159 } else if (auto *ToContainer = dyn_cast<ObjCContainerDecl>(To)) { 160 ToContainer->setHasExternalLexicalStorage(); 161 ToContainer->getPrimaryContext()->setMustBuildLookupTable(); 162 assert(Parent.CanComplete(ToContainer)); 163 } 164 } 165 ASTImporter &GetReverse() { return Reverse; } 166 }; 167 168 bool HasDeclOfSameType(llvm::ArrayRef<Candidate> Decls, const Candidate &C) { 169 if (isa<FunctionDecl>(C.first.get())) 170 return false; 171 return llvm::any_of(Decls, [&](const Candidate &D) { 172 return C.first.get()->getKind() == D.first.get()->getKind(); 173 }); 174 } 175 176 } // end namespace 177 178 ASTImporter &ExternalASTMerger::ImporterForOrigin(ASTContext &OriginContext) { 179 for (const std::unique_ptr<ASTImporter> &I : Importers) 180 if (&I->getFromContext() == &OriginContext) 181 return *I; 182 llvm_unreachable("We should have an importer for this origin!"); 183 } 184 185 namespace { 186 LazyASTImporter &LazyImporterForOrigin(ExternalASTMerger &Merger, 187 ASTContext &OriginContext) { 188 return static_cast<LazyASTImporter &>( 189 Merger.ImporterForOrigin(OriginContext)); 190 } 191 } 192 193 bool ExternalASTMerger::HasImporterForOrigin(ASTContext &OriginContext) { 194 for (const std::unique_ptr<ASTImporter> &I : Importers) 195 if (&I->getFromContext() == &OriginContext) 196 return true; 197 return false; 198 } 199 200 template <typename CallbackType> 201 void ExternalASTMerger::ForEachMatchingDC(const DeclContext *DC, 202 CallbackType Callback) { 203 if (Origins.count(DC)) { 204 ExternalASTMerger::DCOrigin Origin = Origins[DC]; 205 LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST); 206 Callback(Importer, Importer.GetReverse(), Origin.DC); 207 } else { 208 bool DidCallback = false; 209 for (const std::unique_ptr<ASTImporter> &Importer : Importers) { 210 Source<TranslationUnitDecl *> SourceTU = 211 Importer->getFromContext().getTranslationUnitDecl(); 212 ASTImporter &Reverse = 213 static_cast<LazyASTImporter *>(Importer.get())->GetReverse(); 214 if (auto SourceDC = LookupSameContext(SourceTU, DC, Reverse)) { 215 DidCallback = true; 216 if (Callback(*Importer, Reverse, SourceDC)) 217 break; 218 } 219 } 220 if (!DidCallback && LoggingEnabled()) 221 logs() << "(ExternalASTMerger*)" << (void*)this 222 << " asserting for (DeclContext*)" << (const void*)DC 223 << ", (ASTContext*)" << (void*)&Target.AST 224 << "\n"; 225 assert(DidCallback && "Couldn't find a source context matching our DC"); 226 } 227 } 228 229 void ExternalASTMerger::CompleteType(TagDecl *Tag) { 230 assert(Tag->hasExternalLexicalStorage()); 231 ForEachMatchingDC(Tag, [&](ASTImporter &Forward, ASTImporter &Reverse, 232 Source<const DeclContext *> SourceDC) -> bool { 233 auto *SourceTag = const_cast<TagDecl *>(cast<TagDecl>(SourceDC.get())); 234 if (SourceTag->hasExternalLexicalStorage()) 235 SourceTag->getASTContext().getExternalSource()->CompleteType(SourceTag); 236 if (!SourceTag->getDefinition()) 237 return false; 238 Forward.MapImported(SourceTag, Tag); 239 if (llvm::Error Err = Forward.ImportDefinition(SourceTag)) 240 llvm::consumeError(std::move(Err)); 241 Tag->setCompleteDefinition(SourceTag->isCompleteDefinition()); 242 return true; 243 }); 244 } 245 246 void ExternalASTMerger::CompleteType(ObjCInterfaceDecl *Interface) { 247 assert(Interface->hasExternalLexicalStorage()); 248 ForEachMatchingDC( 249 Interface, [&](ASTImporter &Forward, ASTImporter &Reverse, 250 Source<const DeclContext *> SourceDC) -> bool { 251 auto *SourceInterface = const_cast<ObjCInterfaceDecl *>( 252 cast<ObjCInterfaceDecl>(SourceDC.get())); 253 if (SourceInterface->hasExternalLexicalStorage()) 254 SourceInterface->getASTContext().getExternalSource()->CompleteType( 255 SourceInterface); 256 if (!SourceInterface->getDefinition()) 257 return false; 258 Forward.MapImported(SourceInterface, Interface); 259 if (llvm::Error Err = Forward.ImportDefinition(SourceInterface)) 260 llvm::consumeError(std::move(Err)); 261 return true; 262 }); 263 } 264 265 bool ExternalASTMerger::CanComplete(DeclContext *Interface) { 266 assert(Interface->hasExternalLexicalStorage() || 267 Interface->hasExternalVisibleStorage()); 268 bool FoundMatchingDC = false; 269 ForEachMatchingDC(Interface, 270 [&](ASTImporter &Forward, ASTImporter &Reverse, 271 Source<const DeclContext *> SourceDC) -> bool { 272 FoundMatchingDC = true; 273 return true; 274 }); 275 return FoundMatchingDC; 276 } 277 278 namespace { 279 bool IsSameDC(const DeclContext *D1, const DeclContext *D2) { 280 if (isa<ObjCContainerDecl>(D1) && isa<ObjCContainerDecl>(D2)) 281 return true; // There are many cases where Objective-C is ambiguous. 282 if (auto *T1 = dyn_cast<TagDecl>(D1)) 283 if (auto *T2 = dyn_cast<TagDecl>(D2)) 284 if (T1->getFirstDecl() == T2->getFirstDecl()) 285 return true; 286 return D1 == D2 || D1 == CanonicalizeDC(D2); 287 } 288 } 289 290 void ExternalASTMerger::MaybeRecordOrigin(const DeclContext *ToDC, 291 DCOrigin Origin) { 292 LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST); 293 ASTImporter &Reverse = Importer.GetReverse(); 294 Source<const DeclContext *> FoundFromDC = 295 LookupSameContext(Origin.AST->getTranslationUnitDecl(), ToDC, Reverse); 296 const bool DoRecord = !FoundFromDC || !IsSameDC(FoundFromDC.get(), Origin.DC); 297 if (DoRecord) 298 RecordOriginImpl(ToDC, Origin, Importer); 299 if (LoggingEnabled()) 300 logs() << "(ExternalASTMerger*)" << (void*)this 301 << (DoRecord ? " decided " : " decided NOT") 302 << " to record origin (DeclContext*)" << (void*)Origin.DC 303 << ", (ASTContext*)" << (void*)&Origin.AST 304 << "\n"; 305 } 306 307 void ExternalASTMerger::ForceRecordOrigin(const DeclContext *ToDC, 308 DCOrigin Origin) { 309 RecordOriginImpl(ToDC, Origin, ImporterForOrigin(*Origin.AST)); 310 } 311 312 void ExternalASTMerger::RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin, 313 ASTImporter &Importer) { 314 Origins[ToDC] = Origin; 315 Importer.ASTImporter::MapImported(cast<Decl>(Origin.DC), const_cast<Decl*>(cast<Decl>(ToDC))); 316 } 317 318 ExternalASTMerger::ExternalASTMerger(const ImporterTarget &Target, 319 llvm::ArrayRef<ImporterSource> Sources) : LogStream(&llvm::nulls()), Target(Target) { 320 SharedState = std::make_shared<ASTImporterSharedState>( 321 *Target.AST.getTranslationUnitDecl()); 322 AddSources(Sources); 323 } 324 325 void ExternalASTMerger::AddSources(llvm::ArrayRef<ImporterSource> Sources) { 326 for (const ImporterSource &S : Sources) { 327 assert(&S.getASTContext() != &Target.AST); 328 Importers.push_back(std::make_unique<LazyASTImporter>( 329 *this, Target.AST, Target.FM, S, SharedState)); 330 } 331 } 332 333 void ExternalASTMerger::RemoveSources(llvm::ArrayRef<ImporterSource> Sources) { 334 if (LoggingEnabled()) 335 for (const ImporterSource &S : Sources) 336 logs() << "(ExternalASTMerger*)" << (void *)this 337 << " removing source (ASTContext*)" << (void *)&S.getASTContext() 338 << "\n"; 339 Importers.erase( 340 std::remove_if(Importers.begin(), Importers.end(), 341 [&Sources](std::unique_ptr<ASTImporter> &Importer) -> bool { 342 for (const ImporterSource &S : Sources) { 343 if (&Importer->getFromContext() == &S.getASTContext()) 344 return true; 345 } 346 return false; 347 }), 348 Importers.end()); 349 for (OriginMap::iterator OI = Origins.begin(), OE = Origins.end(); OI != OE; ) { 350 std::pair<const DeclContext *, DCOrigin> Origin = *OI; 351 bool Erase = false; 352 for (const ImporterSource &S : Sources) { 353 if (&S.getASTContext() == Origin.second.AST) { 354 Erase = true; 355 break; 356 } 357 } 358 if (Erase) 359 OI = Origins.erase(OI); 360 else 361 ++OI; 362 } 363 } 364 365 template <typename DeclTy> 366 static bool importSpecializations(DeclTy *D, ASTImporter *Importer) { 367 for (auto *Spec : D->specializations()) { 368 auto ImportedSpecOrError = Importer->Import(Spec); 369 if (!ImportedSpecOrError) { 370 llvm::consumeError(ImportedSpecOrError.takeError()); 371 return true; 372 } 373 } 374 return false; 375 } 376 377 /// Imports specializations from template declarations that can be specialized. 378 static bool importSpecializationsIfNeeded(Decl *D, ASTImporter *Importer) { 379 if (!isa<TemplateDecl>(D)) 380 return false; 381 if (auto *FunctionTD = dyn_cast<FunctionTemplateDecl>(D)) 382 return importSpecializations(FunctionTD, Importer); 383 else if (auto *ClassTD = dyn_cast<ClassTemplateDecl>(D)) 384 return importSpecializations(ClassTD, Importer); 385 else if (auto *VarTD = dyn_cast<VarTemplateDecl>(D)) 386 return importSpecializations(VarTD, Importer); 387 return false; 388 } 389 390 bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC, 391 DeclarationName Name) { 392 llvm::SmallVector<NamedDecl *, 1> Decls; 393 llvm::SmallVector<Candidate, 4> Candidates; 394 395 auto FilterFoundDecl = [&Candidates](const Candidate &C) { 396 if (!HasDeclOfSameType(Candidates, C)) 397 Candidates.push_back(C); 398 }; 399 400 ForEachMatchingDC(DC, 401 [&](ASTImporter &Forward, ASTImporter &Reverse, 402 Source<const DeclContext *> SourceDC) -> bool { 403 auto FromNameOrErr = Reverse.Import(Name); 404 if (!FromNameOrErr) { 405 llvm::consumeError(FromNameOrErr.takeError()); 406 return false; 407 } 408 DeclContextLookupResult Result = 409 SourceDC.get()->lookup(*FromNameOrErr); 410 for (NamedDecl *FromD : Result) { 411 FilterFoundDecl(std::make_pair(FromD, &Forward)); 412 } 413 return false; 414 }); 415 416 if (Candidates.empty()) 417 return false; 418 419 Decls.reserve(Candidates.size()); 420 for (const Candidate &C : Candidates) { 421 Decl *LookupRes = C.first.get(); 422 ASTImporter *Importer = C.second; 423 auto NDOrErr = Importer->Import(LookupRes); 424 assert(NDOrErr); 425 (void)static_cast<bool>(NDOrErr); 426 NamedDecl *ND = cast_or_null<NamedDecl>(*NDOrErr); 427 assert(ND); 428 // If we don't import specialization, they are not available via lookup 429 // because the lookup result is imported TemplateDecl and it does not 430 // reference its specializations until they are imported explicitly. 431 bool IsSpecImportFailed = 432 importSpecializationsIfNeeded(LookupRes, Importer); 433 assert(!IsSpecImportFailed); 434 (void)IsSpecImportFailed; 435 Decls.push_back(ND); 436 } 437 SetExternalVisibleDeclsForName(DC, Name, Decls); 438 return true; 439 } 440 441 void ExternalASTMerger::FindExternalLexicalDecls( 442 const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, 443 SmallVectorImpl<Decl *> &Result) { 444 ForEachMatchingDC(DC, [&](ASTImporter &Forward, ASTImporter &Reverse, 445 Source<const DeclContext *> SourceDC) -> bool { 446 for (const Decl *SourceDecl : SourceDC.get()->decls()) { 447 if (IsKindWeWant(SourceDecl->getKind())) { 448 auto ImportedDeclOrErr = Forward.Import(SourceDecl); 449 if (ImportedDeclOrErr) 450 assert(!(*ImportedDeclOrErr) || 451 IsSameDC((*ImportedDeclOrErr)->getDeclContext(), DC)); 452 else 453 llvm::consumeError(ImportedDeclOrErr.takeError()); 454 } 455 } 456 return false; 457 }); 458 } 459 460