kbobyrev updated this revision to Diff 242577.
kbobyrev marked 7 inline comments as done.
kbobyrev added a comment.
Address the comments.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D72746/new/
https://reviews.llvm.org/D72746
Files:
clang-tools-extra/clangd/index/Ref.h
clang-tools-extra/clangd/index/SymbolCollector.cpp
clang-tools-extra/clangd/index/SymbolLocation.h
clang-tools-extra/clangd/unittests/RenameTests.cpp
clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
clang/include/clang/Tooling/Syntax/Tokens.h
clang/lib/Tooling/Syntax/Tokens.cpp
Index: clang/lib/Tooling/Syntax/Tokens.cpp
===================================================================
--- clang/lib/Tooling/Syntax/Tokens.cpp
+++ clang/lib/Tooling/Syntax/Tokens.cpp
@@ -256,21 +256,27 @@
llvm::ArrayRef<syntax::Token>
syntax::spelledTokensTouching(SourceLocation Loc,
- const syntax::TokenBuffer &Tokens) {
+ llvm::ArrayRef<syntax::Token> Tokens) {
assert(Loc.isFileID());
- llvm::ArrayRef<syntax::Token> All =
- Tokens.spelledTokens(Tokens.sourceManager().getFileID(Loc));
auto *Right = llvm::partition_point(
- All, [&](const syntax::Token &Tok) { return Tok.location() < Loc; });
- bool AcceptRight = Right != All.end() && Right->location() <= Loc;
- bool AcceptLeft = Right != All.begin() && (Right - 1)->endLocation() >= Loc;
+ Tokens, [&](const syntax::Token &Tok) { return Tok.location() < Loc; });
+ bool AcceptRight = Right != Tokens.end() && Right->location() <= Loc;
+ bool AcceptLeft =
+ Right != Tokens.begin() && (Right - 1)->endLocation() >= Loc;
return llvm::makeArrayRef(Right - (AcceptLeft ? 1 : 0),
Right + (AcceptRight ? 1 : 0));
}
+llvm::ArrayRef<syntax::Token>
+syntax::spelledTokensTouching(SourceLocation Loc,
+ const syntax::TokenBuffer &Tokens) {
+ return spelledTokensTouching(
+ Loc, Tokens.spelledTokens(Tokens.sourceManager().getFileID(Loc)));
+}
+
const syntax::Token *
syntax::spelledIdentifierTouching(SourceLocation Loc,
- const syntax::TokenBuffer &Tokens) {
+ llvm::ArrayRef<syntax::Token> Tokens) {
for (const syntax::Token &Tok : spelledTokensTouching(Loc, Tokens)) {
if (Tok.kind() == tok::identifier)
return &Tok;
@@ -278,6 +284,13 @@
return nullptr;
}
+const syntax::Token *
+syntax::spelledIdentifierTouching(SourceLocation Loc,
+ const syntax::TokenBuffer &Tokens) {
+ return spelledIdentifierTouching(
+ Loc, Tokens.spelledTokens(Tokens.sourceManager().getFileID(Loc)));
+}
+
std::vector<const syntax::Token *>
TokenBuffer::macroExpansions(FileID FID) const {
auto FileIt = Files.find(FID);
Index: clang/include/clang/Tooling/Syntax/Tokens.h
===================================================================
--- clang/include/clang/Tooling/Syntax/Tokens.h
+++ clang/include/clang/Tooling/Syntax/Tokens.h
@@ -316,11 +316,16 @@
/// The spelled tokens that overlap or touch a spelling location Loc.
/// This always returns 0-2 tokens.
llvm::ArrayRef<syntax::Token>
+spelledTokensTouching(SourceLocation Loc, llvm::ArrayRef<syntax::Token> Tokens);
+llvm::ArrayRef<syntax::Token>
spelledTokensTouching(SourceLocation Loc, const syntax::TokenBuffer &Tokens);
/// The identifier token that overlaps or touches a spelling location Loc.
/// If there is none, returns nullptr.
const syntax::Token *
+spelledIdentifierTouching(SourceLocation Loc,
+ llvm::ArrayRef<syntax::Token> Tokens);
+const syntax::Token *
spelledIdentifierTouching(SourceLocation Loc,
const syntax::TokenBuffer &Tokens);
Index: clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
+++ clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
@@ -700,6 +700,40 @@
EXPECT_THAT(Refs, IsEmpty());
}
+TEST_F(SymbolCollectorTest, SpelledReference) {
+ Annotations Header(R"cpp(
+ struct Foo;
+ #define MACRO Foo
+ )cpp");
+ Annotations Main(R"cpp(
+ struct $spelled[[Foo]] {
+ $spelled[[Foo]]();
+ ~$spelled[[Foo]]();
+ };
+ $spelled[[Foo]] Variable1;
+ $implicit[[MACRO]] Variable2;
+ )cpp");
+ CollectorOpts.RefFilter = RefKind::All;
+ CollectorOpts.RefsInHeaders = false;
+ runSymbolCollector(Header.code(), Main.code());
+ const auto SpelledRanges = Main.ranges("spelled");
+ const auto ImplicitRanges = Main.ranges("implicit");
+ auto AllRanges = SpelledRanges;
+ AllRanges.insert(end(AllRanges), begin(ImplicitRanges), end(ImplicitRanges));
+ EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "Foo").ID,
+ HaveRanges(AllRanges))));
+ RefSlab::Builder SpelledSlabBuilder;
+ for (const auto &SymbolAndRefs : Refs) {
+ const auto Symbol = SymbolAndRefs.first;
+ for (const auto &Ref : SymbolAndRefs.second)
+ if ((Ref.Kind & RefKind::Spelled) != RefKind::Unknown)
+ SpelledSlabBuilder.insert(Symbol, Ref);
+ }
+ const auto SpelledRefs = std::move(SpelledSlabBuilder).build();
+ EXPECT_THAT(SpelledRefs, Contains(Pair(findSymbol(Symbols, "Foo").ID,
+ HaveRanges(SpelledRanges))));
+}
+
TEST_F(SymbolCollectorTest, NameReferences) {
CollectorOpts.RefFilter = RefKind::All;
CollectorOpts.RefsInHeaders = true;
Index: clang-tools-extra/clangd/unittests/RenameTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/RenameTests.cpp
+++ clang-tools-extra/clangd/unittests/RenameTests.cpp
@@ -837,7 +837,7 @@
{
// variables.
R"cpp(
- static const int [[VA^R]] = 123;
+ static const int [[VA^R]] = 123;
)cpp",
R"cpp(
#include "foo.h"
Index: clang-tools-extra/clangd/index/SymbolLocation.h
===================================================================
--- clang-tools-extra/clangd/index/SymbolLocation.h
+++ clang-tools-extra/clangd/index/SymbolLocation.h
@@ -9,6 +9,7 @@
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_SYMBOL_LOCATION_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_SYMBOL_LOCATION_H
+#include "Protocol.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdint>
Index: clang-tools-extra/clangd/index/SymbolCollector.cpp
===================================================================
--- clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -28,6 +28,7 @@
#include "clang/Index/IndexingAction.h"
#include "clang/Index/USRGeneration.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Tooling/Syntax/Tokens.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -179,8 +180,17 @@
isa<TagDecl>(&ND) && !isInsideMainFile(ND.getLocation(), SM);
}
-RefKind toRefKind(index::SymbolRoleSet Roles) {
- return static_cast<RefKind>(static_cast<unsigned>(RefKind::All) & Roles);
+RefKind toRefKind(index::SymbolRoleSet Roles, bool Spelled = false) {
+ RefKind Result = RefKind::Unknown;
+ if (Roles & static_cast<unsigned>(index::SymbolRole::Declaration))
+ Result |= RefKind::Declaration;
+ if (Roles & static_cast<unsigned>(index::SymbolRole::Definition))
+ Result |= RefKind::Definition;
+ if (Roles & static_cast<unsigned>(index::SymbolRole::Reference))
+ Result |= RefKind::Reference;
+ if (Spelled)
+ Result |= RefKind::Spelled;
+ return Result;
}
bool shouldIndexRelation(const index::SymbolRelation &R) {
@@ -291,7 +301,7 @@
// occurrence inside the base-specifier.
processRelations(*ND, *ID, Relations);
- bool CollectRef = static_cast<unsigned>(Opts.RefFilter) & Roles;
+ bool CollectRef = static_cast<bool>(Opts.RefFilter & toRefKind(Roles));
bool IsOnlyRef =
!(Roles & (static_cast<unsigned>(index::SymbolRole::Declaration) |
static_cast<unsigned>(index::SymbolRole::Definition)));
@@ -556,7 +566,8 @@
};
auto CollectRef =
[&](SymbolID ID,
- const std::pair<SourceLocation, index::SymbolRoleSet> &LocAndRole) {
+ const std::pair<SourceLocation, index::SymbolRoleSet> &LocAndRole,
+ bool Spelled = false) {
auto FileID = SM.getFileID(LocAndRole.first);
// FIXME: use the result to filter out references.
shouldIndexFile(FileID);
@@ -567,21 +578,36 @@
R.Location.Start = Range.first;
R.Location.End = Range.second;
R.Location.FileURI = FileURI->c_str();
- R.Kind = toRefKind(LocAndRole.second);
+ R.Kind = toRefKind(LocAndRole.second, Spelled);
Refs.insert(ID, R);
}
};
// Populate Refs slab from MacroRefs.
- for (const auto &IDAndRefs : MacroRefs) {
+ for (const auto &IDAndRefs : MacroRefs)
for (const auto &LocAndRole : IDAndRefs.second)
CollectRef(IDAndRefs.first, LocAndRole);
- }
// Populate Refs slab from DeclRefs.
- if (auto MainFileURI = GetURI(SM.getMainFileID())) {
- for (const auto &It : DeclRefs) {
- if (auto ID = getSymbolID(It.first)) {
- for (const auto &LocAndRole : It.second)
- CollectRef(*ID, LocAndRole);
+ llvm::DenseMap<FileID, std::vector<syntax::Token>> FilesToTokensCache;
+ for (auto &DeclAndRef : DeclRefs) {
+ if (auto ID = getSymbolID(DeclAndRef.first)) {
+ for (auto &LocAndRole : DeclAndRef.second) {
+ const auto FileID = SM.getFileID(LocAndRole.first);
+ // FIXME: It's better to use TokenBuffer by passing spelled tokens from
+ // the caller of SymbolCollector.
+ if (!FilesToTokensCache.count(FileID))
+ FilesToTokensCache[FileID] =
+ syntax::tokenize(FileID, SM, ASTCtx->getLangOpts());
+ llvm::ArrayRef<syntax::Token> Tokens = FilesToTokensCache[FileID];
+ // Check if the referenced symbol is spelled exactly the same way the
+ // corresponding NamedDecl is. If it isn't, mark this reference as
+ // implicit. An example of implicit reference (implicit = !spelled)
+ // would be a macro expansion.
+ const auto *IdentifierToken =
+ spelledIdentifierTouching(LocAndRole.first, Tokens);
+ DeclarationName Name = DeclAndRef.first->getDeclName();
+ bool Spelled = IdentifierToken && Name.isIdentifier() &&
+ Name.getAsString() == IdentifierToken->text(SM);
+ CollectRef(*ID, LocAndRole, Spelled);
}
}
}
Index: clang-tools-extra/clangd/index/Ref.h
===================================================================
--- clang-tools-extra/clangd/index/Ref.h
+++ clang-tools-extra/clangd/index/Ref.h
@@ -27,10 +27,43 @@
/// This is a bitfield which can be combined from different kinds.
enum class RefKind : uint8_t {
Unknown = 0,
- Declaration = static_cast<uint8_t>(index::SymbolRole::Declaration),
- Definition = static_cast<uint8_t>(index::SymbolRole::Definition),
- Reference = static_cast<uint8_t>(index::SymbolRole::Reference),
- All = Declaration | Definition | Reference,
+ // Points to symbol declaration. Example:
+ //
+ // class Foo;
+ // ^ Foo declaration
+ // Foo foo;
+ // ^ this does not reference Foo declaration
+ Declaration = 1 << 0,
+ // Points to symbol definition. Example:
+ //
+ // int foo();
+ // ^ references foo declaration, but not foo definition
+ // int foo() { return 42; }
+ // ^ references foo definition, but not declaration
+ // bool bar() { return true; }
+ // ^ references both definition and declaration
+ Definition = 1 << 1,
+ // Points to symbol reference. Example:
+ //
+ // int Foo = 42;
+ // int Bar = Foo + 1;
+ // ^ this is a reference to Foo
+ Reference = 1 << 2,
+ // The reference explicitly spells out declaration's name. Such references can
+ // not come from macro expansions or implicit AST nodes.
+ //
+ // class Foo { public: Foo() {} };
+ // ^ references declaration, definition and explicitly spells out name
+ // #define MACRO Foo
+ // v there is an implicit constructor call here which is not a spelled ref
+ // Foo foo;
+ // ^ this reference explicitly spells out Foo's name
+ // struct Bar {
+ // MACRO Internal;
+ // ^ this references Foo, but does not explicitly spell out its name
+ // };
+ Spelled = 1 << 3,
+ All = Declaration | Definition | Reference | Spelled,
};
inline RefKind operator|(RefKind L, RefKind R) {
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits