diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp --- a/clang-tools-extra/clangd/Preamble.cpp +++ b/clang-tools-extra/clangd/Preamble.cpp @@ -213,6 +213,9 @@ // Full text that's representing the directive, including the `#`. std::string Text; unsigned Offset; + tok::PPKeywordKind Directive; + // Name of the macro being defined in the case of a #define directive. + std::string MacroName; bool operator==(const TextualPPDirective &RHS) const { return std::tie(DirectiveLine, Offset, Text) == @@ -283,6 +286,8 @@ return; TextualDirectives.emplace_back(); TextualPPDirective &TD = TextualDirectives.back(); + TD.Directive = tok::pp_define; + TD.MacroName = MacroNameTok.getIdentifierInfo()->getName().str(); const auto *MI = MD->getMacroInfo(); TD.Text = @@ -722,6 +727,10 @@ // reduce complexity. The former might cause problems because scanning is // imprecise and might pick directives from disabled regions. for (const auto &TD : ModifiedScan->TextualDirectives) { + // Introduce an #undef directive before #defines to suppress any + // re-definition warnings. + if (TD.Directive == tok::pp_define) + Patch << "#undef " << TD.MacroName << '\n'; Patch << "#line " << TD.DirectiveLine << '\n'; Patch << TD.Text << '\n'; } diff --git a/clang-tools-extra/clangd/unittests/PreambleTests.cpp b/clang-tools-extra/clangd/unittests/PreambleTests.cpp --- a/clang-tools-extra/clangd/unittests/PreambleTests.cpp +++ b/clang-tools-extra/clangd/unittests/PreambleTests.cpp @@ -272,6 +272,7 @@ #define BAR [[BAR]])cpp", R"cpp(#line 0 ".*main.cpp" +#undef BAR #line 2 #define BAR )cpp", @@ -283,6 +284,7 @@ [[BAR]])cpp", R"cpp(#line 0 ".*main.cpp" +#undef BAR #line 2 #define BAR )cpp", @@ -294,6 +296,7 @@ BAR [[BAR]])cpp", R"cpp(#line 0 ".*main.cpp" +#undef BAR #line 3 #define BAR )cpp", @@ -326,8 +329,10 @@ )cpp"); llvm::StringLiteral ExpectedPatch(R"cpp(#line 0 ".*main.cpp" +#undef BAR #line 2 #define BAR\(X, Y\) X Y +#undef BAR #line 3 #define BAR\(X\) X )cpp"); @@ -670,14 +675,13 @@ llvm::StringLiteral BaselinePreamble = "#define [[FOO]] 1\n"; Annotations Code(BaselinePreamble); // Check ranges for notes. - Annotations NewCode(("#define [[BARXYZ]] 1\n" + BaselinePreamble + + Annotations NewCode(("#define BARXYZ 1\n" + BaselinePreamble + "void foo();\n#define [[FOO]] 2") .str()); auto AST = createPatchedAST(Code.code(), NewCode.code(), AdditionalFiles); - // FIXME: We shouldn't be warning for BARXYZ, and pointing at the FOO inside - // the baselinepreamble. + // FIXME: We should be pointing at the first definition of FOO in NewCode. EXPECT_THAT(mainFileDiagRanges(*AST), - UnorderedElementsAre(NewCode.ranges()[0], NewCode.ranges()[2])); + UnorderedElementsAre(NewCode.ranges()[1])); } }