diff --git a/clang-tools-extra/clangd/SourceCode.cpp b/clang-tools-extra/clangd/SourceCode.cpp --- a/clang-tools-extra/clangd/SourceCode.cpp +++ b/clang-tools-extra/clangd/SourceCode.cpp @@ -975,17 +975,30 @@ if (!IdentifierInfo || !IdentifierInfo->hadMacroDefinition()) return None; - // Get the definition just before the searched location so that a macro - // referenced in a '#undef MACRO' can still be found. Note that we only do - // that if Loc is not pointing at start of file. - if (SM.getLocForStartOfFile(SM.getFileID(Loc)) != Loc) - Loc = Loc.getLocWithOffset(-1); - MacroDefinition MacroDef = PP.getMacroDefinitionAtLoc(IdentifierInfo, Loc); - if (auto *MI = MacroDef.getMacroInfo()) - return DefinedMacro{ - IdentifierInfo->getName(), MI, - translatePreamblePatchLocation(MI->getDefinitionLoc(), SM)}; - return None; + // We need to take special case to handle #define and #undef. + // Preprocessor::getMacroDefinitionAtLoc() only considers a macro + // definition to be in scope *after* the location of the macro name in a + // #define that introduces it, and *before* the location of the macro name + // in an #undef that undefines it. To handle these cases, we check for + // the macro being in scope either just after or just before the location + // of the token. In getting the location before, we also take care to check + // for start-of-file. + FileID FID = SM.getFileID(Loc); + assert(Loc != SM.getLocForEndOfFile(FID)); + SourceLocation JustAfterToken = Loc.getLocWithOffset(1); + auto *MacroInfo = + PP.getMacroDefinitionAtLoc(IdentifierInfo, JustAfterToken).getMacroInfo(); + if (!MacroInfo && SM.getLocForStartOfFile(FID) != Loc) { + SourceLocation JustBeforeToken = Loc.getLocWithOffset(-1); + MacroInfo = PP.getMacroDefinitionAtLoc(IdentifierInfo, JustBeforeToken) + .getMacroInfo(); + } + if (!MacroInfo) { + return None; + } + return DefinedMacro{ + IdentifierInfo->getName(), MacroInfo, + translatePreamblePatchLocation(MacroInfo->getDefinitionLoc(), SM)}; } llvm::Expected Edit::apply() const { diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp --- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -1624,6 +1624,14 @@ } )cpp", + R"cpp(// Macro outside preamble + int breakPreamble; + #define [[MA^CRO]](X) (X+1) + void test() { + int x = [[MACRO]]([[MACRO]](1)); + } + )cpp", + R"cpp( int [[v^ar]] = 0; void foo(int s = [[var]]);