// Only a subset of SymbolCollector::Options are respected:
// - include paths are always collected, and canonicalized appropriately
// - references are always counted
-// - main-file refs are collected (if RefsCallback is non-null)
+// - all references are collected (if RefsCallback is non-null)
// - the symbol origin is always Static
-// FIXME: refs from headers should also be collected.
std::unique_ptr<FrontendAction>
createStaticIndexingAction(SymbolCollector::Options Opts,
std::function<void(SymbolSlab)> SymbolsCallback,
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Index/IndexSymbol.h"
return true;
if (!shouldCollectSymbol(*ND, *ASTCtx, Opts))
return true;
- if (CollectRef && SM.getFileID(SpellingLoc) == SM.getMainFileID())
+ if (CollectRef &&
+ (Opts.RefsInHeaders || SM.getFileID(SpellingLoc) == SM.getMainFileID()))
DeclRefs[ND].emplace_back(SpellingLoc, Roles);
// Don't continue indexing if this is a mere reference.
if (IsOnlyRef)
}
const auto &SM = ASTCtx->getSourceManager();
- auto* MainFileEntry = SM.getFileEntryForID(SM.getMainFileID());
+ llvm::DenseMap<FileID, std::string> URICache;
+ auto GetURI = [&](FileID FID) -> llvm::Optional<std::string> {
+ auto Found = URICache.find(FID);
+ if (Found == URICache.end()) {
+ // Ignore cases where we can not find a corresponding file entry
+ // for the loc, thoses are not interesting, e.g. symbols formed
+ // via macro concatenation.
+ if (auto *FileEntry = SM.getFileEntryForID(FID)) {
+ auto FileURI = toURI(SM, FileEntry->getName(), Opts);
+ if (!FileURI) {
+ log("Failed to create URI for file: {0}\n", FileEntry);
+ FileURI = ""; // reset to empty as we also want to cache this case.
+ }
+ Found = URICache.insert({FID, *FileURI}).first;
+ }
+ }
+ return Found->second;
+ };
- if (auto MainFileURI = toURI(SM, MainFileEntry->getName(), Opts)) {
- std::string MainURI = *MainFileURI;
+ if (auto MainFileURI = GetURI(SM.getMainFileID())) {
for (const auto &It : DeclRefs) {
if (auto ID = getSymbolID(It.first)) {
for (const auto &LocAndRole : It.second) {
- Ref R;
- auto Range =
- getTokenRange(LocAndRole.first, SM, ASTCtx->getLangOpts());
- R.Location.Start = Range.first;
- R.Location.End = Range.second;
- R.Location.FileURI = MainURI;
- R.Kind = toRefKind(LocAndRole.second);
- Refs.insert(*ID, R);
+ auto FileID = SM.getFileID(LocAndRole.first);
+ if (auto FileURI = GetURI(FileID)) {
+ auto Range =
+ getTokenRange(LocAndRole.first, SM, ASTCtx->getLangOpts());
+ Ref R;
+ R.Location.Start = Range.first;
+ R.Location.End = Range.second;
+ R.Location.FileURI = *FileURI;
+ R.Kind = toRefKind(LocAndRole.second);
+ Refs.insert(*ID, R);
+ }
}
}
}
- } else {
- log("Failed to create URI for main file: {0}", MainFileEntry->getName());
}
ReferencedDecls.clear();
/// The symbol ref kinds that will be collected.
/// If not set, SymbolCollector will not collect refs.
RefKind RefFilter = RefKind::Unknown;
+ /// If set to true, SymbolCollector will collect all refs (from main file
+ /// and included headers); otherwise, only refs from main file will be
+ /// collected.
+ /// This flag is only meaningful when RefFilter is set.
+ bool RefsInHeaders = false;
// Every symbol collected will be stamped with this origin.
SymbolOrigin Origin = SymbolOrigin::Unknown;
/// Collect macros.
EXPECT_THAT(Refs, Not(Contains(Pair(findSymbol(MainSymbols, "c").ID, _))));
}
+TEST_F(SymbolCollectorTest, RefsInHeaders) {
+ CollectorOpts.RefFilter = RefKind::All;
+ CollectorOpts.RefsInHeaders = true;
+ Annotations Header(R"(
+ class [[Foo]] {};
+ )");
+ runSymbolCollector(Header.code(), "");
+ EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "Foo").ID,
+ HaveRanges(Header.ranges()))));
+}
+
TEST_F(SymbolCollectorTest, References) {
const std::string Header = R"(
class W;