Index: clang-tools-extra/trunk/clangd/SemanticHighlighting.h =================================================================== --- clang-tools-extra/trunk/clangd/SemanticHighlighting.h +++ clang-tools-extra/trunk/clangd/SemanticHighlighting.h @@ -18,6 +18,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SEMANTICHIGHLIGHTING_H #include "Protocol.h" +#include "llvm/Support/raw_ostream.h" namespace clang { namespace clangd { @@ -42,6 +43,7 @@ NumKinds, }; +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, HighlightingKind K); // Contains all information needed for the highlighting a token. struct HighlightingToken { Index: clang-tools-extra/trunk/clangd/SemanticHighlighting.cpp =================================================================== --- clang-tools-extra/trunk/clangd/SemanticHighlighting.cpp +++ clang-tools-extra/trunk/clangd/SemanticHighlighting.cpp @@ -351,6 +351,43 @@ } } // namespace +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, HighlightingKind K) { + switch (K) { + case HighlightingKind::Variable: + return OS << "Variable"; + case HighlightingKind::LocalVariable: + return OS << "LocalVariable"; + case HighlightingKind::Parameter: + return OS << "Parameter"; + case HighlightingKind::Function: + return OS << "Function"; + case HighlightingKind::Method: + return OS << "Method"; + case HighlightingKind::StaticMethod: + return OS << "StaticMethod"; + case HighlightingKind::Field: + return OS << "Field"; + case HighlightingKind::StaticField: + return OS << "StaticField"; + case HighlightingKind::Class: + return OS << "Class"; + case HighlightingKind::Enum: + return OS << "Enum"; + case HighlightingKind::EnumConstant: + return OS << "EnumConstant"; + case HighlightingKind::Namespace: + return OS << "Namespace"; + case HighlightingKind::TemplateParameter: + return OS << "TemplateParameter"; + case HighlightingKind::Primitive: + return OS << "Primitive"; + case HighlightingKind::Macro: + return OS << "Macro"; + case HighlightingKind::NumKinds: + llvm_unreachable("NumKinds is not a valid HighlightingKind"); + } +} + std::vector diffHighlightings(ArrayRef New, ArrayRef Old) { Index: clang-tools-extra/trunk/clangd/unittests/SemanticHighlightingTests.cpp =================================================================== --- clang-tools-extra/trunk/clangd/unittests/SemanticHighlightingTests.cpp +++ clang-tools-extra/trunk/clangd/unittests/SemanticHighlightingTests.cpp @@ -10,9 +10,14 @@ #include "ClangdServer.h" #include "Protocol.h" #include "SemanticHighlighting.h" +#include "SourceCode.h" #include "TestFS.h" #include "TestTU.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" #include "gmock/gmock.h" +#include namespace clang { namespace clangd { @@ -59,6 +64,36 @@ return ExpectedTokens; } +/// Annotates the input code with provided semantic highlightings. Results look +/// something like: +/// class $Class[[X]] { +/// $Primitive[[int]] $Field[[a]] = 0; +/// }; +std::string annotate(llvm::StringRef Input, + llvm::ArrayRef Tokens) { + assert(std::is_sorted( + Tokens.begin(), Tokens.end(), + [](const HighlightingToken &L, const HighlightingToken &R) { + return L.R.start < R.R.start; + })); + + std::string Result; + unsigned NextChar = 0; + for (auto &T : Tokens) { + unsigned StartOffset = llvm::cantFail(positionToOffset(Input, T.R.start)); + unsigned EndOffset = llvm::cantFail(positionToOffset(Input, T.R.end)); + assert(StartOffset <= EndOffset); + assert(NextChar <= StartOffset); + + Result += Input.substr(NextChar, StartOffset - NextChar); + Result += llvm::formatv("${0}[[{1}]]", T.Kind, + Input.substr(StartOffset, EndOffset - StartOffset)); + NextChar = EndOffset; + } + Result += Input.substr(NextChar); + return Result; +} + void checkHighlightings(llvm::StringRef Code, std::vector> @@ -68,8 +103,8 @@ for (auto File : AdditionalFiles) TU.AdditionalFiles.insert({File.first, File.second}); auto AST = TU.build(); - std::vector ActualTokens = getSemanticHighlightings(AST); - EXPECT_THAT(ActualTokens, getExpectedTokens(Test)) << Code; + + EXPECT_EQ(Code, annotate(Test.code(), getSemanticHighlightings(AST))); } // Any annotations in OldCode and NewCode are converted into their corresponding