2019-06-26 21:08:36 +08:00
|
|
|
//==- SemanticHighlightingTests.cpp - SemanticHighlighting tests-*- C++ -* -==//
|
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Annotations.h"
|
2019-06-27 23:13:03 +08:00
|
|
|
#include "ClangdServer.h"
|
2019-07-04 15:53:12 +08:00
|
|
|
#include "Protocol.h"
|
2019-06-26 21:08:36 +08:00
|
|
|
#include "SemanticHighlighting.h"
|
2019-09-09 16:47:05 +08:00
|
|
|
#include "SourceCode.h"
|
2019-06-27 23:13:03 +08:00
|
|
|
#include "TestFS.h"
|
2019-06-26 21:08:36 +08:00
|
|
|
#include "TestTU.h"
|
2019-09-09 16:47:05 +08:00
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
|
#include "llvm/Support/Error.h"
|
2019-06-26 21:08:36 +08:00
|
|
|
#include "gmock/gmock.h"
|
2019-09-09 16:47:05 +08:00
|
|
|
#include <algorithm>
|
2019-06-26 21:08:36 +08:00
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace clangd {
|
|
|
|
namespace {
|
|
|
|
|
2019-08-26 16:38:45 +08:00
|
|
|
MATCHER_P(LineNumber, L, "") { return arg.Line == L; }
|
|
|
|
MATCHER(EmptyHighlightings, "") { return arg.Tokens.empty(); }
|
|
|
|
|
2019-06-26 21:08:36 +08:00
|
|
|
std::vector<HighlightingToken>
|
|
|
|
makeHighlightingTokens(llvm::ArrayRef<Range> Ranges, HighlightingKind Kind) {
|
|
|
|
std::vector<HighlightingToken> Tokens(Ranges.size());
|
|
|
|
for (int I = 0, End = Ranges.size(); I < End; ++I) {
|
|
|
|
Tokens[I].R = Ranges[I];
|
|
|
|
Tokens[I].Kind = Kind;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Tokens;
|
|
|
|
}
|
|
|
|
|
2019-08-01 16:08:44 +08:00
|
|
|
std::vector<HighlightingToken> getExpectedTokens(Annotations &Test) {
|
2019-06-26 21:08:36 +08:00
|
|
|
static const std::map<HighlightingKind, std::string> KindToString{
|
|
|
|
{HighlightingKind::Variable, "Variable"},
|
2019-08-30 11:37:24 +08:00
|
|
|
{HighlightingKind::LocalVariable, "LocalVariable"},
|
2019-08-19 15:51:39 +08:00
|
|
|
{HighlightingKind::Parameter, "Parameter"},
|
2019-07-10 16:41:25 +08:00
|
|
|
{HighlightingKind::Function, "Function"},
|
|
|
|
{HighlightingKind::Class, "Class"},
|
2019-07-11 17:29:16 +08:00
|
|
|
{HighlightingKind::Enum, "Enum"},
|
2019-07-15 15:41:12 +08:00
|
|
|
{HighlightingKind::Namespace, "Namespace"},
|
2019-07-15 16:12:21 +08:00
|
|
|
{HighlightingKind::EnumConstant, "EnumConstant"},
|
|
|
|
{HighlightingKind::Field, "Field"},
|
2019-08-30 11:37:24 +08:00
|
|
|
{HighlightingKind::StaticField, "StaticField"},
|
2019-07-18 17:56:38 +08:00
|
|
|
{HighlightingKind::Method, "Method"},
|
2019-08-30 11:37:24 +08:00
|
|
|
{HighlightingKind::StaticMethod, "StaticMethod"},
|
2019-10-15 02:26:13 +08:00
|
|
|
{HighlightingKind::Typedef, "Typedef"},
|
|
|
|
{HighlightingKind::DependentType, "DependentType"},
|
|
|
|
{HighlightingKind::DependentName, "DependentName"},
|
2019-08-08 21:10:30 +08:00
|
|
|
{HighlightingKind::TemplateParameter, "TemplateParameter"},
|
2019-08-30 23:47:27 +08:00
|
|
|
{HighlightingKind::Primitive, "Primitive"},
|
|
|
|
{HighlightingKind::Macro, "Macro"}};
|
2019-06-26 21:08:36 +08:00
|
|
|
std::vector<HighlightingToken> ExpectedTokens;
|
|
|
|
for (const auto &KindString : KindToString) {
|
2019-07-10 16:41:25 +08:00
|
|
|
std::vector<HighlightingToken> Toks = makeHighlightingTokens(
|
|
|
|
Test.ranges(KindString.second), KindString.first);
|
2019-06-26 21:08:36 +08:00
|
|
|
ExpectedTokens.insert(ExpectedTokens.end(), Toks.begin(), Toks.end());
|
|
|
|
}
|
2019-08-01 16:08:44 +08:00
|
|
|
llvm::sort(ExpectedTokens);
|
|
|
|
return ExpectedTokens;
|
|
|
|
}
|
|
|
|
|
2019-09-09 16:47:05 +08:00
|
|
|
/// 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<HighlightingToken> 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;
|
|
|
|
}
|
|
|
|
|
2019-08-12 21:01:11 +08:00
|
|
|
void checkHighlightings(llvm::StringRef Code,
|
|
|
|
std::vector<std::pair</*FileName*/ llvm::StringRef,
|
|
|
|
/*FileContent*/ llvm::StringRef>>
|
|
|
|
AdditionalFiles = {}) {
|
2019-08-01 16:08:44 +08:00
|
|
|
Annotations Test(Code);
|
2019-10-13 21:15:27 +08:00
|
|
|
TestTU TU;
|
|
|
|
TU.Code = Test.code();
|
|
|
|
|
|
|
|
// FIXME: Auto-completion in a template requires disabling delayed template
|
|
|
|
// parsing.
|
|
|
|
TU.ExtraArgs.push_back("-fno-delayed-template-parsing");
|
|
|
|
|
2019-08-12 21:01:11 +08:00
|
|
|
for (auto File : AdditionalFiles)
|
|
|
|
TU.AdditionalFiles.insert({File.first, File.second});
|
|
|
|
auto AST = TU.build();
|
2019-09-09 16:47:05 +08:00
|
|
|
|
|
|
|
EXPECT_EQ(Code, annotate(Test.code(), getSemanticHighlightings(AST)));
|
2019-08-01 16:08:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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(
|
2019-09-25 06:17:55 +08:00
|
|
|
{LineTokens.first, LineTokens.second, /*IsInactive = */ false});
|
2019-06-26 21:08:36 +08:00
|
|
|
|
2019-08-01 16:08:44 +08:00
|
|
|
std::vector<LineHighlightings> ActualDiffed =
|
2019-08-26 16:38:45 +08:00
|
|
|
diffHighlightings(NewTokens, OldTokens);
|
2019-08-01 16:08:44 +08:00
|
|
|
EXPECT_THAT(ActualDiffed,
|
2019-08-26 16:38:45 +08:00
|
|
|
testing::UnorderedElementsAreArray(ExpectedLinePairHighlighting))
|
|
|
|
<< OldCode;
|
2019-06-26 21:08:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(SemanticHighlighting, GetsCorrectTokens) {
|
|
|
|
const char *TestCases[] = {
|
2019-08-28 03:39:11 +08:00
|
|
|
R"cpp(
|
2019-07-10 16:41:25 +08:00
|
|
|
struct $Class[[AS]] {
|
2019-10-28 18:31:06 +08:00
|
|
|
double $Field[[SomeMember]];
|
2019-07-05 21:06:03 +08:00
|
|
|
};
|
|
|
|
struct {
|
|
|
|
} $Variable[[S]];
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Function[[foo]](int $Parameter[[A]], $Class[[AS]] $Parameter[[As]]) {
|
2019-08-28 03:39:11 +08:00
|
|
|
$Primitive[[auto]] $LocalVariable[[VeryLongVariableName]] = 12312;
|
|
|
|
$Class[[AS]] $LocalVariable[[AA]];
|
|
|
|
$Primitive[[auto]] $LocalVariable[[L]] = $LocalVariable[[AA]].$Field[[SomeMember]] + $Parameter[[A]];
|
2019-10-28 18:31:06 +08:00
|
|
|
auto $LocalVariable[[FN]] = [ $LocalVariable[[AA]]](int $Parameter[[A]]) -> void {};
|
2019-08-28 03:39:11 +08:00
|
|
|
$LocalVariable[[FN]](12312);
|
2019-07-05 21:06:03 +08:00
|
|
|
}
|
|
|
|
)cpp",
|
2019-08-28 03:39:11 +08:00
|
|
|
R"cpp(
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Function[[foo]](int);
|
|
|
|
void $Function[[Gah]]();
|
|
|
|
void $Function[[foo]]() {
|
2019-08-28 03:39:11 +08:00
|
|
|
auto $LocalVariable[[Bou]] = $Function[[Gah]];
|
2019-07-05 21:06:03 +08:00
|
|
|
}
|
2019-07-10 16:41:25 +08:00
|
|
|
struct $Class[[A]] {
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Method[[abc]]();
|
2019-07-10 16:41:25 +08:00
|
|
|
};
|
2019-07-05 21:06:03 +08:00
|
|
|
)cpp",
|
2019-08-28 03:39:11 +08:00
|
|
|
R"cpp(
|
2019-07-11 17:29:16 +08:00
|
|
|
namespace $Namespace[[abc]] {
|
2019-07-18 17:56:38 +08:00
|
|
|
template<typename $TemplateParameter[[T]]>
|
2019-07-10 16:41:25 +08:00
|
|
|
struct $Class[[A]] {
|
2019-07-18 17:56:38 +08:00
|
|
|
$TemplateParameter[[T]] $Field[[t]];
|
2019-07-10 16:41:25 +08:00
|
|
|
};
|
|
|
|
}
|
2019-07-18 17:56:38 +08:00
|
|
|
template<typename $TemplateParameter[[T]]>
|
|
|
|
struct $Class[[C]] : $Namespace[[abc]]::$Class[[A]]<$TemplateParameter[[T]]> {
|
2019-10-15 02:26:13 +08:00
|
|
|
typename $TemplateParameter[[T]]::$DependentType[[A]]* $Field[[D]];
|
2019-07-10 16:41:25 +08:00
|
|
|
};
|
2019-10-28 18:31:06 +08:00
|
|
|
$Namespace[[abc]]::$Class[[A]]<int> $Variable[[AA]];
|
|
|
|
typedef $Namespace[[abc]]::$Class[[A]]<int> $Class[[AAA]];
|
2019-07-10 16:41:25 +08:00
|
|
|
struct $Class[[B]] {
|
|
|
|
$Class[[B]]();
|
|
|
|
~$Class[[B]]();
|
2019-10-28 18:31:06 +08:00
|
|
|
void operator<<($Class[[B]]);
|
2019-07-15 16:12:21 +08:00
|
|
|
$Class[[AAA]] $Field[[AA]];
|
2019-07-10 16:41:25 +08:00
|
|
|
};
|
|
|
|
$Class[[B]]::$Class[[B]]() {}
|
|
|
|
$Class[[B]]::~$Class[[B]]() {}
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Function[[f]] () {
|
2019-08-28 03:39:11 +08:00
|
|
|
$Class[[B]] $LocalVariable[[BB]] = $Class[[B]]();
|
|
|
|
$LocalVariable[[BB]].~$Class[[B]]();
|
2019-07-10 16:41:25 +08:00
|
|
|
$Class[[B]]();
|
|
|
|
}
|
|
|
|
)cpp",
|
2019-08-28 03:39:11 +08:00
|
|
|
R"cpp(
|
2019-07-15 15:41:12 +08:00
|
|
|
enum class $Enum[[E]] {
|
|
|
|
$EnumConstant[[A]],
|
|
|
|
$EnumConstant[[B]],
|
|
|
|
};
|
|
|
|
enum $Enum[[EE]] {
|
|
|
|
$EnumConstant[[Hi]],
|
|
|
|
};
|
2019-07-10 16:41:25 +08:00
|
|
|
struct $Class[[A]] {
|
2019-07-15 16:12:21 +08:00
|
|
|
$Enum[[E]] $Field[[EEE]];
|
|
|
|
$Enum[[EE]] $Field[[EEEE]];
|
2019-07-05 21:06:03 +08:00
|
|
|
};
|
2019-10-28 18:31:06 +08:00
|
|
|
int $Variable[[I]] = $EnumConstant[[Hi]];
|
2019-07-15 15:41:12 +08:00
|
|
|
$Enum[[E]] $Variable[[L]] = $Enum[[E]]::$EnumConstant[[B]];
|
2019-07-11 17:29:16 +08:00
|
|
|
)cpp",
|
2019-08-28 03:39:11 +08:00
|
|
|
R"cpp(
|
2019-07-11 17:29:16 +08:00
|
|
|
namespace $Namespace[[abc]] {
|
|
|
|
namespace {}
|
|
|
|
namespace $Namespace[[bcd]] {
|
|
|
|
struct $Class[[A]] {};
|
|
|
|
namespace $Namespace[[cde]] {
|
|
|
|
struct $Class[[A]] {
|
|
|
|
enum class $Enum[[B]] {
|
2019-07-15 15:41:12 +08:00
|
|
|
$EnumConstant[[Hi]],
|
2019-07-11 17:29:16 +08:00
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
using namespace $Namespace[[abc]]::$Namespace[[bcd]];
|
|
|
|
namespace $Namespace[[vwz]] =
|
|
|
|
$Namespace[[abc]]::$Namespace[[bcd]]::$Namespace[[cde]];
|
|
|
|
$Namespace[[abc]]::$Namespace[[bcd]]::$Class[[A]] $Variable[[AA]];
|
|
|
|
$Namespace[[vwz]]::$Class[[A]]::$Enum[[B]] $Variable[[AAA]] =
|
2019-07-15 15:41:12 +08:00
|
|
|
$Namespace[[vwz]]::$Class[[A]]::$Enum[[B]]::$EnumConstant[[Hi]];
|
2019-07-11 17:29:16 +08:00
|
|
|
::$Namespace[[vwz]]::$Class[[A]] $Variable[[B]];
|
|
|
|
::$Namespace[[abc]]::$Namespace[[bcd]]::$Class[[A]] $Variable[[BB]];
|
2019-07-15 16:12:21 +08:00
|
|
|
)cpp",
|
2019-08-28 03:39:11 +08:00
|
|
|
R"cpp(
|
2019-07-15 16:12:21 +08:00
|
|
|
struct $Class[[D]] {
|
2019-10-28 18:31:06 +08:00
|
|
|
double $Field[[C]];
|
2019-07-15 16:12:21 +08:00
|
|
|
};
|
|
|
|
struct $Class[[A]] {
|
2019-10-28 18:31:06 +08:00
|
|
|
double $Field[[B]];
|
2019-07-15 16:12:21 +08:00
|
|
|
$Class[[D]] $Field[[E]];
|
2019-10-28 18:31:06 +08:00
|
|
|
static double $StaticField[[S]];
|
|
|
|
static void $StaticMethod[[bar]]() {}
|
|
|
|
void $Method[[foo]]() {
|
2019-07-15 16:12:21 +08:00
|
|
|
$Field[[B]] = 123;
|
|
|
|
this->$Field[[B]] = 156;
|
|
|
|
this->$Method[[foo]]();
|
|
|
|
$Method[[foo]]();
|
2019-08-30 11:37:24 +08:00
|
|
|
$StaticMethod[[bar]]();
|
|
|
|
$StaticField[[S]] = 90.1;
|
2019-07-15 16:12:21 +08:00
|
|
|
}
|
|
|
|
};
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Function[[foo]]() {
|
2019-08-28 03:39:11 +08:00
|
|
|
$Class[[A]] $LocalVariable[[AA]];
|
|
|
|
$LocalVariable[[AA]].$Field[[B]] += 2;
|
|
|
|
$LocalVariable[[AA]].$Method[[foo]]();
|
|
|
|
$LocalVariable[[AA]].$Field[[E]].$Field[[C]];
|
2019-08-30 11:37:24 +08:00
|
|
|
$Class[[A]]::$StaticField[[S]] = 90;
|
2019-07-15 16:12:21 +08:00
|
|
|
}
|
2019-07-15 23:08:27 +08:00
|
|
|
)cpp",
|
2019-08-28 03:39:11 +08:00
|
|
|
R"cpp(
|
2019-07-15 23:08:27 +08:00
|
|
|
struct $Class[[AA]] {
|
2019-10-28 18:31:06 +08:00
|
|
|
int $Field[[A]];
|
2019-07-15 23:08:27 +08:00
|
|
|
}
|
2019-10-28 18:31:06 +08:00
|
|
|
int $Variable[[B]];
|
2019-07-15 23:08:27 +08:00
|
|
|
$Class[[AA]] $Variable[[A]]{$Variable[[B]]};
|
2019-07-16 21:23:12 +08:00
|
|
|
)cpp",
|
2019-08-28 03:39:11 +08:00
|
|
|
R"cpp(
|
2019-07-16 21:23:12 +08:00
|
|
|
namespace $Namespace[[a]] {
|
|
|
|
struct $Class[[A]] {};
|
2019-10-28 18:31:06 +08:00
|
|
|
typedef char $Primitive[[C]];
|
2019-07-16 21:23:12 +08:00
|
|
|
}
|
|
|
|
typedef $Namespace[[a]]::$Class[[A]] $Class[[B]];
|
|
|
|
using $Class[[BB]] = $Namespace[[a]]::$Class[[A]];
|
|
|
|
enum class $Enum[[E]] {};
|
|
|
|
typedef $Enum[[E]] $Enum[[C]];
|
|
|
|
typedef $Enum[[C]] $Enum[[CC]];
|
|
|
|
using $Enum[[CD]] = $Enum[[CC]];
|
|
|
|
$Enum[[CC]] $Function[[f]]($Class[[B]]);
|
|
|
|
$Enum[[CD]] $Function[[f]]($Class[[BB]]);
|
2019-08-08 21:10:30 +08:00
|
|
|
typedef $Namespace[[a]]::$Primitive[[C]] $Primitive[[PC]];
|
2019-10-28 18:31:06 +08:00
|
|
|
typedef float $Primitive[[F]];
|
2019-07-18 17:56:38 +08:00
|
|
|
)cpp",
|
2019-08-28 03:39:11 +08:00
|
|
|
R"cpp(
|
2019-10-28 18:31:06 +08:00
|
|
|
template<typename $TemplateParameter[[T]], typename = void>
|
2019-07-18 17:56:38 +08:00
|
|
|
class $Class[[A]] {
|
|
|
|
$TemplateParameter[[T]] $Field[[AA]];
|
|
|
|
$TemplateParameter[[T]] $Method[[foo]]();
|
|
|
|
};
|
|
|
|
template<class $TemplateParameter[[TT]]>
|
|
|
|
class $Class[[B]] {
|
|
|
|
$Class[[A]]<$TemplateParameter[[TT]]> $Field[[AA]];
|
|
|
|
};
|
|
|
|
template<class $TemplateParameter[[TT]], class $TemplateParameter[[GG]]>
|
|
|
|
class $Class[[BB]] {};
|
|
|
|
template<class $TemplateParameter[[T]]>
|
2019-10-28 18:31:06 +08:00
|
|
|
class $Class[[BB]]<$TemplateParameter[[T]], int> {};
|
2019-07-18 17:56:38 +08:00
|
|
|
template<class $TemplateParameter[[T]]>
|
|
|
|
class $Class[[BB]]<$TemplateParameter[[T]], $TemplateParameter[[T]]*> {};
|
|
|
|
|
|
|
|
template<template<class> class $TemplateParameter[[T]], class $TemplateParameter[[C]]>
|
|
|
|
$TemplateParameter[[T]]<$TemplateParameter[[C]]> $Function[[f]]();
|
|
|
|
|
|
|
|
template<typename>
|
|
|
|
class $Class[[Foo]] {};
|
|
|
|
|
|
|
|
template<typename $TemplateParameter[[T]]>
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Function[[foo]]($TemplateParameter[[T]] ...);
|
2019-08-08 15:21:06 +08:00
|
|
|
)cpp",
|
2019-08-28 03:39:11 +08:00
|
|
|
R"cpp(
|
2019-08-08 15:21:06 +08:00
|
|
|
template <class $TemplateParameter[[T]]>
|
|
|
|
struct $Class[[Tmpl]] {$TemplateParameter[[T]] $Field[[x]] = 0;};
|
2019-10-28 18:31:06 +08:00
|
|
|
extern template struct $Class[[Tmpl]]<float>;
|
|
|
|
template struct $Class[[Tmpl]]<double>;
|
2019-08-08 20:43:55 +08:00
|
|
|
)cpp",
|
2019-08-28 03:39:11 +08:00
|
|
|
// This test is to guard against highlightings disappearing when using
|
|
|
|
// conversion operators as their behaviour in the clang AST differ from
|
|
|
|
// other CXXMethodDecls.
|
|
|
|
R"cpp(
|
2019-08-08 20:43:55 +08:00
|
|
|
class $Class[[Foo]] {};
|
|
|
|
struct $Class[[Bar]] {
|
|
|
|
explicit operator $Class[[Foo]]*() const;
|
2019-10-28 18:31:06 +08:00
|
|
|
explicit operator int() const;
|
2019-08-08 20:43:55 +08:00
|
|
|
operator $Class[[Foo]]();
|
|
|
|
};
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Function[[f]]() {
|
2019-08-28 03:39:11 +08:00
|
|
|
$Class[[Bar]] $LocalVariable[[B]];
|
|
|
|
$Class[[Foo]] $LocalVariable[[F]] = $LocalVariable[[B]];
|
|
|
|
$Class[[Foo]] *$LocalVariable[[FP]] = ($Class[[Foo]]*)$LocalVariable[[B]];
|
2019-10-28 18:31:06 +08:00
|
|
|
int $LocalVariable[[I]] = (int)$LocalVariable[[B]];
|
2019-08-08 20:43:55 +08:00
|
|
|
}
|
2019-08-09 15:30:28 +08:00
|
|
|
)cpp"
|
2019-08-28 03:39:11 +08:00
|
|
|
R"cpp(
|
2019-08-09 15:30:28 +08:00
|
|
|
struct $Class[[B]] {};
|
|
|
|
struct $Class[[A]] {
|
|
|
|
$Class[[B]] $Field[[BB]];
|
2019-08-19 15:51:39 +08:00
|
|
|
$Class[[A]] &operator=($Class[[A]] &&$Parameter[[O]]);
|
2019-08-09 15:30:28 +08:00
|
|
|
};
|
|
|
|
|
2019-08-19 15:51:39 +08:00
|
|
|
$Class[[A]] &$Class[[A]]::operator=($Class[[A]] &&$Parameter[[O]]) = default;
|
2019-08-09 20:19:10 +08:00
|
|
|
)cpp",
|
2019-08-28 03:39:11 +08:00
|
|
|
R"cpp(
|
2019-08-09 20:19:10 +08:00
|
|
|
enum $Enum[[En]] {
|
|
|
|
$EnumConstant[[EC]],
|
|
|
|
};
|
|
|
|
class $Class[[Foo]] {};
|
|
|
|
class $Class[[Bar]] {
|
|
|
|
$Class[[Foo]] $Field[[Fo]];
|
|
|
|
$Enum[[En]] $Field[[E]];
|
2019-10-28 18:31:06 +08:00
|
|
|
int $Field[[I]];
|
2019-08-19 15:51:39 +08:00
|
|
|
$Class[[Bar]] ($Class[[Foo]] $Parameter[[F]],
|
|
|
|
$Enum[[En]] $Parameter[[E]])
|
|
|
|
: $Field[[Fo]] ($Parameter[[F]]), $Field[[E]] ($Parameter[[E]]),
|
2019-08-09 20:19:10 +08:00
|
|
|
$Field[[I]] (123) {}
|
|
|
|
};
|
|
|
|
class $Class[[Bar2]] : public $Class[[Bar]] {
|
|
|
|
$Class[[Bar2]]() : $Class[[Bar]]($Class[[Foo]](), $EnumConstant[[EC]]) {}
|
|
|
|
};
|
2019-08-12 15:45:12 +08:00
|
|
|
)cpp",
|
2019-08-28 03:39:11 +08:00
|
|
|
R"cpp(
|
2019-08-12 15:45:12 +08:00
|
|
|
enum $Enum[[E]] {
|
|
|
|
$EnumConstant[[E]],
|
|
|
|
};
|
|
|
|
class $Class[[Foo]] {};
|
|
|
|
$Enum[[auto]] $Variable[[AE]] = $Enum[[E]]::$EnumConstant[[E]];
|
|
|
|
$Class[[auto]] $Variable[[AF]] = $Class[[Foo]]();
|
|
|
|
$Class[[decltype]](auto) $Variable[[AF2]] = $Class[[Foo]]();
|
|
|
|
$Class[[auto]] *$Variable[[AFP]] = &$Variable[[AF]];
|
|
|
|
$Enum[[auto]] &$Variable[[AER]] = $Variable[[AE]];
|
|
|
|
$Primitive[[auto]] $Variable[[Form]] = 10.2 + 2 * 4;
|
|
|
|
$Primitive[[decltype]]($Variable[[Form]]) $Variable[[F]] = 10;
|
2019-10-28 18:31:06 +08:00
|
|
|
auto $Variable[[Fun]] = []()->void{};
|
2019-08-16 17:30:21 +08:00
|
|
|
)cpp",
|
2019-08-28 03:39:11 +08:00
|
|
|
R"cpp(
|
2019-08-16 17:30:21 +08:00
|
|
|
class $Class[[G]] {};
|
|
|
|
template<$Class[[G]] *$TemplateParameter[[U]]>
|
|
|
|
class $Class[[GP]] {};
|
|
|
|
template<$Class[[G]] &$TemplateParameter[[U]]>
|
|
|
|
class $Class[[GR]] {};
|
2019-10-28 18:31:06 +08:00
|
|
|
template<int *$TemplateParameter[[U]]>
|
2019-08-16 17:30:21 +08:00
|
|
|
class $Class[[IP]] {
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Method[[f]]() {
|
2019-08-16 17:30:21 +08:00
|
|
|
*$TemplateParameter[[U]] += 5;
|
|
|
|
}
|
|
|
|
};
|
2019-10-28 18:31:06 +08:00
|
|
|
template<unsigned $TemplateParameter[[U]] = 2>
|
2019-08-16 17:30:21 +08:00
|
|
|
class $Class[[Foo]] {
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Method[[f]]() {
|
|
|
|
for(int $LocalVariable[[I]] = 0;
|
2019-08-28 03:39:11 +08:00
|
|
|
$LocalVariable[[I]] < $TemplateParameter[[U]];) {}
|
2019-08-16 17:30:21 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
$Class[[G]] $Variable[[L]];
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Function[[f]]() {
|
2019-08-28 03:39:11 +08:00
|
|
|
$Class[[Foo]]<123> $LocalVariable[[F]];
|
|
|
|
$Class[[GP]]<&$Variable[[L]]> $LocalVariable[[LL]];
|
|
|
|
$Class[[GR]]<$Variable[[L]]> $LocalVariable[[LLL]];
|
2019-08-16 17:30:21 +08:00
|
|
|
}
|
|
|
|
)cpp",
|
2019-08-28 03:39:11 +08:00
|
|
|
R"cpp(
|
2019-12-06 08:16:08 +08:00
|
|
|
template<typename $TemplateParameter[[T]],
|
|
|
|
void (T::*$TemplateParameter[[method]])(int)>
|
2019-08-16 17:30:21 +08:00
|
|
|
struct $Class[[G]] {
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Method[[foo]](
|
2019-08-19 15:51:39 +08:00
|
|
|
$TemplateParameter[[T]] *$Parameter[[O]]) {
|
|
|
|
($Parameter[[O]]->*$TemplateParameter[[method]])(10);
|
2019-08-16 17:30:21 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
struct $Class[[F]] {
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Method[[f]](int);
|
2019-08-16 17:30:21 +08:00
|
|
|
};
|
2019-10-28 18:31:06 +08:00
|
|
|
template<void (*$TemplateParameter[[Func]])()>
|
2019-08-16 17:30:21 +08:00
|
|
|
struct $Class[[A]] {
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Method[[f]]() {
|
2019-08-16 17:30:21 +08:00
|
|
|
(*$TemplateParameter[[Func]])();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Function[[foo]]() {
|
2019-08-28 03:39:11 +08:00
|
|
|
$Class[[F]] $LocalVariable[[FF]];
|
|
|
|
$Class[[G]]<$Class[[F]], &$Class[[F]]::$Method[[f]]> $LocalVariable[[GG]];
|
|
|
|
$LocalVariable[[GG]].$Method[[foo]](&$LocalVariable[[FF]]);
|
|
|
|
$Class[[A]]<$Function[[foo]]> $LocalVariable[[AA]];
|
2019-08-20 00:27:49 +08:00
|
|
|
)cpp",
|
2019-08-28 03:39:11 +08:00
|
|
|
// Tokens that share a source range but have conflicting Kinds are not
|
|
|
|
// highlighted.
|
|
|
|
R"cpp(
|
2019-09-24 19:14:06 +08:00
|
|
|
#define $Macro[[DEF_MULTIPLE]](X) namespace X { class X { int X; }; }
|
|
|
|
#define $Macro[[DEF_CLASS]](T) class T {};
|
2019-09-10 18:10:36 +08:00
|
|
|
// Preamble ends.
|
2019-08-30 23:47:27 +08:00
|
|
|
$Macro[[DEF_MULTIPLE]](XYZ);
|
|
|
|
$Macro[[DEF_MULTIPLE]](XYZW);
|
|
|
|
$Macro[[DEF_CLASS]]($Class[[A]])
|
2019-09-10 18:10:36 +08:00
|
|
|
#define $Macro[[MACRO_CONCAT]](X, V, T) T foo##X = V
|
|
|
|
#define $Macro[[DEF_VAR]](X, V) int X = V
|
|
|
|
#define $Macro[[DEF_VAR_T]](T, X, V) T X = V
|
|
|
|
#define $Macro[[DEF_VAR_REV]](V, X) DEF_VAR(X, V)
|
|
|
|
#define $Macro[[CPY]](X) X
|
|
|
|
#define $Macro[[DEF_VAR_TYPE]](X, Y) X Y
|
|
|
|
#define $Macro[[SOME_NAME]] variable
|
|
|
|
#define $Macro[[SOME_NAME_SET]] variable2 = 123
|
|
|
|
#define $Macro[[INC_VAR]](X) X += 2
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Function[[foo]]() {
|
2019-08-30 23:47:27 +08:00
|
|
|
$Macro[[DEF_VAR]]($LocalVariable[[X]], 123);
|
|
|
|
$Macro[[DEF_VAR_REV]](908, $LocalVariable[[XY]]);
|
2019-10-28 18:31:06 +08:00
|
|
|
int $Macro[[CPY]]( $LocalVariable[[XX]] );
|
2019-08-30 23:47:27 +08:00
|
|
|
$Macro[[DEF_VAR_TYPE]]($Class[[A]], $LocalVariable[[AA]]);
|
2019-10-28 18:31:06 +08:00
|
|
|
double $Macro[[SOME_NAME]];
|
|
|
|
int $Macro[[SOME_NAME_SET]];
|
2019-08-28 03:39:11 +08:00
|
|
|
$LocalVariable[[variable]] = 20.1;
|
2019-10-28 18:31:06 +08:00
|
|
|
$Macro[[MACRO_CONCAT]](var, 2, float);
|
2019-08-30 23:47:27 +08:00
|
|
|
$Macro[[DEF_VAR_T]]($Class[[A]], $Macro[[CPY]](
|
|
|
|
$Macro[[CPY]]($LocalVariable[[Nested]])),
|
|
|
|
$Macro[[CPY]]($Class[[A]]()));
|
|
|
|
$Macro[[INC_VAR]]($LocalVariable[[variable]]);
|
2019-08-20 00:27:49 +08:00
|
|
|
}
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Macro[[SOME_NAME]]();
|
2019-08-30 23:47:27 +08:00
|
|
|
$Macro[[DEF_VAR]]($Variable[[XYZ]], 567);
|
|
|
|
$Macro[[DEF_VAR_REV]](756, $Variable[[AB]]);
|
2019-08-20 00:27:49 +08:00
|
|
|
|
2019-09-10 18:10:36 +08:00
|
|
|
#define $Macro[[CALL_FN]](F) F();
|
|
|
|
#define $Macro[[DEF_FN]](F) void F ()
|
2019-08-30 23:47:27 +08:00
|
|
|
$Macro[[DEF_FN]]($Function[[g]]) {
|
|
|
|
$Macro[[CALL_FN]]($Function[[foo]]);
|
2019-08-20 00:27:49 +08:00
|
|
|
}
|
|
|
|
)cpp",
|
2019-08-28 03:39:11 +08:00
|
|
|
R"cpp(
|
2019-09-24 19:14:06 +08:00
|
|
|
#define $Macro[[fail]](expr) expr
|
|
|
|
#define $Macro[[assert]](COND) if (!(COND)) { fail("assertion failed" #COND); }
|
2019-09-10 18:10:36 +08:00
|
|
|
// Preamble ends.
|
2019-10-28 18:31:06 +08:00
|
|
|
int $Variable[[x]];
|
|
|
|
int $Variable[[y]];
|
|
|
|
int $Function[[f]]();
|
|
|
|
void $Function[[foo]]() {
|
2019-08-30 23:47:27 +08:00
|
|
|
$Macro[[assert]]($Variable[[x]] != $Variable[[y]]);
|
|
|
|
$Macro[[assert]]($Variable[[x]] != $Function[[f]]());
|
2019-08-16 17:30:21 +08:00
|
|
|
}
|
2019-10-07 18:10:31 +08:00
|
|
|
)cpp",
|
|
|
|
// highlighting all macro references
|
|
|
|
R"cpp(
|
|
|
|
#ifndef $Macro[[name]]
|
|
|
|
#define $Macro[[name]]
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define $Macro[[test]]
|
|
|
|
#undef $Macro[[test]]
|
2019-09-25 06:17:55 +08:00
|
|
|
$InactiveCode[[]] #ifdef $Macro[[test]]
|
|
|
|
$InactiveCode[[]] #endif
|
2019-10-07 18:10:31 +08:00
|
|
|
|
2019-09-25 06:17:55 +08:00
|
|
|
$InactiveCode[[]] #if defined($Macro[[test]])
|
|
|
|
$InactiveCode[[]] #endif
|
2019-08-30 22:07:05 +08:00
|
|
|
)cpp",
|
[clangd] Highlight typedefs to template parameters as template parameters
Summary:
Template parameters were handled outside `addType`, this led to lack of highlightings for typedefs
to template types.
This was never desirable, we want to highlight our typedefs as their underlying type.
Note that typedefs to more complicated types, like pointers and references are still not highlighted.
Original patch by Johan Vikström.
Reviewers: hokein, jvikstrom
Reviewed By: hokein
Subscribers: nridge, javed.absar, kristof.beyls, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66516
llvm-svn: 371379
2019-09-09 17:37:17 +08:00
|
|
|
R"cpp(
|
2019-08-30 22:07:05 +08:00
|
|
|
struct $Class[[S]] {
|
2019-10-28 18:31:06 +08:00
|
|
|
float $Field[[Value]];
|
2019-08-30 22:07:05 +08:00
|
|
|
$Class[[S]] *$Field[[Next]];
|
|
|
|
};
|
|
|
|
$Class[[S]] $Variable[[Global]][2] = {$Class[[S]](), $Class[[S]]()};
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Function[[f]]($Class[[S]] $Parameter[[P]]) {
|
|
|
|
int $LocalVariable[[A]][2] = {1,2};
|
2019-08-30 22:07:05 +08:00
|
|
|
auto [$Variable[[B1]], $Variable[[B2]]] = $LocalVariable[[A]];
|
|
|
|
auto [$Variable[[G1]], $Variable[[G2]]] = $Variable[[Global]];
|
|
|
|
$Class[[auto]] [$Variable[[P1]], $Variable[[P2]]] = $Parameter[[P]];
|
|
|
|
// Highlights references to BindingDecls.
|
|
|
|
$Variable[[B1]]++;
|
|
|
|
}
|
[clangd] Highlight typedefs to template parameters as template parameters
Summary:
Template parameters were handled outside `addType`, this led to lack of highlightings for typedefs
to template types.
This was never desirable, we want to highlight our typedefs as their underlying type.
Note that typedefs to more complicated types, like pointers and references are still not highlighted.
Original patch by Johan Vikström.
Reviewers: hokein, jvikstrom
Reviewed By: hokein
Subscribers: nridge, javed.absar, kristof.beyls, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66516
llvm-svn: 371379
2019-09-09 17:37:17 +08:00
|
|
|
)cpp",
|
|
|
|
R"cpp(
|
|
|
|
template<class $TemplateParameter[[T]]>
|
|
|
|
class $Class[[A]] {
|
|
|
|
using $TemplateParameter[[TemplateParam1]] = $TemplateParameter[[T]];
|
|
|
|
typedef $TemplateParameter[[T]] $TemplateParameter[[TemplateParam2]];
|
2019-10-28 18:31:06 +08:00
|
|
|
using $Primitive[[IntType]] = int;
|
[clangd] Highlight typedefs to template parameters as template parameters
Summary:
Template parameters were handled outside `addType`, this led to lack of highlightings for typedefs
to template types.
This was never desirable, we want to highlight our typedefs as their underlying type.
Note that typedefs to more complicated types, like pointers and references are still not highlighted.
Original patch by Johan Vikström.
Reviewers: hokein, jvikstrom
Reviewed By: hokein
Subscribers: nridge, javed.absar, kristof.beyls, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66516
llvm-svn: 371379
2019-09-09 17:37:17 +08:00
|
|
|
|
2019-09-09 22:33:10 +08:00
|
|
|
using $Typedef[[Pointer]] = $TemplateParameter[[T]] *;
|
|
|
|
using $Typedef[[LVReference]] = $TemplateParameter[[T]] &;
|
|
|
|
using $Typedef[[RVReference]] = $TemplateParameter[[T]]&&;
|
|
|
|
using $Typedef[[Array]] = $TemplateParameter[[T]]*[3];
|
2019-10-28 18:31:06 +08:00
|
|
|
using $Typedef[[MemberPointer]] = int (A::*)(int);
|
2019-09-09 22:33:10 +08:00
|
|
|
|
|
|
|
// Use various previously defined typedefs in a function type.
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Method[[func]](
|
2019-09-09 22:33:10 +08:00
|
|
|
$Typedef[[Pointer]], $Typedef[[LVReference]], $Typedef[[RVReference]],
|
|
|
|
$Typedef[[Array]], $Typedef[[MemberPointer]]);
|
[clangd] Highlight typedefs to template parameters as template parameters
Summary:
Template parameters were handled outside `addType`, this led to lack of highlightings for typedefs
to template types.
This was never desirable, we want to highlight our typedefs as their underlying type.
Note that typedefs to more complicated types, like pointers and references are still not highlighted.
Original patch by Johan Vikström.
Reviewers: hokein, jvikstrom
Reviewed By: hokein
Subscribers: nridge, javed.absar, kristof.beyls, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66516
llvm-svn: 371379
2019-09-09 17:37:17 +08:00
|
|
|
};
|
2019-10-15 02:26:13 +08:00
|
|
|
)cpp",
|
|
|
|
R"cpp(
|
|
|
|
template <class $TemplateParameter[[T]]>
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Function[[phase1]]($TemplateParameter[[T]]);
|
2019-10-15 02:26:13 +08:00
|
|
|
template <class $TemplateParameter[[T]]>
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Function[[foo]]($TemplateParameter[[T]] $Parameter[[P]]) {
|
2019-10-15 02:26:13 +08:00
|
|
|
$Function[[phase1]]($Parameter[[P]]);
|
|
|
|
$DependentName[[phase2]]($Parameter[[P]]);
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
R"cpp(
|
|
|
|
class $Class[[A]] {
|
|
|
|
template <class $TemplateParameter[[T]]>
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Method[[bar]]($TemplateParameter[[T]]);
|
2019-10-15 02:26:13 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
template <class $TemplateParameter[[U]]>
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Function[[foo]]($TemplateParameter[[U]] $Parameter[[P]]) {
|
2019-10-15 02:26:13 +08:00
|
|
|
$Class[[A]]().$Method[[bar]]($Parameter[[P]]);
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
R"cpp(
|
|
|
|
struct $Class[[A]] {
|
|
|
|
template <class $TemplateParameter[[T]]>
|
2019-10-28 18:31:06 +08:00
|
|
|
static void $StaticMethod[[foo]]($TemplateParameter[[T]]);
|
2019-10-15 02:26:13 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
template <class $TemplateParameter[[T]]>
|
|
|
|
struct $Class[[B]] {
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Method[[bar]]() {
|
2019-10-15 02:26:13 +08:00
|
|
|
$Class[[A]]::$StaticMethod[[foo]]($TemplateParameter[[T]]());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
)cpp",
|
|
|
|
R"cpp(
|
|
|
|
template <class $TemplateParameter[[T]]>
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Function[[foo]](typename $TemplateParameter[[T]]::$DependentType[[Type]]
|
2019-10-15 02:26:13 +08:00
|
|
|
= $TemplateParameter[[T]]::$DependentName[[val]]);
|
|
|
|
)cpp",
|
|
|
|
R"cpp(
|
|
|
|
template <class $TemplateParameter[[T]]>
|
2019-10-28 18:31:06 +08:00
|
|
|
void $Function[[foo]]($TemplateParameter[[T]] $Parameter[[P]]) {
|
2019-10-15 02:26:13 +08:00
|
|
|
$Parameter[[P]].$DependentName[[Field]];
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
R"cpp(
|
|
|
|
template <class $TemplateParameter[[T]]>
|
|
|
|
class $Class[[A]] {
|
2019-10-28 18:31:06 +08:00
|
|
|
int $Method[[foo]]() {
|
2019-10-15 02:26:13 +08:00
|
|
|
return $TemplateParameter[[T]]::$DependentName[[Field]];
|
|
|
|
}
|
|
|
|
};
|
2019-10-28 20:42:20 +08:00
|
|
|
)cpp",
|
|
|
|
// Highlighting the using decl as the underlying using shadow decl.
|
|
|
|
R"cpp(
|
|
|
|
void $Function[[foo]]();
|
|
|
|
using ::$Function[[foo]];
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
)cpp",
|
|
|
|
// Highlighting of template template arguments.
|
|
|
|
R"cpp(
|
|
|
|
template <template <class> class $TemplateParameter[[TT]],
|
|
|
|
template <class> class ...$TemplateParameter[[TTs]]>
|
|
|
|
struct $Class[[Foo]] {
|
|
|
|
$Class[[Foo]]<$TemplateParameter[[TT]], $TemplateParameter[[TTs]]...>
|
|
|
|
*$Field[[t]];
|
|
|
|
}
|
2019-09-25 06:17:55 +08:00
|
|
|
)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
|
2019-12-06 03:27:23 +08:00
|
|
|
)cpp",
|
|
|
|
// Argument to 'sizeof...'
|
|
|
|
R"cpp(
|
|
|
|
template <typename... $TemplateParameter[[Elements]]>
|
|
|
|
struct $Class[[TupleSize]] {
|
2019-12-06 03:28:56 +08:00
|
|
|
static const int $StaticField[[size]] =
|
|
|
|
sizeof...($TemplateParameter[[Elements]]);
|
|
|
|
};
|
|
|
|
)cpp",
|
|
|
|
// More dependent types
|
|
|
|
R"cpp(
|
|
|
|
template <typename $TemplateParameter[[T]]>
|
|
|
|
struct $Class[[Waldo]] {
|
|
|
|
using $Typedef[[Location1]] = typename $TemplateParameter[[T]]
|
|
|
|
::$DependentType[[Resolver]]::$DependentType[[Location]];
|
|
|
|
using $Typedef[[Location2]] = typename $TemplateParameter[[T]]
|
|
|
|
::template $DependentType[[Resolver]]<$TemplateParameter[[T]]>
|
|
|
|
::$DependentType[[Location]];
|
|
|
|
using $Typedef[[Location3]] = typename $TemplateParameter[[T]]
|
|
|
|
::$DependentType[[Resolver]]
|
|
|
|
::template $DependentType[[Location]]<$TemplateParameter[[T]]>;
|
|
|
|
static const int $StaticField[[Value]] = $TemplateParameter[[T]]
|
|
|
|
::$DependentType[[Resolver]]::$DependentName[[Value]];
|
2019-12-06 03:27:23 +08:00
|
|
|
};
|
2019-07-05 21:06:03 +08:00
|
|
|
)cpp"};
|
2019-06-26 21:08:36 +08:00
|
|
|
for (const auto &TestCase : TestCases) {
|
|
|
|
checkHighlightings(TestCase);
|
|
|
|
}
|
2019-08-12 21:01:11 +08:00
|
|
|
|
|
|
|
checkHighlightings(R"cpp(
|
|
|
|
class $Class[[A]] {
|
|
|
|
#include "imp.h"
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
)cpp",
|
|
|
|
{{"imp.h", R"cpp(
|
|
|
|
int someMethod();
|
|
|
|
void otherMethod();
|
|
|
|
)cpp"}});
|
2019-08-20 00:27:49 +08:00
|
|
|
|
|
|
|
// A separate test for macros in headers.
|
|
|
|
checkHighlightings(R"cpp(
|
|
|
|
#include "imp.h"
|
2019-08-30 23:47:27 +08:00
|
|
|
$Macro[[DEFINE_Y]]
|
|
|
|
$Macro[[DXYZ_Y]](A);
|
2019-08-20 00:27:49 +08:00
|
|
|
)cpp",
|
|
|
|
{{"imp.h", R"cpp(
|
|
|
|
#define DXYZ(X) class X {};
|
|
|
|
#define DXYZ_Y(Y) DXYZ(x##Y)
|
|
|
|
#define DEFINE(X) int X;
|
|
|
|
#define DEFINE_Y DEFINE(Y)
|
|
|
|
)cpp"}});
|
2019-06-26 21:08:36 +08:00
|
|
|
}
|
|
|
|
|
2019-07-04 15:53:12 +08:00
|
|
|
TEST(SemanticHighlighting, GeneratesHighlightsWhenFileChange) {
|
2019-06-27 23:13:03 +08:00
|
|
|
class HighlightingsCounterDiagConsumer : public DiagnosticsConsumer {
|
|
|
|
public:
|
|
|
|
std::atomic<int> Count = {0};
|
|
|
|
|
|
|
|
void onDiagnosticsReady(PathRef, std::vector<Diag>) override {}
|
2019-08-26 16:38:45 +08:00
|
|
|
void onHighlightingsReady(
|
|
|
|
PathRef File, std::vector<HighlightingToken> Highlightings) override {
|
2019-06-27 23:13:03 +08:00
|
|
|
++Count;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
auto FooCpp = testPath("foo.cpp");
|
|
|
|
MockFSProvider FS;
|
|
|
|
FS.Files[FooCpp] = "";
|
|
|
|
|
|
|
|
MockCompilationDatabase MCD;
|
|
|
|
HighlightingsCounterDiagConsumer DiagConsumer;
|
|
|
|
ClangdServer Server(MCD, FS, DiagConsumer, ClangdServer::optsForTest());
|
|
|
|
Server.addDocument(FooCpp, "int a;");
|
|
|
|
ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for server";
|
|
|
|
ASSERT_EQ(DiagConsumer.Count, 1);
|
|
|
|
}
|
|
|
|
|
2019-07-04 15:53:12 +08:00
|
|
|
TEST(SemanticHighlighting, toSemanticHighlightingInformation) {
|
|
|
|
auto CreatePosition = [](int Line, int Character) -> Position {
|
|
|
|
Position Pos;
|
|
|
|
Pos.line = Line;
|
|
|
|
Pos.character = Character;
|
|
|
|
return Pos;
|
|
|
|
};
|
|
|
|
|
2019-08-01 16:08:44 +08:00
|
|
|
std::vector<LineHighlightings> Tokens{
|
|
|
|
{3,
|
|
|
|
{{HighlightingKind::Variable,
|
|
|
|
Range{CreatePosition(3, 8), CreatePosition(3, 12)}},
|
|
|
|
{HighlightingKind::Function,
|
2019-09-25 06:17:55 +08:00
|
|
|
Range{CreatePosition(3, 4), CreatePosition(3, 7)}}},
|
|
|
|
/* IsInactive = */ false},
|
2019-08-01 16:08:44 +08:00
|
|
|
{1,
|
|
|
|
{{HighlightingKind::Variable,
|
2019-09-25 06:17:55 +08:00
|
|
|
Range{CreatePosition(1, 1), CreatePosition(1, 5)}}},
|
|
|
|
/* IsInactive = */ true}};
|
2019-07-04 15:53:12 +08:00
|
|
|
std::vector<SemanticHighlightingInformation> ActualResults =
|
|
|
|
toSemanticHighlightingInformation(Tokens);
|
|
|
|
std::vector<SemanticHighlightingInformation> ExpectedResults = {
|
2019-08-28 03:39:11 +08:00
|
|
|
{3, "AAAACAAEAAAAAAAEAAMAAw=="}, {1, "AAAAAQAEAAA="}};
|
2019-07-04 15:53:12 +08:00
|
|
|
EXPECT_EQ(ActualResults, ExpectedResults);
|
|
|
|
}
|
|
|
|
|
2019-08-01 16:08:44 +08:00
|
|
|
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]]
|
|
|
|
)",
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-08-26 16:38:45 +08:00
|
|
|
TEST(SemanticHighlighting, DiffBeyondTheEndOfFile) {
|
|
|
|
llvm::StringRef OldCode =
|
|
|
|
R"(
|
|
|
|
$Class[[A]]
|
|
|
|
$Variable[[A]]
|
|
|
|
$Class[[A]]
|
|
|
|
$Variable[[A]]
|
|
|
|
)";
|
|
|
|
llvm::StringRef NewCode =
|
|
|
|
R"(
|
|
|
|
$Class[[A]] // line 1
|
|
|
|
$Variable[[A]] // line 2
|
|
|
|
)";
|
|
|
|
|
|
|
|
Annotations OldTest(OldCode);
|
|
|
|
Annotations NewTest(NewCode);
|
|
|
|
std::vector<HighlightingToken> OldTokens = getExpectedTokens(OldTest);
|
|
|
|
std::vector<HighlightingToken> NewTokens = getExpectedTokens(NewTest);
|
|
|
|
|
|
|
|
auto ActualDiff = diffHighlightings(NewTokens, OldTokens);
|
|
|
|
EXPECT_THAT(ActualDiff,
|
|
|
|
testing::UnorderedElementsAre(
|
|
|
|
testing::AllOf(LineNumber(3), EmptyHighlightings()),
|
|
|
|
testing::AllOf(LineNumber(4), EmptyHighlightings())));
|
|
|
|
}
|
|
|
|
|
2019-06-26 21:08:36 +08:00
|
|
|
} // namespace
|
|
|
|
} // namespace clangd
|
2019-10-13 21:15:27 +08:00
|
|
|
} // namespace clang
|