[clang-tools-extra] b2e6c2b - [clangd] Inactive regions support as an extension to semantic highlighting
Nathan Ridge via cfe-commits
cfe-commits at lists.llvm.org
Thu Nov 21 16:41:43 PST 2019
Author: Nathan Ridge
Date: 2019-11-21T19:40:55-05:00
New Revision: b2e6c2b9954ba9f9b68b8394790f6cae35aea58e
URL: https://github.com/llvm/llvm-project/commit/b2e6c2b9954ba9f9b68b8394790f6cae35aea58e
DIFF: https://github.com/llvm/llvm-project/commit/b2e6c2b9954ba9f9b68b8394790f6cae35aea58e.diff
LOG: [clangd] Inactive regions support as an extension to semantic highlighting
Differential Revision: https://reviews.llvm.org/D67536
Added:
Modified:
clang-tools-extra/clangd/CollectMacros.h
clang-tools-extra/clangd/Protocol.cpp
clang-tools-extra/clangd/Protocol.h
clang-tools-extra/clangd/SemanticHighlighting.cpp
clang-tools-extra/clangd/SemanticHighlighting.h
clang-tools-extra/clangd/test/semantic-highlighting.test
clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clangd/CollectMacros.h b/clang-tools-extra/clangd/CollectMacros.h
index 17e9917542bd..5c3fca10ad4a 100644
--- a/clang-tools-extra/clangd/CollectMacros.h
+++ b/clang-tools-extra/clangd/CollectMacros.h
@@ -30,6 +30,8 @@ struct MainFileMacros {
// reference to an undefined macro. Store them separately, e.g. for semantic
// highlighting.
std::vector<Range> UnknownMacros;
+ // Ranges skipped by the preprocessor due to being inactive.
+ std::vector<Range> SkippedRanges;
};
/// Collects macro references (e.g. definitions, expansions) in the main file.
@@ -78,6 +80,14 @@ class CollectMainFileMacros : public PPCallbacks {
add(MacroName, MD.getMacroInfo());
}
+ void SourceRangeSkipped(SourceRange R, SourceLocation EndifLoc) override {
+ if (!InMainFile)
+ return;
+ Position Begin = sourceLocToPosition(SM, R.getBegin());
+ Position End = sourceLocToPosition(SM, R.getEnd());
+ Out.SkippedRanges.push_back(Range{Begin, End});
+ }
+
private:
void add(const Token &MacroNameTok, const MacroInfo *MI) {
if (!InMainFile)
diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp
index bdf284dc502f..25826bd5a11d 100644
--- a/clang-tools-extra/clangd/Protocol.cpp
+++ b/clang-tools-extra/clangd/Protocol.cpp
@@ -1063,7 +1063,8 @@ bool operator==(const SemanticHighlightingInformation &Lhs,
llvm::json::Value toJSON(const SemanticHighlightingInformation &Highlighting) {
return llvm::json::Object{{"line", Highlighting.Line},
- {"tokens", Highlighting.Tokens}};
+ {"tokens", Highlighting.Tokens},
+ {"isInactive", Highlighting.IsInactive}};
}
llvm::json::Value toJSON(const SemanticHighlightingParams &Highlighting) {
diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h
index 6540365dccd8..f110292b091b 100644
--- a/clang-tools-extra/clangd/Protocol.h
+++ b/clang-tools-extra/clangd/Protocol.h
@@ -1209,6 +1209,11 @@ struct SemanticHighlightingInformation {
int Line = 0;
/// The base64 encoded string of highlighting tokens.
std::string Tokens;
+ /// Is the line in an inactive preprocessor branch?
+ /// This is a clangd extension.
+ /// An inactive line can still contain highlighting tokens as well;
+ /// clients should combine line style and token style if possible.
+ bool IsInactive = false;
};
bool operator==(const SemanticHighlightingInformation &Lhs,
const SemanticHighlightingInformation &Rhs);
diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp
index 4e47a83d8da0..049afb741b27 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.cpp
+++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp
@@ -25,6 +25,7 @@
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Casting.h"
#include <algorithm>
@@ -160,7 +161,7 @@ class HighlightingsBuilder {
Tokens.push_back(HighlightingToken{Kind, *Range});
}
- std::vector<HighlightingToken> collect() && {
+ std::vector<HighlightingToken> collect(ParsedAST &AST) && {
// Initializer lists can give duplicates of tokens, therefore all tokens
// must be deduplicated.
llvm::sort(Tokens);
@@ -187,6 +188,22 @@ class HighlightingsBuilder {
// the end of the Tokens).
TokRef = TokRef.drop_front(Conflicting.size());
}
+ // Add tokens indicating lines skipped by the preprocessor.
+ for (const Range &R : AST.getMacros().SkippedRanges) {
+ // Create one token for each line in the skipped range, so it works
+ // with line-based
diff ing.
+ assert(R.start.line <= R.end.line);
+ for (int Line = R.start.line; Line < R.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
diff ing expects.
+ llvm::sort(NonConflicting);
return NonConflicting;
}
@@ -319,7 +336,7 @@ std::vector<HighlightingToken> getSemanticHighlightings(ParsedAST &AST) {
for (const auto &M : AST.getMacros().UnknownMacros)
Builder.addToken({HighlightingKind::Macro, M});
- return std::move(Builder).collect();
+ return std::move(Builder).collect(AST);
}
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, HighlightingKind K) {
@@ -360,6 +377,8 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, HighlightingKind K) {
return OS << "Primitive";
case HighlightingKind::Macro:
return OS << "Macro";
+ case HighlightingKind::InactiveCode:
+ return OS << "InactiveCode";
}
llvm_unreachable("invalid HighlightingKind");
}
@@ -404,8 +423,19 @@
diff Highlightings(ArrayRef<HighlightingToken> New,
LineNumber = NextLineNumber()) {
NewLine = takeLine(New, NewLine.end(), LineNumber);
OldLine = takeLine(Old, OldLine.end(), LineNumber);
- if (NewLine != OldLine)
- DiffedLines.push_back({LineNumber, NewLine});
+ if (NewLine != OldLine) {
+ DiffedLines.push_back({LineNumber, NewLine, /*IsInactive=*/false});
+
+ // Turn a HighlightingKind::InactiveCode token into the IsInactive flag.
+ auto &AddedLine = DiffedLines.back();
+ llvm::erase_if(AddedLine.Tokens, [&](const HighlightingToken &T) {
+ if (T.Kind == HighlightingKind::InactiveCode) {
+ AddedLine.IsInactive = true;
+ return true;
+ }
+ return false;
+ });
+ }
}
return DiffedLines;
@@ -444,7 +474,7 @@ toSemanticHighlightingInformation(llvm::ArrayRef<LineHighlightings> Tokens) {
write16be(static_cast<int>(Token.Kind), OS);
}
- Lines.push_back({Line.Line, encodeBase64(LineByteTokens)});
+ Lines.push_back({Line.Line, encodeBase64(LineByteTokens), Line.IsInactive});
}
return Lines;
@@ -489,6 +519,8 @@ llvm::StringRef toTextMateScope(HighlightingKind Kind) {
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/SemanticHighlighting.h b/clang-tools-extra/clangd/SemanticHighlighting.h
index 7d8cb938ab51..bc57d1ceed93 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.h
+++ b/clang-tools-extra/clangd/SemanticHighlighting.h
@@ -44,7 +44,11 @@ enum class HighlightingKind {
Primitive,
Macro,
- LastKind = Macro
+ // This one is
diff erent from the other kinds as it's a line style
+ // rather than a token style.
+ InactiveCode,
+
+ LastKind = InactiveCode
};
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, HighlightingKind K);
@@ -61,6 +65,7 @@ bool operator<(const HighlightingToken &L, const HighlightingToken &R);
struct LineHighlightings {
int Line;
std::vector<HighlightingToken> Tokens;
+ bool IsInactive;
};
bool operator==(const LineHighlightings &L, const LineHighlightings &R);
diff --git a/clang-tools-extra/clangd/test/semantic-highlighting.test b/clang-tools-extra/clangd/test/semantic-highlighting.test
index 7d9b381e2842..4036c541069b 100644
--- a/clang-tools-extra/clangd/test/semantic-highlighting.test
+++ b/clang-tools-extra/clangd/test/semantic-highlighting.test
@@ -57,6 +57,9 @@
# CHECK-NEXT: ],
# CHECK-NEXT: [
# CHECK-NEXT: "entity.name.function.preprocessor.cpp"
+# CHECK-NEXT: ],
+# CHECK-NEXT: [
+# CHECK-NEXT: "meta.disabled"
# CHECK-NEXT: ]
# CHECK-NEXT: ]
# CHECK-NEXT: },
@@ -66,6 +69,7 @@
# CHECK-NEXT: "params": {
# CHECK-NEXT: "lines": [
# CHECK-NEXT: {
+# CHECK-NEXT: "isInactive": false,
# CHECK-NEXT: "line": 0,
# CHECK-NEXT: "tokens": "AAAABAABAAA="
# CHECK-NEXT: }
@@ -81,10 +85,12 @@
# CHECK-NEXT: "params": {
# CHECK-NEXT: "lines": [
# CHECK-NEXT: {
+# CHECK-NEXT: "isInactive": false,
# CHECK-NEXT: "line": 0,
# CHECK-NEXT: "tokens": "AAAABAABAAA="
# CHECK-NEXT: }
# CHECK-NEXT: {
+# CHECK-NEXT: "isInactive": false,
# CHECK-NEXT: "line": 1,
# CHECK-NEXT: "tokens": "AAAABAABAAA="
# CHECK-NEXT: }
@@ -100,6 +106,7 @@
# CHECK-NEXT: "params": {
# CHECK-NEXT: "lines": [
# CHECK-NEXT: {
+# CHECK-NEXT: "isInactive": false,
# CHECK-NEXT: "line": 1,
# CHECK-NEXT: "tokens": "AAAABAABAAA="
# CHECK-NEXT: }
@@ -115,6 +122,7 @@
# CHECK-NEXT: "params": {
# CHECK-NEXT: "lines": [
# CHECK-NEXT: {
+# CHECK-NEXT: "isInactive": false,
# CHECK-NEXT: "line": 1,
# CHECK-NEXT: "tokens": ""
# CHECK-NEXT: }
diff --git a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
index 36237e94dfe0..5b844462e839 100644
--- a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
@@ -140,7 +140,7 @@ void checkDiffedHighlights(llvm::StringRef OldCode, llvm::StringRef NewCode) {
}
for (auto &LineTokens : ExpectedLines)
ExpectedLinePairHighlighting.push_back(
- {LineTokens.first, LineTokens.second});
+ {LineTokens.first, LineTokens.second, /*IsInactive = */ false});
std::vector<LineHighlightings> ActualDiffed =
diff Highlightings(NewTokens, OldTokens);
@@ -493,11 +493,11 @@ TEST(SemanticHighlighting, GetsCorrectTokens) {
#define $Macro[[test]]
#undef $Macro[[test]]
- #ifdef $Macro[[test]]
- #endif
+$InactiveCode[[]] #ifdef $Macro[[test]]
+$InactiveCode[[]] #endif
- #if defined($Macro[[test]])
- #endif
+$InactiveCode[[]] #if defined($Macro[[test]])
+$InactiveCode[[]] #endif
)cpp",
R"cpp(
struct $Class[[S]] {
@@ -598,6 +598,33 @@ TEST(SemanticHighlighting, GetsCorrectTokens) {
$Class[[Foo]]<$TemplateParameter[[TT]], $TemplateParameter[[TTs]]...>
*$Field[[t]];
}
+ )cpp",
+ // Inactive code highlighting
+ R"cpp(
+ // Code in the preamble.
+ // Inactive lines get an empty InactiveCode token at the beginning.
+$InactiveCode[[]] #ifdef $Macro[[test]]
+$InactiveCode[[]] #endif
+
+ // A declaration to cause the preamble to end.
+ int $Variable[[EndPreamble]];
+
+ // Code after the preamble.
+ // Code inside inactive blocks does not get regular highlightings
+ // because it's not part of the AST.
+$InactiveCode[[]] #ifdef $Macro[[test]]
+$InactiveCode[[]] int Inactive2;
+$InactiveCode[[]] #endif
+
+ #ifndef $Macro[[test]]
+ int $Variable[[Active1]];
+ #endif
+
+$InactiveCode[[]] #ifdef $Macro[[test]]
+$InactiveCode[[]] int Inactive3;
+$InactiveCode[[]] #else
+ int $Variable[[Active2]];
+ #endif
)cpp"};
for (const auto &TestCase : TestCases) {
checkHighlightings(TestCase);
@@ -665,10 +692,12 @@ TEST(SemanticHighlighting, toSemanticHighlightingInformation) {
{{HighlightingKind::Variable,
Range{CreatePosition(3, 8), CreatePosition(3, 12)}},
{HighlightingKind::Function,
- Range{CreatePosition(3, 4), CreatePosition(3, 7)}}}},
+ Range{CreatePosition(3, 4), CreatePosition(3, 7)}}},
+ /* IsInactive = */ false},
{1,
{{HighlightingKind::Variable,
- Range{CreatePosition(1, 1), CreatePosition(1, 5)}}}}};
+ Range{CreatePosition(1, 1), CreatePosition(1, 5)}}},
+ /* IsInactive = */ true}};
std::vector<SemanticHighlightingInformation> ActualResults =
toSemanticHighlightingInformation(Tokens);
std::vector<SemanticHighlightingInformation> ExpectedResults = {
More information about the cfe-commits
mailing list