diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -1874,9 +1874,10 @@ ? std::move(Flow).runWithoutSema(ParseInput.Contents, *Offset, *ParseInput.TFS) : std::move(Flow).run({FileName, *Offset, *Preamble, - // We want to serve code completions with - // low latency, so don't bother patching. - /*PreamblePatch=*/llvm::None, ParseInput}); + /*PreamblePatch=*/ + PreamblePatch::createMacroPatch( + FileName, ParseInput, *Preamble), + ParseInput}); } SignatureHelp signatureHelp(PathRef FileName, Position Pos, @@ -1898,7 +1899,8 @@ Result), Options, {FileName, *Offset, Preamble, - PreamblePatch::create(FileName, ParseInput, Preamble), ParseInput}); + PreamblePatch::createFullPatch(FileName, ParseInput, Preamble), + ParseInput}); return Result; } diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp --- a/clang-tools-extra/clangd/ParsedAST.cpp +++ b/clang-tools-extra/clangd/ParsedAST.cpp @@ -284,7 +284,7 @@ llvm::Optional Patch; bool PreserveDiags = true; if (Preamble) { - Patch = PreamblePatch::create(Filename, Inputs, *Preamble); + Patch = PreamblePatch::createFullPatch(Filename, Inputs, *Preamble); Patch->apply(*CI); PreserveDiags = Patch->preserveDiagnostics(); } diff --git a/clang-tools-extra/clangd/Preamble.h b/clang-tools-extra/clangd/Preamble.h --- a/clang-tools-extra/clangd/Preamble.h +++ b/clang-tools-extra/clangd/Preamble.h @@ -97,15 +97,20 @@ /// new include directives. class PreamblePatch { public: + enum class PatchType { MacroDirectives, All }; /// \p Preamble is used verbatim. static PreamblePatch unmodified(const PreambleData &Preamble); /// Builds a patch that contains new PP directives introduced to the preamble /// section of \p Modified compared to \p Baseline. /// FIXME: This only handles include directives, we should at least handle /// define/undef. - static PreamblePatch create(llvm::StringRef FileName, - const ParseInputs &Modified, - const PreambleData &Baseline); + static PreamblePatch createFullPatch(llvm::StringRef FileName, + const ParseInputs &Modified, + const PreambleData &Baseline); + static PreamblePatch createMacroPatch(llvm::StringRef FileName, + const ParseInputs &Modified, + const PreambleData &Baseline); + /// Adjusts CI (which compiles the modified inputs) to be used with the /// baseline preamble. This is done by inserting an artifical include to the /// \p CI that contains new directives calculated in create. @@ -129,6 +134,11 @@ bool preserveDiagnostics() const { return PatchContents.empty(); } private: + static PreamblePatch create(llvm::StringRef FileName, + const ParseInputs &Modified, + const PreambleData &Baseline, + PatchType PatchType); + PreamblePatch() = default; std::string PatchContents; std::string PatchFileName; 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 @@ -142,10 +142,11 @@ unsigned DirectiveLine; // Full text that's representing the directive, including the `#`. std::string Text; + unsigned Offset; bool operator==(const TextualPPDirective &RHS) const { - return std::tie(DirectiveLine, Text) == - std::tie(RHS.DirectiveLine, RHS.Text); + return std::tie(DirectiveLine, Offset, Text) == + std::tie(RHS.DirectiveLine, RHS.Offset, RHS.Text); } }; @@ -155,7 +156,7 @@ std::string spellDirective(llvm::StringRef Prefix, CharSourceRange DirectiveRange, const LangOptions &LangOpts, const SourceManager &SM, - unsigned &DirectiveLine) { + unsigned &DirectiveLine, unsigned &Offset) { std::string SpelledDirective; llvm::raw_string_ostream OS(SpelledDirective); OS << Prefix; @@ -169,6 +170,7 @@ auto DecompLoc = SM.getDecomposedLoc(DirectiveRange.getBegin()); DirectiveLine = SM.getLineNumber(DecompLoc.first, DecompLoc.second); + Offset = DecompLoc.second; auto TargetColumn = SM.getColumnNumber(DecompLoc.first, DecompLoc.second) - 1; // Pad with spaces before DirectiveRange to make sure it will be on right @@ -217,7 +219,7 @@ spellDirective("#define ", CharSourceRange::getTokenRange( MI->getDefinitionLoc(), MI->getDefinitionEndLoc()), - LangOpts, SM, TD.DirectiveLine); + LangOpts, SM, TD.DirectiveLine, TD.Offset); } private: @@ -426,7 +428,8 @@ PreamblePatch PreamblePatch::create(llvm::StringRef FileName, const ParseInputs &Modified, - const PreambleData &Baseline) { + const PreambleData &Baseline, + PatchType PatchType) { trace::Span Tracer("CreatePreamblePatch"); SPAN_ATTACH(Tracer, "File", FileName); assert(llvm::sys::path::is_absolute(FileName) && "relative FileName!"); @@ -475,7 +478,7 @@ escapeBackslashAndQuotes(FileName, Patch); Patch << "\"\n"; - if (IncludesChanged) { + if (IncludesChanged && PatchType == PatchType::All) { // We are only interested in newly added includes, record the ones in // Baseline for exclusion. llvm::DenseMap, @@ -528,6 +531,18 @@ return PP; } +PreamblePatch PreamblePatch::createFullPatch(llvm::StringRef FileName, + const ParseInputs &Modified, + const PreambleData &Baseline) { + return create(FileName, Modified, Baseline, PatchType::All); +} + +PreamblePatch PreamblePatch::createMacroPatch(llvm::StringRef FileName, + const ParseInputs &Modified, + const PreambleData &Baseline) { + return create(FileName, Modified, Baseline, PatchType::MacroDirectives); +} + void PreamblePatch::apply(CompilerInvocation &CI) const { // No need to map an empty file. if (PatchContents.empty()) diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -3262,6 +3262,23 @@ EXPECT_THAT(Results.Completions, UnorderedElementsAre(Labeled("BarExt"))); } } + +TEST(CompletionTest, PreambleCodeComplete) { + llvm::StringLiteral Baseline = "\n#define MACRO 12\nint num = MACRO;"; + llvm::StringLiteral ModifiedCC = + "#include \"header.h\"\n#define MACRO 12\nint num = MACRO; int num2 = M^"; + + Annotations Test(ModifiedCC); + auto BaselineTU = TestTU::withCode(Baseline); + auto ModifiedTU = TestTU::withCode(Test.code()); + + MockFS FS; + auto Inputs = ModifiedTU.inputs(FS); + auto Result = codeComplete(testPath(ModifiedTU.Filename), Test.point(), + BaselineTU.preamble().get(), Inputs, {}); + EXPECT_THAT(Result.Completions, Not(testing::IsEmpty())); +} + } // namespace } // namespace clangd } // namespace clang 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 @@ -59,7 +59,8 @@ // Create the patch. TU.Code = ModifiedContents.str(); auto PI = TU.inputs(FS); - auto PP = PreamblePatch::create(testPath(TU.Filename), PI, *BaselinePreamble); + auto PP = PreamblePatch::createFullPatch(testPath(TU.Filename), PI, + *BaselinePreamble); // Collect patch contents. IgnoreDiagnostics Diags; auto CI = buildCompilerInvocation(PI, Diags); @@ -183,8 +184,8 @@ #include "a.h" #include "b.h" )cpp"; - auto PP = PreamblePatch::create(testPath(TU.Filename), TU.inputs(FS), - *BaselinePreamble); + auto PP = PreamblePatch::createFullPatch(testPath(TU.Filename), TU.inputs(FS), + *BaselinePreamble); // Only a.h should exists in the preamble, as c.h has been dropped and b.h was // newly introduced. EXPECT_THAT(PP.preambleIncludes(), @@ -221,8 +222,8 @@ } MockFS FS; auto TU = TestTU::withCode(Modified); - return PreamblePatch::create(testPath("main.cpp"), TU.inputs(FS), - *BaselinePreamble) + return PreamblePatch::createFullPatch(testPath("main.cpp"), TU.inputs(FS), + *BaselinePreamble) .text() .str(); } @@ -523,8 +524,8 @@ Annotations Modified(Case.Modified); TU.Code = Modified.code().str(); MockFS FS; - auto PP = PreamblePatch::create(testPath(TU.Filename), TU.inputs(FS), - *BaselinePreamble); + auto PP = PreamblePatch::createFullPatch(testPath(TU.Filename), + TU.inputs(FS), *BaselinePreamble); IgnoreDiagnostics Diags; auto CI = buildCompilerInvocation(TU.inputs(FS), Diags); @@ -546,6 +547,13 @@ // Ensure they are dropeed when a patched preamble is used. EXPECT_FALSE(createPatchedAST("", Code)->getDiagnostics()); } + +TEST(PreamblePatch, MacroLoc) { + llvm::StringLiteral Baseline = "\n#define MACRO 12\nint num = MACRO;"; + llvm::StringLiteral Modified = " \n#define MACRO 12\nint num = MACRO;"; + auto AST = createPatchedAST(Baseline, Modified); + ASSERT_TRUE(AST); +} } // namespace } // namespace clangd } // namespace clang