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 @@ -182,6 +182,7 @@ std::vector PatchedDiags; PreambleBounds ModifiedBounds = {0, false}; const PreambleData *Baseline = nullptr; + std::vector PatchedMarks; }; } // namespace clangd 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 @@ -15,7 +15,9 @@ #include "Protocol.h" #include "SourceCode.h" #include "clang-include-cleaner/Record.h" +#include "index/CanonicalIncludes.h" #include "support/Logger.h" +#include "support/Path.h" #include "support/ThreadsafeFS.h" #include "support/Trace.h" #include "clang/AST/DeclTemplate.h" @@ -27,6 +29,7 @@ #include "clang/Basic/TokenKinds.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/PrecompiledPreamble.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/PPCallbacks.h" @@ -42,6 +45,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormatVariadic.h" @@ -50,10 +54,12 @@ #include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include +#include #include #include #include #include +#include #include #include @@ -566,6 +572,29 @@ return NewD; } }; + +std::vector getPragmaMarks(const ScannedPreamble &Modified) { + std::vector Marks; + for (size_t I = 0, E = Modified.Lines.size(); I != E; ++I) { + llvm::StringRef Line = Modified.Lines[I].ltrim(); + size_t MarkOffset = Line.find("mark"); + if (MarkOffset == Line.npos) + continue; + if (!Line.consume_front("#pragma")) + continue; + Line = Line.ltrim(); + if (!Line.consume_front("mark")) + continue; + PragmaMark &PM = Marks.emplace_back(); + PM.Trivia = Line.str(); + PM.Rng.start.line = I; + // We are only skipping whitespaces and `#pragma` when calculating this + // offset, hence no need to care about utf-16. + PM.Rng.start.character = MarkOffset; + PM.Rng.end.line = I + 1; + } + return Marks; +} } // namespace std::shared_ptr @@ -849,6 +878,7 @@ } PP.PatchedDiags = patchDiags(Baseline.Diags, *BaselineScan, *ModifiedScan); + PP.PatchedMarks = getPragmaMarks(*ModifiedScan); dlog("Created preamble patch: {0}", Patch.str()); Patch.flush(); return PP; @@ -902,8 +932,7 @@ llvm::ArrayRef PreamblePatch::marks() const { if (PatchContents.empty()) return Baseline->Marks; - // FIXME: Patch pragma marks. - return {}; + return PatchedMarks; } MainFileMacros PreamblePatch::mainFileMacros() const { 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 @@ -830,6 +830,10 @@ } } +MATCHER_P2(Mark, Range, Text, "") { + return std::tie(arg.Rng, arg.Trivia) == std::tie(Range, Text); +} + TEST(PreamblePatch, MacroAndMarkHandling) { Config Cfg; Cfg.Diagnostics.AllowStalePreamble = true; @@ -848,13 +852,18 @@ #ifndef FOO #define FOO #define BAR -#pragma mark XX +#pragma $x[[mark XX +]] +#pragma $y[[mark YY +]] #endif)cpp"); auto AST = createPatchedAST(Code.code(), NewCode.code()); // FIXME: Macros and marks have locations that need to be patched. EXPECT_THAT(AST->getMacros().Names, IsEmpty()); - EXPECT_THAT(AST->getMarks(), IsEmpty()); + EXPECT_THAT(AST->getMarks(), + UnorderedElementsAre(Mark(NewCode.range("x"), " XX"), + Mark(NewCode.range("y"), " YY"))); } }