@@ -821,25 +821,45 @@ void SymbolCollector::setIncludeLocation(const Symbol &S, SourceLocation DefLoc,
821821 // Use the expansion location to get the #include header since this is
822822 // where the symbol is exposed.
823823 IncludeFiles[S.ID ] = SM.getDecomposedExpansionLoc (DefLoc).first ;
824+
825+ // We update providers for a symbol with each occurence, as SymbolCollector
826+ // might run while parsing, rather than at the end of a translation unit.
827+ // Hence we see more and more redecls over time.
828+ auto [It, Inserted] = SymbolProviders.try_emplace (S.ID );
829+ auto Headers =
830+ include_cleaner::headersForSymbol (Sym, SM, Opts.PragmaIncludes );
831+ if (Headers.empty ())
832+ return ;
833+
834+ auto *HeadersIter = Headers.begin ();
835+ include_cleaner::Header H = *HeadersIter;
836+ while (HeadersIter != Headers.end () &&
837+ H.kind () == include_cleaner::Header::Physical &&
838+ !tooling::isSelfContainedHeader (H.physical (), SM,
839+ PP->getHeaderSearchInfo ())) {
840+ H = *HeadersIter;
841+ HeadersIter++;
842+ }
843+ It->second = H;
824844}
825845
826846llvm::StringRef getStdHeader (const Symbol *S, const LangOptions &LangOpts) {
827847 tooling::stdlib::Lang Lang = tooling::stdlib::Lang::CXX;
828- if (LangOpts.C11 )
829- Lang = tooling::stdlib::Lang::C;
830- else if (!LangOpts.CPlusPlus )
831- return " " ;
832-
833- if (S->Scope == " std::" && S->Name == " move" ) {
834- if (!S->Signature .contains (' ,' ))
835- return " <utility>" ;
836- return " <algorithm>" ;
837- }
838-
839- if (auto StdSym = tooling::stdlib::Symbol::named (S->Scope , S->Name , Lang))
840- if (auto Header = StdSym->header ())
841- return Header->name ();
848+ if (LangOpts.C11 )
849+ Lang = tooling::stdlib::Lang::C;
850+ else if (!LangOpts.CPlusPlus )
842851 return " " ;
852+
853+ if (S->Scope == " std::" && S->Name == " move" ) {
854+ if (!S->Signature .contains (' ,' ))
855+ return " <utility>" ;
856+ return " <algorithm>" ;
857+ }
858+
859+ if (auto StdSym = tooling::stdlib::Symbol::named (S->Scope , S->Name , Lang))
860+ if (auto Header = StdSym->header ())
861+ return Header->name ();
862+ return " " ;
843863}
844864
845865void SymbolCollector::finish () {
@@ -865,13 +885,16 @@ void SymbolCollector::finish() {
865885 }
866886 }
867887 llvm::DenseMap<FileID, bool > FileToContainsImportsOrObjC;
888+ llvm::DenseMap<include_cleaner::Header, std::string> HeaderSpelling;
868889 // Fill in IncludeHeaders.
869890 // We delay this until end of TU so header guards are all resolved.
870- for (const auto &[SID, FID ] : IncludeFiles ) {
891+ for (const auto &[SID, OptionalProvider ] : SymbolProviders ) {
871892 const Symbol *S = Symbols.find (SID);
872893 if (!S)
873894 continue ;
895+ assert (IncludeFiles.find (SID) != IncludeFiles.end ());
874896
897+ const auto FID = IncludeFiles.at (SID);
875898 // Determine if the FID is #include'd or #import'ed.
876899 Symbol::IncludeDirective Directives = Symbol::Invalid;
877900 auto CollectDirectives = shouldCollectIncludePath (S->SymInfo .Kind );
@@ -891,20 +914,61 @@ void SymbolCollector::finish() {
891914 if (Directives == Symbol::Invalid)
892915 continue ;
893916
894- // FIXME: Use the include-cleaner library instead.
895- llvm::StringRef IncludeHeader = getStdHeader (S, ASTCtx->getLangOpts ());
896- if (IncludeHeader.empty ())
897- IncludeHeader = HeaderFileURIs->getIncludeHeader (FID);
917+ // Use the include location-based logic for Objective-C symbols.
918+ if (Directives & Symbol::Import) {
919+ llvm::StringRef IncludeHeader = getStdHeader (S, ASTCtx->getLangOpts ());
920+ if (IncludeHeader.empty ())
921+ IncludeHeader = HeaderFileURIs->getIncludeHeader (FID);
922+
923+ if (!IncludeHeader.empty ()) {
924+ auto NewSym = *S;
925+ NewSym.IncludeHeaders .push_back ({IncludeHeader, 1 , Directives});
926+ Symbols.insert (NewSym);
927+ }
928+ // FIXME: use providers from include-cleaner library once it's polished
929+ // for Objective-C.
930+ continue ;
931+ }
932+
933+ assert (Directives == Symbol::Include);
934+ // For #include's, use the providers computed by the include-cleaner
935+ // library.
936+ if (!OptionalProvider)
937+ continue ;
938+ const auto &H = *OptionalProvider;
939+ const auto [SpellingIt, Inserted] = HeaderSpelling.try_emplace (H);
940+ if (Inserted) {
941+ auto &SM = ASTCtx->getSourceManager ();
942+ if (H.kind () == include_cleaner::Header::Kind::Physical) {
943+ // FIXME: Get rid of this once include-cleaner has support for system
944+ // headers.
945+ if (auto Canonical =
946+ HeaderFileURIs->mapCanonical (H.physical ()->getName ());
947+ !Canonical.empty ())
948+ SpellingIt->second = Canonical;
949+ // For physical files, prefer URIs as spellings might change
950+ // depending on the translation unit.
951+ else if (tooling::isSelfContainedHeader (H.physical (), SM,
952+ PP->getHeaderSearchInfo ()))
953+ SpellingIt->second =
954+ HeaderFileURIs->toURI (H.physical ()->getLastRef ());
955+ } else {
956+ SpellingIt->second = include_cleaner::spellHeader (
957+ {H, PP->getHeaderSearchInfo (),
958+ SM.getFileEntryForID (SM.getMainFileID ())});
959+ }
960+ }
898961
899- if (!IncludeHeader .empty ()) {
962+ if (!SpellingIt-> second .empty ()) {
900963 auto NewSym = *S;
901- NewSym.IncludeHeaders .push_back ({IncludeHeader , 1 , Directives});
964+ NewSym.IncludeHeaders .push_back ({SpellingIt-> second , 1 , Directives});
902965 Symbols.insert (NewSym);
903966 }
904967 }
905968
906969 ReferencedSymbols.clear ();
907970 IncludeFiles.clear ();
971+ SymbolProviders.clear ();
908972 FilesWithObjCConstructs.clear ();
909973}
910974
0 commit comments