It seems to have made this buildbot sad: http://lab.llvm.org:8011/builders/clang-cmake-armv8-lnt/builds/10968
On Thu, Aug 1, 2019 at 10:07 AM Johan Vikstrom via cfe-commits <cfe-commits@lists.llvm.org> wrote: > > Author: jvikstrom > Date: Thu Aug 1 01:08:44 2019 > New Revision: 367521 > > URL: http://llvm.org/viewvc/llvm-project?rev=367521&view=rev > Log: > [clangd] Duplicate lines of semantic highlightings sent removed. > > Summary: Added a class for diffing highlightings and removing duplicate > lines. Integrated into the highlighting generation flow. Only works correctly > if all tokens are on a single line. Also returns empty lines if the IDE > should remove previous highlightings on a line. > > Reviewers: hokein, sammccall, ilya-biryukov > > Subscribers: MaskRay, jkorous, mgrang, arphaman, kadircet, cfe-commits > > Tags: #clang > > Differential Revision: https://reviews.llvm.org/D64475 > > Modified: > clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp > clang-tools-extra/trunk/clangd/ClangdLSPServer.h > clang-tools-extra/trunk/clangd/ClangdServer.cpp > clang-tools-extra/trunk/clangd/ClangdServer.h > clang-tools-extra/trunk/clangd/SemanticHighlighting.cpp > clang-tools-extra/trunk/clangd/SemanticHighlighting.h > clang-tools-extra/trunk/clangd/test/semantic-highlighting.test > clang-tools-extra/trunk/clangd/unittests/SemanticHighlightingTests.cpp > > Modified: clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp?rev=367521&r1=367520&r2=367521&view=diff > ============================================================================== > --- clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp (original) > +++ clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp Thu Aug 1 01:08:44 > 2019 > @@ -615,6 +615,10 @@ void ClangdLSPServer::onDocumentDidClose > std::lock_guard<std::mutex> Lock(FixItsMutex); > FixItsMap.erase(File); > } > + { > + std::lock_guard<std::mutex> HLock(HighlightingsMutex); > + FileToHighlightings.erase(File); > + } > // clangd will not send updates for this file anymore, so we empty out the > // list of diagnostics shown on the client (e.g. in the "Problems" pane of > // VSCode). Note that this cannot race with actual diagnostics responses > @@ -1113,10 +1117,21 @@ bool ClangdLSPServer::shouldRunCompletio > } > > void ClangdLSPServer::onHighlightingsReady( > - PathRef File, std::vector<HighlightingToken> Highlightings) { > + PathRef File, std::vector<HighlightingToken> Highlightings, int > NumLines) { > + std::vector<HighlightingToken> Old; > + std::vector<HighlightingToken> HighlightingsCopy = Highlightings; > + { > + std::lock_guard<std::mutex> Lock(HighlightingsMutex); > + Old = std::move(FileToHighlightings[File]); > + FileToHighlightings[File] = std::move(HighlightingsCopy); > + } > + // LSP allows us to send incremental edits of highlightings. Also need to > diff > + // to remove highlightings from tokens that should no longer have them. > + std::vector<LineHighlightings> Diffed = > + diffHighlightings(Highlightings, Old, NumLines); > publishSemanticHighlighting( > {{URIForFile::canonicalize(File, /*TUPath=*/File)}, > - toSemanticHighlightingInformation(Highlightings)}); > + toSemanticHighlightingInformation(Diffed)}); > } > > void ClangdLSPServer::onDiagnosticsReady(PathRef File, > > Modified: clang-tools-extra/trunk/clangd/ClangdLSPServer.h > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdLSPServer.h?rev=367521&r1=367520&r2=367521&view=diff > ============================================================================== > --- clang-tools-extra/trunk/clangd/ClangdLSPServer.h (original) > +++ clang-tools-extra/trunk/clangd/ClangdLSPServer.h Thu Aug 1 01:08:44 2019 > @@ -55,9 +55,9 @@ private: > // Implement DiagnosticsConsumer. > void onDiagnosticsReady(PathRef File, std::vector<Diag> Diagnostics) > override; > void onFileUpdated(PathRef File, const TUStatus &Status) override; > - void > - onHighlightingsReady(PathRef File, > - std::vector<HighlightingToken> Highlightings) > override; > + void onHighlightingsReady(PathRef File, > + std::vector<HighlightingToken> Highlightings, > + int NumLines) override; > > // LSP methods. Notifications have signature void(const Params&). > // Calls have signature void(const Params&, Callback<Response>). > @@ -138,6 +138,8 @@ private: > DiagnosticToReplacementMap; > /// Caches FixIts per file and diagnostics > llvm::StringMap<DiagnosticToReplacementMap> FixItsMap; > + std::mutex HighlightingsMutex; > + llvm::StringMap<std::vector<HighlightingToken>> FileToHighlightings; > > // Most code should not deal with Transport directly. > // MessageHandler deals with incoming messages, use call() etc for > outgoing. > > Modified: clang-tools-extra/trunk/clangd/ClangdServer.cpp > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdServer.cpp?rev=367521&r1=367520&r2=367521&view=diff > ============================================================================== > --- clang-tools-extra/trunk/clangd/ClangdServer.cpp (original) > +++ clang-tools-extra/trunk/clangd/ClangdServer.cpp Thu Aug 1 01:08:44 2019 > @@ -71,10 +71,19 @@ struct UpdateIndexCallbacks : public Par > if (SemanticHighlighting) > Highlightings = getSemanticHighlightings(AST); > > + // FIXME: We need a better way to send the maximum line number to the > + // differ. > + // The differ needs the information about the max number of lines > + // to not send diffs that are outside the file. > + const SourceManager &SM = AST.getSourceManager(); > + FileID MainFileID = SM.getMainFileID(); > + int NumLines = SM.getBufferData(MainFileID).count('\n') + 1; > + > Publish([&]() { > DiagConsumer.onDiagnosticsReady(Path, std::move(Diagnostics)); > if (SemanticHighlighting) > - DiagConsumer.onHighlightingsReady(Path, std::move(Highlightings)); > + DiagConsumer.onHighlightingsReady(Path, std::move(Highlightings), > + NumLines); > }); > } > > > Modified: clang-tools-extra/trunk/clangd/ClangdServer.h > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdServer.h?rev=367521&r1=367520&r2=367521&view=diff > ============================================================================== > --- clang-tools-extra/trunk/clangd/ClangdServer.h (original) > +++ clang-tools-extra/trunk/clangd/ClangdServer.h Thu Aug 1 01:08:44 2019 > @@ -52,9 +52,12 @@ public: > virtual void onFileUpdated(PathRef File, const TUStatus &Status){}; > > /// Called by ClangdServer when some \p Highlightings for \p File are > ready. > + /// \p NumLines are the number of lines in the file where the highlightings > + /// where generated from. > virtual void > onHighlightingsReady(PathRef File, > - std::vector<HighlightingToken> Highlightings) {} > + std::vector<HighlightingToken> Highlightings, > + int NumLines) {} > }; > > /// When set, used by ClangdServer to get clang-tidy options for each > particular > > Modified: clang-tools-extra/trunk/clangd/SemanticHighlighting.cpp > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/SemanticHighlighting.cpp?rev=367521&r1=367520&r2=367521&view=diff > ============================================================================== > --- clang-tools-extra/trunk/clangd/SemanticHighlighting.cpp (original) > +++ clang-tools-extra/trunk/clangd/SemanticHighlighting.cpp Thu Aug 1 > 01:08:44 2019 > @@ -12,6 +12,7 @@ > #include "SourceCode.h" > #include "clang/AST/ASTContext.h" > #include "clang/AST/RecursiveASTVisitor.h" > +#include <algorithm> > > namespace clang { > namespace clangd { > @@ -33,10 +34,7 @@ public: > TraverseAST(Ctx); > // Initializer lists can give duplicates of tokens, therefore all tokens > // must be deduplicated. > - llvm::sort(Tokens, > - [](const HighlightingToken &L, const HighlightingToken &R) { > - return std::tie(L.R, L.Kind) < std::tie(R.R, R.Kind); > - }); > + llvm::sort(Tokens); > auto Last = std::unique(Tokens.begin(), Tokens.end()); > Tokens.erase(Last, Tokens.end()); > return Tokens; > @@ -260,10 +258,74 @@ void write16be(uint16_t I, llvm::raw_ost > llvm::support::endian::write16be(Buf.data(), I); > OS.write(Buf.data(), Buf.size()); > } > + > +// Get the highlightings on \c Line where the first entry of line is at \c > +// StartLineIt. If it is not at \c StartLineIt an empty vector is returned. > +ArrayRef<HighlightingToken> > +takeLine(ArrayRef<HighlightingToken> AllTokens, > + ArrayRef<HighlightingToken>::iterator StartLineIt, int Line) { > + return ArrayRef<HighlightingToken>(StartLineIt, AllTokens.end()) > + .take_while([Line](const HighlightingToken &Token) { > + return Token.R.start.line == Line; > + }); > +} > } // namespace > > -bool operator==(const HighlightingToken &Lhs, const HighlightingToken &Rhs) { > - return Lhs.Kind == Rhs.Kind && Lhs.R == Rhs.R; > +std::vector<LineHighlightings> > +diffHighlightings(ArrayRef<HighlightingToken> New, > + ArrayRef<HighlightingToken> Old, int NewMaxLine) { > + assert(std::is_sorted(New.begin(), New.end()) && "New must be a sorted > vector"); > + assert(std::is_sorted(Old.begin(), Old.end()) && "Old must be a sorted > vector"); > + > + // FIXME: There's an edge case when tokens span multiple lines. If the > first > + // token on the line started on a line above the current one and the rest > of > + // the line is the equal to the previous one than we will remove all > + // highlights but the ones for the token spanning multiple lines. This > means > + // that when we get into the LSP layer the only highlights that will be > + // visible are the ones for the token spanning multiple lines. > + // Example: > + // EndOfMultilineToken Token Token Token > + // If "Token Token Token" don't differ from previously the line is > + // incorrectly removed. Suggestion to fix is to separate any multiline > tokens > + // into one token for every line it covers. This requires reading from the > + // file buffer to figure out the length of each line though. > + std::vector<LineHighlightings> DiffedLines; > + // ArrayRefs to the current line in the highlightings. > + ArrayRef<HighlightingToken> NewLine(New.begin(), > + /*length*/0UL); > + ArrayRef<HighlightingToken> OldLine(Old.begin(), > + /*length*/ 0UL); > + auto NewEnd = New.end(); > + auto OldEnd = Old.end(); > + auto NextLineNumber = [&]() { > + int NextNew = NewLine.end() != NewEnd ? NewLine.end()->R.start.line > + : > std::numeric_limits<int>::max(); > + int NextOld = OldLine.end() != OldEnd ? OldLine.end()->R.start.line > + : > std::numeric_limits<int>::max(); > + return std::min(NextNew, NextOld); > + }; > + > + // If the New file has fewer lines than the Old file we don't want to send > + // highlightings beyond the end of the file. > + for (int LineNumber = 0; LineNumber < NewMaxLine; > + LineNumber = NextLineNumber()) { > + NewLine = takeLine(New, NewLine.end(), LineNumber); > + OldLine = takeLine(Old, OldLine.end(), LineNumber); > + if (NewLine != OldLine) > + DiffedLines.push_back({LineNumber, NewLine}); > + } > + > + return DiffedLines; > +} > + > +bool operator==(const HighlightingToken &L, const HighlightingToken &R) { > + return std::tie(L.R, L.Kind) == std::tie(R.R, R.Kind); > +} > +bool operator<(const HighlightingToken &L, const HighlightingToken &R) { > + return std::tie(L.R, L.Kind) < std::tie(R.R, R.Kind); > +} > +bool operator==(const LineHighlightings &L, const LineHighlightings &R) { > + return std::tie(L.Line, L.Tokens) == std::tie(R.Line, R.Tokens); > } > > std::vector<HighlightingToken> getSemanticHighlightings(ParsedAST &AST) { > @@ -271,22 +333,18 @@ std::vector<HighlightingToken> getSemant > } > > std::vector<SemanticHighlightingInformation> > -toSemanticHighlightingInformation(llvm::ArrayRef<HighlightingToken> Tokens) { > +toSemanticHighlightingInformation(llvm::ArrayRef<LineHighlightings> Tokens) { > if (Tokens.size() == 0) > return {}; > > // FIXME: Tokens might be multiple lines long (block comments) in this case > // this needs to add multiple lines for those tokens. > - std::map<int, std::vector<HighlightingToken>> TokenLines; > - for (const HighlightingToken &Token : Tokens) > - TokenLines[Token.R.start.line].push_back(Token); > - > std::vector<SemanticHighlightingInformation> Lines; > - Lines.reserve(TokenLines.size()); > - for (const auto &Line : TokenLines) { > + Lines.reserve(Tokens.size()); > + for (const auto &Line : Tokens) { > llvm::SmallVector<char, 128> LineByteTokens; > llvm::raw_svector_ostream OS(LineByteTokens); > - for (const auto &Token : Line.second) { > + for (const auto &Token : Line.Tokens) { > // Writes the token to LineByteTokens in the byte format specified by > the > // LSP proposal. Described below. > // |<---- 4 bytes ---->|<-- 2 bytes -->|<--- 2 bytes -->| > @@ -297,7 +355,7 @@ toSemanticHighlightingInformation(llvm:: > write16be(static_cast<int>(Token.Kind), OS); > } > > - Lines.push_back({Line.first, encodeBase64(LineByteTokens)}); > + Lines.push_back({Line.Line, encodeBase64(LineByteTokens)}); > } > > return Lines; > > Modified: clang-tools-extra/trunk/clangd/SemanticHighlighting.h > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/SemanticHighlighting.h?rev=367521&r1=367520&r2=367521&view=diff > ============================================================================== > --- clang-tools-extra/trunk/clangd/SemanticHighlighting.h (original) > +++ clang-tools-extra/trunk/clangd/SemanticHighlighting.h Thu Aug 1 01:08:44 > 2019 > @@ -43,7 +43,16 @@ struct HighlightingToken { > Range R; > }; > > -bool operator==(const HighlightingToken &Lhs, const HighlightingToken &Rhs); > +bool operator==(const HighlightingToken &L, const HighlightingToken &R); > +bool operator<(const HighlightingToken &L, const HighlightingToken &R); > + > +/// Contains all information about highlightings on a single line. > +struct LineHighlightings { > + int Line; > + std::vector<HighlightingToken> Tokens; > +}; > + > +bool operator==(const LineHighlightings &L, const LineHighlightings &R); > > // Returns all HighlightingTokens from an AST. Only generates highlights for > the > // main AST. > @@ -53,9 +62,22 @@ std::vector<HighlightingToken> getSemant > /// (https://manual.macromates.com/en/language_grammars). > llvm::StringRef toTextMateScope(HighlightingKind Kind); > > -// Convert to LSP's semantic highlighting information. > +/// Convert to LSP's semantic highlighting information. > std::vector<SemanticHighlightingInformation> > -toSemanticHighlightingInformation(llvm::ArrayRef<HighlightingToken> Tokens); > +toSemanticHighlightingInformation(llvm::ArrayRef<LineHighlightings> Tokens); > + > +/// Return a line-by-line diff between two highlightings. > +/// - if the tokens on a line are the same in both hightlightings, this > line is > +/// omitted. > +/// - if a line exists in New but not in Old the tokens on this line are > +/// emitted. > +/// - if a line does not exists in New but exists in Old an empty line is > +/// emitted (to tell client to clear the previous highlightings on this > line). > +/// \p NewMaxLine is the maximum line number from the new file. > +/// REQUIRED: Old and New are sorted. > +std::vector<LineHighlightings> > +diffHighlightings(ArrayRef<HighlightingToken> New, > + ArrayRef<HighlightingToken> Old, int NewMaxLine); > > } // namespace clangd > } // namespace clang > > Modified: clang-tools-extra/trunk/clangd/test/semantic-highlighting.test > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/test/semantic-highlighting.test?rev=367521&r1=367520&r2=367521&view=diff > ============================================================================== > --- clang-tools-extra/trunk/clangd/test/semantic-highlighting.test (original) > +++ clang-tools-extra/trunk/clangd/test/semantic-highlighting.test Thu Aug 1 > 01:08:44 2019 > @@ -49,6 +49,50 @@ > # CHECK-NEXT: } > # CHECK-NEXT:} > --- > +{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///foo2.cpp","languageId":"cpp","version":1,"text":"int > x = 2;\nint y = 2;"}}} > +# CHECK: "method": "textDocument/semanticHighlighting", > +# CHECK-NEXT: "params": { > +# CHECK-NEXT: "lines": [ > +# CHECK-NEXT: { > +# CHECK-NEXT: "line": 0, > +# CHECK-NEXT: "tokens": "AAAABAABAAA=" > +# CHECK-NEXT: } > +# CHECK-NEXT: { > +# CHECK-NEXT: "line": 1, > +# CHECK-NEXT: "tokens": "AAAABAABAAA=" > +# CHECK-NEXT: } > +# CHECK-NEXT: ], > +# CHECK-NEXT: "textDocument": { > +# CHECK-NEXT: "uri": "file:///clangd-test/foo2.cpp" > +# CHECK-NEXT: } > +# CHECK-NEXT: } > +# CHECK-NEXT:} > +--- > +{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"test:///foo.cpp","version":2},"contentChanges": > [{"range":{"start": {"line": 0,"character": 10},"end": {"line": > 0,"character": 10}},"rangeLength": 0,"text": "\nint y = 2;"}]}} > +# CHECK: "method": "textDocument/semanticHighlighting", > +# CHECK-NEXT: "params": { > +# CHECK-NEXT: "lines": [ > +# CHECK-NEXT: { > +# CHECK-NEXT: "line": 1, > +# CHECK-NEXT: "tokens": "AAAABAABAAA=" > +# CHECK-NEXT: } > +# CHECK-NEXT: ], > +# CHECK-NEXT: "textDocument": { > +# CHECK-NEXT: "uri": "file:///clangd-test/foo.cpp" > +# CHECK-NEXT: } > +# CHECK-NEXT: } > +# CHECK-NEXT:} > +--- > +{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"test:///foo.cpp","version":2},"contentChanges": > [{"range":{"start": {"line": 0,"character": 10},"end": {"line": > 1,"character": 10}},"rangeLength": 11,"text": ""}]}} > +# CHECK: "method": "textDocument/semanticHighlighting", > +# CHECK-NEXT: "params": { > +# CHECK-NEXT: "lines": [], > +# CHECK-NEXT: "textDocument": { > +# CHECK-NEXT: "uri": "file:///clangd-test/foo.cpp" > +# CHECK-NEXT: } > +# CHECK-NEXT: } > +# CHECK-NEXT:} > +--- > {"jsonrpc":"2.0","id":3,"method":"shutdown"} > --- > {"jsonrpc":"2.0","method":"exit"} > > Modified: > clang-tools-extra/trunk/clangd/unittests/SemanticHighlightingTests.cpp > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/unittests/SemanticHighlightingTests.cpp?rev=367521&r1=367520&r2=367521&view=diff > ============================================================================== > --- clang-tools-extra/trunk/clangd/unittests/SemanticHighlightingTests.cpp > (original) > +++ clang-tools-extra/trunk/clangd/unittests/SemanticHighlightingTests.cpp > Thu Aug 1 01:08:44 2019 > @@ -29,9 +29,7 @@ makeHighlightingTokens(llvm::ArrayRef<Ra > return Tokens; > } > > -void checkHighlightings(llvm::StringRef Code) { > - Annotations Test(Code); > - auto AST = TestTU::withCode(Test.code()).build(); > +std::vector<HighlightingToken> getExpectedTokens(Annotations &Test) { > static const std::map<HighlightingKind, std::string> KindToString{ > {HighlightingKind::Variable, "Variable"}, > {HighlightingKind::Function, "Function"}, > @@ -48,10 +46,47 @@ void checkHighlightings(llvm::StringRef > Test.ranges(KindString.second), KindString.first); > ExpectedTokens.insert(ExpectedTokens.end(), Toks.begin(), Toks.end()); > } > + llvm::sort(ExpectedTokens); > + return ExpectedTokens; > +} > + > +void checkHighlightings(llvm::StringRef Code) { > + Annotations Test(Code); > + auto AST = TestTU::withCode(Test.code()).build(); > + std::vector<HighlightingToken> ActualTokens = > getSemanticHighlightings(AST); > + EXPECT_THAT(ActualTokens, getExpectedTokens(Test)); > +} > > - auto ActualTokens = getSemanticHighlightings(AST); > - EXPECT_THAT(ActualTokens, > testing::UnorderedElementsAreArray(ExpectedTokens)) > - << "Inputs is:\n" << Code; > +// Any annotations in OldCode and NewCode are converted into their > corresponding > +// HighlightingToken. The tokens are diffed against each other. Any lines > where > +// the tokens should diff must be marked with a ^ somewhere on that line in > +// NewCode. If there are diffs that aren't marked with ^ the test fails. The > +// test also fails if there are lines marked with ^ that don't differ. > +void checkDiffedHighlights(llvm::StringRef OldCode, llvm::StringRef NewCode) > { > + Annotations OldTest(OldCode); > + Annotations NewTest(NewCode); > + std::vector<HighlightingToken> OldTokens = getExpectedTokens(OldTest); > + std::vector<HighlightingToken> NewTokens = getExpectedTokens(NewTest); > + > + llvm::DenseMap<int, std::vector<HighlightingToken>> ExpectedLines; > + for (const Position &Point : NewTest.points()) { > + ExpectedLines[Point.line]; // Default initialize to an empty line. Tokens > + // are inserted on these lines later. > + } > + std::vector<LineHighlightings> ExpectedLinePairHighlighting; > + for (const HighlightingToken &Token : NewTokens) { > + auto It = ExpectedLines.find(Token.R.start.line); > + if (It != ExpectedLines.end()) > + It->second.push_back(Token); > + } > + for (auto &LineTokens : ExpectedLines) > + ExpectedLinePairHighlighting.push_back( > + {LineTokens.first, LineTokens.second}); > + > + std::vector<LineHighlightings> ActualDiffed = > + diffHighlightings(NewTokens, OldTokens, NewCode.count('\n')); > + EXPECT_THAT(ActualDiffed, > + > testing::UnorderedElementsAreArray(ExpectedLinePairHighlighting)); > } > > TEST(SemanticHighlighting, GetsCorrectTokens) { > @@ -226,8 +261,9 @@ TEST(SemanticHighlighting, GeneratesHigh > std::atomic<int> Count = {0}; > > void onDiagnosticsReady(PathRef, std::vector<Diag>) override {} > - void onHighlightingsReady( > - PathRef File, std::vector<HighlightingToken> Highlightings) override > { > + void onHighlightingsReady(PathRef File, > + std::vector<HighlightingToken> Highlightings, > + int NLines) override { > ++Count; > } > }; > @@ -252,21 +288,124 @@ TEST(SemanticHighlighting, toSemanticHig > return Pos; > }; > > - std::vector<HighlightingToken> Tokens{ > - {HighlightingKind::Variable, > - Range{CreatePosition(3, 8), CreatePosition(3, 12)}}, > - {HighlightingKind::Function, > - Range{CreatePosition(3, 4), CreatePosition(3, 7)}}, > - {HighlightingKind::Variable, > - Range{CreatePosition(1, 1), CreatePosition(1, 5)}}}; > + std::vector<LineHighlightings> Tokens{ > + {3, > + {{HighlightingKind::Variable, > + Range{CreatePosition(3, 8), CreatePosition(3, 12)}}, > + {HighlightingKind::Function, > + Range{CreatePosition(3, 4), CreatePosition(3, 7)}}}}, > + {1, > + {{HighlightingKind::Variable, > + Range{CreatePosition(1, 1), CreatePosition(1, 5)}}}}}; > std::vector<SemanticHighlightingInformation> ActualResults = > toSemanticHighlightingInformation(Tokens); > std::vector<SemanticHighlightingInformation> ExpectedResults = { > - {1, "AAAAAQAEAAA="}, > - {3, "AAAACAAEAAAAAAAEAAMAAQ=="}}; > + {3, "AAAACAAEAAAAAAAEAAMAAQ=="}, {1, "AAAAAQAEAAA="}}; > EXPECT_EQ(ActualResults, ExpectedResults); > } > > +TEST(SemanticHighlighting, HighlightingDiffer) { > + struct { > + llvm::StringRef OldCode; > + llvm::StringRef NewCode; > + } TestCases[]{{ > + R"( > + $Variable[[A]] > + $Class[[B]] > + $Function[[C]] > + )", > + R"( > + $Variable[[A]] > + $Class[[D]] > + $Function[[C]] > + )"}, > + { > + R"( > + $Class[[C]] > + $Field[[F]] > + $Variable[[V]] > + $Class[[C]] $Variable[[V]] $Field[[F]] > + )", > + R"( > + $Class[[C]] > + $Field[[F]] > + ^$Function[[F]] > + $Class[[C]] $Variable[[V]] $Field[[F]] > + )"}, > + { > + R"( > + > + $Class[[A]] > + $Variable[[A]] > + )", > + R"( > + > + ^ > + ^$Class[[A]] > + ^$Variable[[A]] > + )"}, > + { > + R"( > + $Class[[C]] > + $Field[[F]] > + $Variable[[V]] > + $Class[[C]] $Variable[[V]] $Field[[F]] > + )", > + R"( > + $Class[[C]] > + ^ > + ^ > + $Class[[C]] $Variable[[V]] $Field[[F]] > + )"}, > + { > + R"( > + $Class[[A]] > + $Variable[[A]] > + $Variable[[A]] > + )", > + R"( > + $Class[[A]] > + ^$Variable[[AA]] > + $Variable[[A]] > + )"}, > + { > + R"( > + $Class[[A]] > + $Variable[[A]] > + $Class[[A]] > + $Variable[[A]] > + )", > + R"( > + $Class[[A]] > + $Variable[[A]] > + )"}, > + { > + R"( > + $Class[[A]] > + $Variable[[A]] > + )", > + R"( > + $Class[[A]] > + $Variable[[A]] > + ^$Class[[A]] > + ^$Variable[[A]] > + )"}, > + { > + R"( > + $Variable[[A]] > + $Variable[[A]] > + $Variable[[A]] > + )", > + R"( > + ^$Class[[A]] > + ^$Class[[A]] > + ^$Class[[A]] > + )"}}; > + > + for (const auto &Test : TestCases) > + checkDiffedHighlights(Test.OldCode, Test.NewCode); > +} > + > } // namespace > } // namespace clangd > } // namespace clang > > > _______________________________________________ > cfe-commits mailing list > cfe-commits@lists.llvm.org > https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits