@@ -821,25 +821,45 @@ void SymbolCollector::setIncludeLocation(const Symbol &S, SourceLocation DefLoc,
821
821
// Use the expansion location to get the #include header since this is
822
822
// where the symbol is exposed.
823
823
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;
824
844
}
825
845
826
846
llvm::StringRef getStdHeader (const Symbol *S, const LangOptions &LangOpts) {
827
847
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 )
842
851
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 " " ;
843
863
}
844
864
845
865
void SymbolCollector::finish () {
@@ -865,13 +885,16 @@ void SymbolCollector::finish() {
865
885
}
866
886
}
867
887
llvm::DenseMap<FileID, bool > FileToContainsImportsOrObjC;
888
+ llvm::DenseMap<include_cleaner::Header, std::string> HeaderSpelling;
868
889
// Fill in IncludeHeaders.
869
890
// 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 ) {
871
892
const Symbol *S = Symbols.find (SID);
872
893
if (!S)
873
894
continue ;
895
+ assert (IncludeFiles.find (SID) != IncludeFiles.end ());
874
896
897
+ const auto FID = IncludeFiles.at (SID);
875
898
// Determine if the FID is #include'd or #import'ed.
876
899
Symbol::IncludeDirective Directives = Symbol::Invalid;
877
900
auto CollectDirectives = shouldCollectIncludePath (S->SymInfo .Kind );
@@ -891,20 +914,61 @@ void SymbolCollector::finish() {
891
914
if (Directives == Symbol::Invalid)
892
915
continue ;
893
916
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
+ }
898
961
899
- if (!IncludeHeader .empty ()) {
962
+ if (!SpellingIt-> second .empty ()) {
900
963
auto NewSym = *S;
901
- NewSym.IncludeHeaders .push_back ({IncludeHeader , 1 , Directives});
964
+ NewSym.IncludeHeaders .push_back ({SpellingIt-> second , 1 , Directives});
902
965
Symbols.insert (NewSym);
903
966
}
904
967
}
905
968
906
969
ReferencedSymbols.clear ();
907
970
IncludeFiles.clear ();
971
+ SymbolProviders.clear ();
908
972
FilesWithObjCConstructs.clear ();
909
973
}
910
974
0 commit comments