diff --git a/clang-tools-extra/clangd/ParsedAST.h b/clang-tools-extra/clangd/ParsedAST.h --- a/clang-tools-extra/clangd/ParsedAST.h +++ b/clang-tools-extra/clangd/ParsedAST.h @@ -97,13 +97,18 @@ /// (!) does not have tokens from the preamble. const syntax::TokenBuffer &getTokens() const { return Tokens; } + const std::vector &getSkippedRanges() const { + return SkippedRanges; + } + private: ParsedAST(std::shared_ptr Preamble, std::unique_ptr Clang, std::unique_ptr Action, syntax::TokenBuffer Tokens, MainFileMacros Macros, std::vector LocalTopLevelDecls, std::vector Diags, IncludeStructure Includes, - CanonicalIncludes CanonIncludes); + CanonicalIncludes CanonIncludes, + std::vector SkippedRanges); // In-memory preambles must outlive the AST, it is important that this member // goes before Clang and Action. @@ -130,6 +135,8 @@ std::vector LocalTopLevelDecls; IncludeStructure Includes; CanonicalIncludes CanonIncludes; + // Ranges skipped during preprocessing. + std::vector SkippedRanges; }; /// Build an AST from provided user inputs. This function does not check if 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 @@ -208,6 +208,19 @@ const LangOptions &LangOpts; }; +class CollectSkippedRanges : public PPCallbacks { +public: + explicit CollectSkippedRanges(std::vector &SkippedRanges) + : SkippedRanges(SkippedRanges) {} + + void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) override { + SkippedRanges.push_back(Range); + } + +private: + std::vector &SkippedRanges; +}; + } // namespace void dumpAST(ParsedAST &AST, llvm::raw_ostream &OS) { @@ -348,6 +361,9 @@ Clang->getPreprocessor().addPPCallbacks( std::make_unique(Clang->getSourceManager(), Clang->getLangOpts(), Macros)); + std::vector SkippedRanges; + Clang->getPreprocessor().addPPCallbacks( + std::make_unique(SkippedRanges)); // Copy over the includes from the preamble, then combine with the // non-preamble includes below. @@ -403,7 +419,7 @@ return ParsedAST(std::move(Preamble), std::move(Clang), std::move(Action), std::move(Tokens), std::move(Macros), std::move(ParsedDecls), std::move(Diags), std::move(Includes), - std::move(CanonIncludes)); + std::move(CanonIncludes), std::move(SkippedRanges)); } ParsedAST::ParsedAST(ParsedAST &&Other) = default; @@ -491,12 +507,14 @@ syntax::TokenBuffer Tokens, MainFileMacros Macros, std::vector LocalTopLevelDecls, std::vector Diags, IncludeStructure Includes, - CanonicalIncludes CanonIncludes) + CanonicalIncludes CanonIncludes, + std::vector SkippedRanges) : Preamble(std::move(Preamble)), Clang(std::move(Clang)), Action(std::move(Action)), Tokens(std::move(Tokens)), Macros(std::move(Macros)), Diags(std::move(Diags)), LocalTopLevelDecls(std::move(LocalTopLevelDecls)), - Includes(std::move(Includes)), CanonIncludes(std::move(CanonIncludes)) { + Includes(std::move(Includes)), CanonIncludes(std::move(CanonIncludes)), + SkippedRanges(std::move(SkippedRanges)) { assert(this->Clang); assert(this->Action); } diff --git a/clang-tools-extra/clangd/SemanticHighlighting.h b/clang-tools-extra/clangd/SemanticHighlighting.h --- a/clang-tools-extra/clangd/SemanticHighlighting.h +++ b/clang-tools-extra/clangd/SemanticHighlighting.h @@ -41,8 +41,9 @@ TemplateParameter, Primitive, Macro, + InactiveCode, - LastKind = Macro + LastKind = InactiveCode }; llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, HighlightingKind K); diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp --- a/clang-tools-extra/clangd/SemanticHighlighting.cpp +++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp @@ -137,6 +137,27 @@ // the end of the Tokens). TokRef = TokRef.drop_front(Conflicting.size()); } + // Add inactive highlighting tokens. + const SourceManager &SM = AST.getSourceManager(); + for (const SourceRange &R : AST.getSkippedRanges()) { + if (isInsideMainFile(R.getBegin(), SM)) { + // Create one token for each line in the skipped range, so it works + // with line-based diffing. + Position Begin = sourceLocToPosition(SM, R.getBegin()); + Position End = sourceLocToPosition(SM, R.getEnd()); + assert(Begin.line <= End.line); + for (int Line = Begin.line; Line < End.line; ++Line) { + // Don't bother computing the offset for the end of the line, just use + // zero. The client will treat this highlighting kind specially, and + // highlight the entire line visually (i.e. not just to where the text + // on the line ends, but to the end of the screen). + NonConflicting.push_back({HighlightingKind::InactiveCode, + {Position{Line, 0}, Position{Line, 0}}}); + } + } + } + // Re-sort the tokens because that's what the diffing expects. + llvm::sort(NonConflicting); return NonConflicting; } @@ -347,6 +368,8 @@ return OS << "Primitive"; case HighlightingKind::Macro: return OS << "Macro"; + case HighlightingKind::InactiveCode: + return OS << "InactiveCode"; } llvm_unreachable("invalid HighlightingKind"); } @@ -476,6 +499,8 @@ return "storage.type.primitive.cpp"; case HighlightingKind::Macro: return "entity.name.function.preprocessor.cpp"; + case HighlightingKind::InactiveCode: + return "meta.disabled"; } llvm_unreachable("unhandled HighlightingKind"); } diff --git a/clang-tools-extra/clangd/test/semantic-highlighting.test b/clang-tools-extra/clangd/test/semantic-highlighting.test --- a/clang-tools-extra/clangd/test/semantic-highlighting.test +++ b/clang-tools-extra/clangd/test/semantic-highlighting.test @@ -50,6 +50,9 @@ # CHECK-NEXT: "storage.type.primitive.cpp" # CHECK-NEXT: ], # CHECK-NEXT: [ +# CHECK-NEXT: "meta.disabled" +# CHECK-NEXT: ], +# CHECK-NEXT: [ # CHECK-NEXT: "entity.name.function.preprocessor.cpp" # CHECK-NEXT: ] # CHECK-NEXT: ]