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 = @@ -711,6 +716,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 @@ -251,6 +251,7 @@ #define BAR [[BAR]])cpp", R"cpp(#line 0 ".*main.cpp" +#undef BAR #line 2 #define BAR )cpp", @@ -262,6 +263,7 @@ [[BAR]])cpp", R"cpp(#line 0 ".*main.cpp" +#undef BAR #line 2 #define BAR )cpp", @@ -273,6 +275,7 @@ BAR [[BAR]])cpp", R"cpp(#line 0 ".*main.cpp" +#undef BAR #line 3 #define BAR )cpp", @@ -305,8 +308,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"); @@ -624,7 +629,7 @@ llvm::StringMap AdditionalFiles; AdditionalFiles["foo.h"] = "#pragma once"; - AdditionalFiles["bar.h"] = "#pragma once"; + AdditionalFiles["barx.h"] = "#pragma once"; llvm::StringLiteral BaselinePreamble("#define FOO 1\n[[#include \"foo.h\"]]"); { // Check with removals from preamble. @@ -637,23 +642,23 @@ { // Check with additions to preamble. Annotations Code(BaselinePreamble); - Annotations NewCode(("[[#include \"bar.h\"]]\n" + BaselinePreamble).str()); + Annotations NewCode(("[[#include \"barx.h\"]]\n" + BaselinePreamble).str()); auto AST = createPatchedAST(Code.code(), NewCode.code(), AdditionalFiles); - // FIXME: This is just all sorts of wrong. We point at the FOO from baseline - // claiming it's redefined and not point at the new include of "bar.h". + // FIXME: Should preserve existing diagnostics. + EXPECT_THAT(mainFileDiagRanges(*AST), + UnorderedElementsAre(NewCode.ranges()[0])); } { 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])); } }