Index: clangd/AST.h =================================================================== --- clangd/AST.h +++ clangd/AST.h @@ -24,6 +24,14 @@ namespace clangd { +// Returns true if the complete name of decl \p D is spelled in the source code. +// This is not the case for +// * symbols formed via macro concatenation, the spelling location will +// be "" +// * symbols controlled and defined by a compile command-line option +// `-DName=foo`, the spelling location will be "". +bool SpelledInSourceCode(const Decl *D); + /// Find the identifier source location of the given D. /// /// The returned location is usually the spelling location where the name of the Index: clangd/AST.cpp =================================================================== --- clangd/AST.cpp +++ clangd/AST.cpp @@ -11,6 +11,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Index/USRGeneration.h" @@ -18,25 +19,26 @@ namespace clangd { using namespace llvm; -SourceLocation findNameLoc(const clang::Decl* D) { - const auto& SM = D->getASTContext().getSourceManager(); +bool SpelledInSourceCode(const Decl *D) { + const auto &SM = D->getASTContext().getSourceManager(); + auto Loc = D->getLocation(); // FIXME: Revisit the strategy, the heuristic is limitted when handling // macros, we should use the location where the whole definition occurs. - SourceLocation SpellingLoc = SM.getSpellingLoc(D->getLocation()); - if (D->getLocation().isMacroID()) { - std::string PrintLoc = SpellingLoc.printToString(SM); + if (Loc.isMacroID()) { + std::string PrintLoc = SM.getSpellingLoc(Loc).printToString(SM); if (llvm::StringRef(PrintLoc).startswith("")) { - // We use the expansion location for the following symbols, as spelling - // locations of these symbols are not interesting to us: - // * symbols formed via macro concatenation, the spelling location will - // be "" - // * symbols controlled and defined by a compile command-line option - // `-DName=foo`, the spelling location will be "". - SpellingLoc = SM.getExpansionRange(D->getLocation()).getBegin(); - } + llvm::StringRef(PrintLoc).startswith("")) + return false; } - return SpellingLoc; + return true; +} + +SourceLocation findNameLoc(const clang::Decl* D) { + const auto &SM = D->getASTContext().getSourceManager(); + if (!SpelledInSourceCode(D)) + // Use the expansion location as spelling location is not interesting. + return SM.getExpansionRange(D->getLocation()).getBegin(); + return SM.getSpellingLoc(D->getLocation()); } std::string printQualifiedName(const NamedDecl &ND) { Index: clangd/Quality.cpp =================================================================== --- clangd/Quality.cpp +++ clangd/Quality.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// #include "Quality.h" +#include "AST.h" #include "FileDistance.h" #include "URI.h" #include "index/Index.h" @@ -178,7 +179,8 @@ if (SemaCCResult.Declaration) { if (auto *ID = SemaCCResult.Declaration->getIdentifier()) - ReservedName = ReservedName || isReserved(ID->getName()); + ReservedName = ReservedName || isReserved(ID->getName()) || + !SpelledInSourceCode(SemaCCResult.Declaration); } else if (SemaCCResult.Kind == CodeCompletionResult::RK_Macro) ReservedName = ReservedName || isReserved(SemaCCResult.Macro->getName()); } Index: unittests/clangd/QualityTests.cpp =================================================================== --- unittests/clangd/QualityTests.cpp +++ unittests/clangd/QualityTests.cpp @@ -45,7 +45,15 @@ [[deprecated]] int _f() { return _X; } + + #define DECL_NAME(x, y) x##_##y##_Decl + #define DECL(x, y) class DECL_NAME(x, y) {}; + DECL(X, Y); // X_Y_Decl + + class MAC {}; )cpp"); + Header.ExtraArgs = {"-DMAC=mac_name"}; + auto Symbols = Header.headerSymbols(); auto AST = Header.build(); @@ -56,6 +64,16 @@ EXPECT_EQ(Quality.References, SymbolQualitySignals().References); EXPECT_EQ(Quality.Category, SymbolQualitySignals::Variable); + Quality.ReservedName = false; + Quality.merge( + CodeCompletionResult(&findDecl(AST, "X_Y_Decl"), /*Priority=*/42)); + EXPECT_TRUE(Quality.ReservedName); + + Quality.ReservedName = false; + Quality.merge( + CodeCompletionResult(&findDecl(AST, "mac_name"), /*Priority=*/42)); + EXPECT_TRUE(Quality.ReservedName); + Symbol F = findSymbol(Symbols, "_f"); F.References = 24; // TestTU doesn't count references, so fake it. Quality = {};