nridge updated this revision to Diff 228959.
nridge added a comment.
Add unit tests
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D67536/new/
https://reviews.llvm.org/D67536
Files:
clang-tools-extra/clangd/ParsedAST.cpp
clang-tools-extra/clangd/ParsedAST.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
Index: clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
+++ clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
@@ -140,7 +140,7 @@
}
for (auto &LineTokens : ExpectedLines)
ExpectedLinePairHighlighting.push_back(
- {LineTokens.first, LineTokens.second});
+ {LineTokens.first, LineTokens.second, /*IsInactive = */ false});
std::vector<LineHighlightings> ActualDiffed =
diffHighlightings(NewTokens, OldTokens);
@@ -589,6 +589,33 @@
R"cpp(
void $Function[[foo]]();
using ::$Function[[foo]];
+ )cpp",
+ // Inactive code highlighting
+ R"cpp(
+ // FIXME: In the preamble, no inactive code highlightings are produced.
+ #ifdef $Macro[[test]]
+ #endif
+
+ // A declaration to cause the preamble to end.
+ int $Variable[[EndPreamble]];
+
+ // Code after the preamble.
+ // Inactive lines get an empty InactiveCode token at the beginning.
+ // Code inside inactive blocks does not get regular highlightings
+ // because it's not part of the AST.
+$InactiveCode[[]] #ifdef $Macro[[test]]
+$InactiveCode[[]] int Inactive1;
+$InactiveCode[[]] #endif
+
+ #ifndef $Macro[[test]]
+ int $Variable[[Active1]];
+ #endif
+
+$InactiveCode[[]] #ifdef $Macro[[test]]
+$InactiveCode[[]] int Inactive2;
+$InactiveCode[[]] #else
+ int $Variable[[Active2]];
+ #endif
)cpp"};
for (const auto &TestCase : TestCases) {
checkHighlightings(TestCase);
@@ -656,10 +683,12 @@
{{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 = {
Index: clang-tools-extra/clangd/test/semantic-highlighting.test
===================================================================
--- clang-tools-extra/clangd/test/semantic-highlighting.test
+++ 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: }
Index: clang-tools-extra/clangd/SemanticHighlighting.h
===================================================================
--- clang-tools-extra/clangd/SemanticHighlighting.h
+++ clang-tools-extra/clangd/SemanticHighlighting.h
@@ -44,7 +44,11 @@
Primitive,
Macro,
- LastKind = Macro
+ // This one is different 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 @@
struct LineHighlightings {
int Line;
std::vector<HighlightingToken> Tokens;
+ bool IsInactive;
};
bool operator==(const LineHighlightings &L, const LineHighlightings &R);
Index: clang-tools-extra/clangd/SemanticHighlighting.cpp
===================================================================
--- clang-tools-extra/clangd/SemanticHighlighting.cpp
+++ clang-tools-extra/clangd/SemanticHighlighting.cpp
@@ -158,6 +158,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;
}
@@ -405,6 +426,8 @@
return OS << "Primitive";
case HighlightingKind::Macro:
return OS << "Macro";
+ case HighlightingKind::InactiveCode:
+ return OS << "InactiveCode";
}
llvm_unreachable("invalid HighlightingKind");
}
@@ -449,8 +472,24 @@
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.
+ // We do this by iterating over the tokens in the line, and if we find
+ // one with kind InactiveCode, removing that token and setting the
+ // IsInactive flag on the line instead.
+ auto &AddedLine = DiffedLines.back();
+ for (auto Iter = AddedLine.Tokens.begin();
+ Iter != AddedLine.Tokens.end();) {
+ if (Iter->Kind == HighlightingKind::InactiveCode) {
+ Iter = AddedLine.Tokens.erase(Iter);
+ AddedLine.IsInactive = true;
+ } else {
+ ++Iter;
+ }
+ }
+ }
}
return DiffedLines;
@@ -493,7 +532,7 @@
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;
@@ -538,6 +577,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");
}
Index: clang-tools-extra/clangd/Protocol.h
===================================================================
--- clang-tools-extra/clangd/Protocol.h
+++ clang-tools-extra/clangd/Protocol.h
@@ -1209,6 +1209,9 @@
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.
+ bool IsInactive = false;
};
bool operator==(const SemanticHighlightingInformation &Lhs,
const SemanticHighlightingInformation &Rhs);
Index: clang-tools-extra/clangd/Protocol.cpp
===================================================================
--- clang-tools-extra/clangd/Protocol.cpp
+++ clang-tools-extra/clangd/Protocol.cpp
@@ -1063,7 +1063,8 @@
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) {
Index: clang-tools-extra/clangd/ParsedAST.h
===================================================================
--- clang-tools-extra/clangd/ParsedAST.h
+++ clang-tools-extra/clangd/ParsedAST.h
@@ -97,13 +97,16 @@
/// (!) does not have tokens from the preamble.
const syntax::TokenBuffer &getTokens() const { return Tokens; }
+ llvm::ArrayRef<SourceRange> getSkippedRanges() const { return SkippedRanges; }
+
private:
ParsedAST(std::shared_ptr<const PreambleData> Preamble,
std::unique_ptr<CompilerInstance> Clang,
std::unique_ptr<FrontendAction> Action, syntax::TokenBuffer Tokens,
MainFileMacros Macros, std::vector<Decl *> LocalTopLevelDecls,
std::vector<Diag> Diags, IncludeStructure Includes,
- CanonicalIncludes CanonIncludes);
+ CanonicalIncludes CanonIncludes,
+ std::vector<SourceRange> SkippedRanges);
// In-memory preambles must outlive the AST, it is important that this member
// goes before Clang and Action.
@@ -130,6 +133,8 @@
std::vector<Decl *> LocalTopLevelDecls;
IncludeStructure Includes;
CanonicalIncludes CanonIncludes;
+ // Ranges skipped during preprocessing.
+ std::vector<SourceRange> SkippedRanges;
};
/// Build an AST from provided user inputs. This function does not check if
Index: clang-tools-extra/clangd/ParsedAST.cpp
===================================================================
--- clang-tools-extra/clangd/ParsedAST.cpp
+++ clang-tools-extra/clangd/ParsedAST.cpp
@@ -208,6 +208,23 @@
const LangOptions &LangOpts;
};
+class CollectSkippedRanges : public PPCallbacks {
+public:
+ explicit CollectSkippedRanges(SourceManager &SM,
+ std::vector<SourceRange> &SkippedRanges)
+ : SM(SM), SkippedRanges(SkippedRanges) {}
+
+ void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) override {
+ if (isInsideMainFile(Range.getBegin(), SM)) {
+ SkippedRanges.push_back(Range);
+ }
+ }
+
+private:
+ SourceManager &SM;
+ std::vector<SourceRange> &SkippedRanges;
+};
+
} // namespace
void dumpAST(ParsedAST &AST, llvm::raw_ostream &OS) {
@@ -348,6 +365,10 @@
Clang->getPreprocessor().addPPCallbacks(
std::make_unique<CollectMainFileMacros>(Clang->getSourceManager(),
Clang->getLangOpts(), Macros));
+ std::vector<SourceRange> SkippedRanges;
+ Clang->getPreprocessor().addPPCallbacks(
+ std::make_unique<CollectSkippedRanges>(Clang->getSourceManager(),
+ SkippedRanges));
// Copy over the includes from the preamble, then combine with the
// non-preamble includes below.
@@ -403,7 +424,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 +512,14 @@
syntax::TokenBuffer Tokens, MainFileMacros Macros,
std::vector<Decl *> LocalTopLevelDecls,
std::vector<Diag> Diags, IncludeStructure Includes,
- CanonicalIncludes CanonIncludes)
+ CanonicalIncludes CanonIncludes,
+ std::vector<SourceRange> 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);
}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits