21
21
#include " clang/AST/DeclBase.h"
22
22
#include " clang/AST/DeclObjC.h"
23
23
#include " clang/AST/DeclTemplate.h"
24
+ #include " clang/AST/DeclarationName.h"
25
+ #include " clang/Basic/LangOptions.h"
24
26
#include " clang/Basic/SourceLocation.h"
25
27
#include " clang/Basic/SourceManager.h"
26
28
#include " clang/Index/IndexSymbol.h"
27
29
#include " clang/Lex/Preprocessor.h"
28
- #include " clang/Tooling/Syntax/Tokens.h"
30
+ #include " clang/Lex/Token.h"
31
+ #include " llvm/ADT/ArrayRef.h"
29
32
#include " llvm/Support/Casting.h"
30
33
#include " llvm/Support/FileSystem.h"
31
34
#include " llvm/Support/Path.h"
@@ -171,6 +174,22 @@ const Decl *getRefContainer(const Decl *Enclosing,
171
174
return Enclosing;
172
175
}
173
176
177
+ // Check if there is an exact spelling of \p ND at \p Loc.
178
+ bool isSpelled (SourceLocation Loc, const NamedDecl &ND) {
179
+ auto Name = ND.getDeclName ();
180
+ const auto NameKind = Name.getNameKind ();
181
+ if (NameKind != DeclarationName::Identifier &&
182
+ NameKind != DeclarationName::CXXConstructorName)
183
+ return false ;
184
+ const auto &AST = ND.getASTContext ();
185
+ const auto &SM = AST.getSourceManager ();
186
+ const auto &LO = AST.getLangOpts ();
187
+ clang::Token Tok;
188
+ if (clang::Lexer::getRawToken (Loc, Tok, SM, LO))
189
+ return false ;
190
+ auto StrName = Name.getAsString ();
191
+ return clang::Lexer::getSpelling (Tok, SM, LO) == StrName;
192
+ }
174
193
} // namespace
175
194
176
195
// Encapsulates decisions about how to record header paths in the index,
@@ -545,17 +564,17 @@ bool SymbolCollector::handleDeclOccurrence(
545
564
if (!ND)
546
565
return true ;
547
566
567
+ auto ID = getSymbolIDCached (ND);
568
+ if (!ID)
569
+ return true ;
570
+
548
571
// Mark D as referenced if this is a reference coming from the main file.
549
572
// D may not be an interesting symbol, but it's cheaper to check at the end.
550
573
auto &SM = ASTCtx->getSourceManager ();
551
574
if (Opts.CountReferences &&
552
575
(Roles & static_cast <unsigned >(index::SymbolRole::Reference)) &&
553
576
SM.getFileID (SM.getSpellingLoc (Loc)) == SM.getMainFileID ())
554
- ReferencedDecls.insert (ND);
555
-
556
- auto ID = getSymbolID (ND);
557
- if (!ID)
558
- return true ;
577
+ ReferencedSymbols.insert (ID);
559
578
560
579
// ND is the canonical (i.e. first) declaration. If it's in the main file
561
580
// (which is not a header), then no public declaration was visible, so assume
@@ -576,27 +595,25 @@ bool SymbolCollector::handleDeclOccurrence(
576
595
processRelations (*ND, ID, Relations);
577
596
578
597
bool CollectRef = static_cast <bool >(Opts.RefFilter & toRefKind (Roles));
579
- bool IsOnlyRef =
580
- !(Roles & (static_cast <unsigned >(index::SymbolRole::Declaration) |
581
- static_cast <unsigned >(index::SymbolRole::Definition)));
582
-
583
- if (IsOnlyRef && !CollectRef)
584
- return true ;
585
-
586
598
// Unlike other fields, e.g. Symbols (which use spelling locations), we use
587
599
// file locations for references (as it aligns the behavior of clangd's
588
600
// AST-based xref).
589
601
// FIXME: we should try to use the file locations for other fields.
590
602
if (CollectRef &&
591
603
(!IsMainFileOnly || Opts.CollectMainFileRefs ||
592
604
ND->isExternallyVisible ()) &&
593
- !isa<NamespaceDecl>(ND) &&
594
- (Opts.RefsInHeaders ||
595
- SM.getFileID (SM.getFileLoc (Loc)) == SM.getMainFileID ()))
596
- DeclRefs[ND].push_back (SymbolRef{SM.getFileLoc (Loc), Roles,
597
- getRefContainer (ASTNode.Parent , Opts)});
605
+ !isa<NamespaceDecl>(ND)) {
606
+ auto FileLoc = SM.getFileLoc (Loc);
607
+ auto FID = SM.getFileID (FileLoc);
608
+ if (Opts.RefsInHeaders || FID == SM.getMainFileID ()) {
609
+ addRef (ID, SymbolRef{FileLoc, FID, Roles,
610
+ getRefContainer (ASTNode.Parent , Opts),
611
+ isSpelled (FileLoc, *ND)});
612
+ }
613
+ }
598
614
// Don't continue indexing if this is a mere reference.
599
- if (IsOnlyRef)
615
+ if (!(Roles & (static_cast <unsigned >(index::SymbolRole::Declaration) |
616
+ static_cast <unsigned >(index::SymbolRole::Definition))))
600
617
return true ;
601
618
602
619
// FIXME: ObjCPropertyDecl are not properly indexed here:
@@ -682,7 +699,7 @@ bool SymbolCollector::handleMacroOccurrence(const IdentifierInfo *Name,
682
699
Name->getName () == " __GCC_HAVE_DWARF2_CFI_ASM" )
683
700
return true ;
684
701
685
- auto ID = getSymbolID (Name->getName (), MI, SM);
702
+ auto ID = getSymbolIDCached (Name->getName (), MI, SM);
686
703
if (!ID)
687
704
return true ;
688
705
@@ -693,9 +710,13 @@ bool SymbolCollector::handleMacroOccurrence(const IdentifierInfo *Name,
693
710
ASTCtx->getLangOpts ());
694
711
// Do not store references to main-file macros.
695
712
if ((static_cast <unsigned >(Opts.RefFilter ) & Roles) && !IsMainFileOnly &&
696
- (Opts.RefsInHeaders || SM.getFileID (SpellingLoc) == SM.getMainFileID ()))
713
+ (Opts.RefsInHeaders || SM.getFileID (SpellingLoc) == SM.getMainFileID ())) {
697
714
// FIXME: Populate container information for macro references.
698
- MacroRefs[ID].push_back ({Loc, Roles, /* Container=*/ nullptr });
715
+ // FIXME: All MacroRefs are marked as Spelled now, but this should be
716
+ // checked.
717
+ addRef (ID, SymbolRef{Loc, SM.getFileID (Loc), Roles, /* Container=*/ nullptr ,
718
+ /* Spelled=*/ true });
719
+ }
699
720
700
721
// Collect symbols.
701
722
if (!Opts.CollectMacro )
@@ -711,7 +732,7 @@ bool SymbolCollector::handleMacroOccurrence(const IdentifierInfo *Name,
711
732
if (Opts.CountReferences &&
712
733
(Roles & static_cast <unsigned >(index::SymbolRole::Reference)) &&
713
734
SM.getFileID (SpellingLoc) == SM.getMainFileID ())
714
- ReferencedMacros .insert (Name );
735
+ ReferencedSymbols .insert (ID );
715
736
716
737
// Don't continue indexing if this is a mere reference.
717
738
// FIXME: remove macro with ID if it is undefined.
@@ -761,7 +782,7 @@ void SymbolCollector::processRelations(
761
782
continue ;
762
783
const Decl *Object = R.RelatedSymbol ;
763
784
764
- auto ObjectID = getSymbolID (Object);
785
+ auto ObjectID = getSymbolIDCached (Object);
765
786
if (!ObjectID)
766
787
continue ;
767
788
@@ -792,33 +813,25 @@ void SymbolCollector::setIncludeLocation(const Symbol &S, SourceLocation Loc) {
792
813
793
814
void SymbolCollector::finish () {
794
815
// At the end of the TU, add 1 to the refcount of all referenced symbols.
795
- auto IncRef = [ this ] (const SymbolID &ID) {
816
+ for (const auto &ID : ReferencedSymbols ) {
796
817
if (const auto *S = Symbols.find (ID)) {
797
- Symbol Inc = *S;
798
- ++Inc.References ;
799
- Symbols.insert (Inc);
800
- }
801
- };
802
- for (const NamedDecl *ND : ReferencedDecls) {
803
- if (auto ID = getSymbolID (ND)) {
804
- IncRef (ID);
818
+ // SymbolSlab::Builder returns const symbols because strings are interned
819
+ // and modifying returned symbols without inserting again wouldn't go
820
+ // well. const_cast is safe here as we're modifying a data owned by the
821
+ // Symbol. This reduces time spent in SymbolCollector by ~1%.
822
+ ++const_cast <Symbol *>(S)->References ;
805
823
}
806
824
}
807
825
if (Opts.CollectMacro ) {
808
826
assert (PP);
809
827
// First, drop header guards. We can't identify these until EOF.
810
828
for (const IdentifierInfo *II : IndexedMacros) {
811
829
if (const auto *MI = PP->getMacroDefinition (II).getMacroInfo ())
812
- if (auto ID = getSymbolID (II->getName (), MI, PP->getSourceManager ()))
830
+ if (auto ID =
831
+ getSymbolIDCached (II->getName (), MI, PP->getSourceManager ()))
813
832
if (MI->isUsedForHeaderGuard ())
814
833
Symbols.erase (ID);
815
834
}
816
- // Now increment refcounts.
817
- for (const IdentifierInfo *II : ReferencedMacros) {
818
- if (const auto *MI = PP->getMacroDefinition (II).getMacroInfo ())
819
- if (auto ID = getSymbolID (II->getName (), MI, PP->getSourceManager ()))
820
- IncRef (ID);
821
- }
822
835
}
823
836
// Fill in IncludeHeaders.
824
837
// We delay this until end of TU so header guards are all resolved.
@@ -852,58 +865,7 @@ void SymbolCollector::finish() {
852
865
}
853
866
}
854
867
855
- const auto &SM = ASTCtx->getSourceManager ();
856
- auto CollectRef = [&](SymbolID ID, const SymbolRef &LocAndRole,
857
- bool Spelled = false ) {
858
- auto FileID = SM.getFileID (LocAndRole.Loc );
859
- // FIXME: use the result to filter out references.
860
- shouldIndexFile (FileID);
861
- if (const auto *FE = SM.getFileEntryForID (FileID)) {
862
- auto Range = getTokenRange (LocAndRole.Loc , SM, ASTCtx->getLangOpts ());
863
- Ref R;
864
- R.Location .Start = Range.first ;
865
- R.Location .End = Range.second ;
866
- R.Location .FileURI = HeaderFileURIs->toURI (FE).c_str ();
867
- R.Kind = toRefKind (LocAndRole.Roles , Spelled);
868
- R.Container = getSymbolID (LocAndRole.Container );
869
- Refs.insert (ID, R);
870
- }
871
- };
872
- // Populate Refs slab from MacroRefs.
873
- // FIXME: All MacroRefs are marked as Spelled now, but this should be checked.
874
- for (const auto &IDAndRefs : MacroRefs)
875
- for (const auto &LocAndRole : IDAndRefs.second )
876
- CollectRef (IDAndRefs.first , LocAndRole, /* Spelled=*/ true );
877
- // Populate Refs slab from DeclRefs.
878
- llvm::DenseMap<FileID, std::vector<syntax::Token>> FilesToTokensCache;
879
- for (auto &DeclAndRef : DeclRefs) {
880
- if (auto ID = getSymbolID (DeclAndRef.first )) {
881
- for (auto &LocAndRole : DeclAndRef.second ) {
882
- const auto FileID = SM.getFileID (LocAndRole.Loc );
883
- // FIXME: It's better to use TokenBuffer by passing spelled tokens from
884
- // the caller of SymbolCollector.
885
- if (!FilesToTokensCache.count (FileID))
886
- FilesToTokensCache[FileID] =
887
- syntax::tokenize (FileID, SM, ASTCtx->getLangOpts ());
888
- llvm::ArrayRef<syntax::Token> Tokens = FilesToTokensCache[FileID];
889
- // Check if the referenced symbol is spelled exactly the same way the
890
- // corresponding NamedDecl is. If it is, mark this reference as spelled.
891
- const auto *IdentifierToken =
892
- spelledIdentifierTouching (LocAndRole.Loc , Tokens);
893
- DeclarationName Name = DeclAndRef.first ->getDeclName ();
894
- const auto NameKind = Name.getNameKind ();
895
- bool IsTargetKind = NameKind == DeclarationName::Identifier ||
896
- NameKind == DeclarationName::CXXConstructorName;
897
- bool Spelled = IdentifierToken && IsTargetKind &&
898
- Name.getAsString () == IdentifierToken->text (SM);
899
- CollectRef (ID, LocAndRole, Spelled);
900
- }
901
- }
902
- }
903
-
904
- ReferencedDecls.clear ();
905
- ReferencedMacros.clear ();
906
- DeclRefs.clear ();
868
+ ReferencedSymbols.clear ();
907
869
IncludeFiles.clear ();
908
870
}
909
871
@@ -983,16 +945,18 @@ void SymbolCollector::addDefinition(const NamedDecl &ND,
983
945
const Symbol &DeclSym) {
984
946
if (DeclSym.Definition )
985
947
return ;
948
+ const auto &SM = ND.getASTContext ().getSourceManager ();
949
+ auto Loc = nameLocation (ND, SM);
950
+ shouldIndexFile (SM.getFileID (Loc));
951
+ auto DefLoc = getTokenLocation (Loc);
986
952
// If we saw some forward declaration, we end up copying the symbol.
987
953
// This is not ideal, but avoids duplicating the "is this a definition" check
988
954
// in clang::index. We should only see one definition.
955
+ if (!DefLoc)
956
+ return ;
989
957
Symbol S = DeclSym;
990
- const auto &SM = ND.getASTContext ().getSourceManager ();
991
- auto Loc = nameLocation (ND, SM);
992
958
// FIXME: use the result to filter out symbols.
993
- shouldIndexFile (SM.getFileID (Loc));
994
- if (auto DefLoc = getTokenLocation (Loc))
995
- S.Definition = *DefLoc;
959
+ S.Definition = *DefLoc;
996
960
Symbols.insert (S);
997
961
}
998
962
@@ -1005,5 +969,36 @@ bool SymbolCollector::shouldIndexFile(FileID FID) {
1005
969
return I.first ->second ;
1006
970
}
1007
971
972
+ void SymbolCollector::addRef (SymbolID ID, const SymbolRef &SR) {
973
+ const auto &SM = ASTCtx->getSourceManager ();
974
+ // FIXME: use the result to filter out references.
975
+ shouldIndexFile (SR.FID );
976
+ if (const auto *FE = SM.getFileEntryForID (SR.FID )) {
977
+ auto Range = getTokenRange (SR.Loc , SM, ASTCtx->getLangOpts ());
978
+ Ref R;
979
+ R.Location .Start = Range.first ;
980
+ R.Location .End = Range.second ;
981
+ R.Location .FileURI = HeaderFileURIs->toURI (FE).c_str ();
982
+ R.Kind = toRefKind (SR.Roles , SR.Spelled );
983
+ R.Container = getSymbolIDCached (SR.Container );
984
+ Refs.insert (ID, R);
985
+ }
986
+ }
987
+
988
+ SymbolID SymbolCollector::getSymbolIDCached (const Decl *D) {
989
+ auto It = DeclToIDCache.try_emplace (D, SymbolID{});
990
+ if (It.second )
991
+ It.first ->second = getSymbolID (D);
992
+ return It.first ->second ;
993
+ }
994
+
995
+ SymbolID SymbolCollector::getSymbolIDCached (const llvm::StringRef MacroName,
996
+ const MacroInfo *MI,
997
+ const SourceManager &SM) {
998
+ auto It = MacroToIDCache.try_emplace (MI, SymbolID{});
999
+ if (It.second )
1000
+ It.first ->second = getSymbolID (MacroName, MI, SM);
1001
+ return It.first ->second ;
1002
+ }
1008
1003
} // namespace clangd
1009
1004
} // namespace clang
0 commit comments