ClangCodeModel: Make use of new semantic token in clangd

... for angle brackets.
See https://reviews.llvm.org/D139926.

Change-Id: I17be843005e290a8aec91573d9ed4bd0727e2dab
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2022-07-19 15:00:07 +02:00
parent df3e7e5bdd
commit be9a01252d
2 changed files with 125 additions and 120 deletions

View File

@@ -360,6 +360,17 @@ void doSemanticHighlighting(
result.kind = CppEditor::SemanticHighlighter::TernaryElse;
}
return result;
} else if (token.type == "bracket") {
styles.mainStyle = C_PUNCTUATION;
HighlightingResult result(token.line, token.column, token.length, styles);
const int pos = Utils::Text::positionInText(&doc, token.line, token.column);
QTC_ASSERT(pos >= 0 || pos < docContents.size(), return HighlightingResult());
const char symbol = docContents.at(pos).toLatin1();
QTC_ASSERT(symbol == '<' || symbol == '>', return HighlightingResult());
result.kind = symbol == '<'
? CppEditor::SemanticHighlighter::AngleBracketOpen
: CppEditor::SemanticHighlighter::AngleBracketClose;
return result;
}
if (token.modifiers.contains(QLatin1String("declaration")))
styles.mixinStyles.push_back(C_DECLARATION);
@@ -598,6 +609,7 @@ void ExtraHighlightingResultsCollector::collectFromNode(const ClangdAstNode &nod
insertResult(node, C_PRIMITIVE_TYPE);
return;
}
if (m_clangdVersion < 16 && node.role() == "attribute"
&& (node.kind() == "Override" || node.kind() == "Final")) {
insertResult(node, C_KEYWORD);
@@ -655,125 +667,126 @@ void ExtraHighlightingResultsCollector::collectFromNode(const ClangdAstNode &nod
return;
}
if (isDeclaration && (node.kind() == "FunctionTemplate"
|| node.kind() == "ClassTemplate")) {
// The child nodes are the template parameters and and the function or class.
// The opening angle bracket is before the first child node, the closing angle
// bracket is before the function child node and after the last param node.
const QString classOrFunctionKind = QLatin1String(node.kind() == "FunctionTemplate"
? "Function" : "CXXRecord");
const auto functionOrClassIt = std::find_if(children.begin(), children.end(),
[&classOrFunctionKind](const ClangdAstNode &n) {
return n.role() == "declaration" && n.kind() == classOrFunctionKind;
});
if (functionOrClassIt == children.end() || functionOrClassIt == children.begin())
if (m_clangdVersion < 17) {
if (isDeclaration && (node.kind() == "FunctionTemplate" || node.kind() == "ClassTemplate")) {
// The child nodes are the template parameters and and the function or class.
// The opening angle bracket is before the first child node, the closing angle
// bracket is before the function child node and after the last param node.
const QString classOrFunctionKind = QLatin1String(node.kind() == "FunctionTemplate"
? "Function" : "CXXRecord");
const auto functionOrClassIt = std::find_if(children.begin(), children.end(),
[&classOrFunctionKind](const ClangdAstNode &n) {
return n.role() == "declaration" && n.kind() == classOrFunctionKind;
});
if (functionOrClassIt == children.end() || functionOrClassIt == children.begin())
return;
const int firstTemplateParamStartPos = posForNodeStart(children.first());
const int lastTemplateParamEndPos = posForNodeEnd(*(functionOrClassIt - 1));
const int functionOrClassStartPos = posForNodeStart(*functionOrClassIt);
insertAngleBracketInfo(nodeStartPos, firstTemplateParamStartPos,
lastTemplateParamEndPos, functionOrClassStartPos);
return;
const int firstTemplateParamStartPos = posForNodeStart(children.first());
const int lastTemplateParamEndPos = posForNodeEnd(*(functionOrClassIt - 1));
const int functionOrClassStartPos = posForNodeStart(*functionOrClassIt);
insertAngleBracketInfo(nodeStartPos, firstTemplateParamStartPos,
lastTemplateParamEndPos, functionOrClassStartPos);
return;
}
const auto isTemplateParamDecl = [](const ClangdAstNode &node) {
return node.isTemplateParameterDeclaration();
};
if (isDeclaration && node.kind() == "TypeAliasTemplate") {
// Children are one node of type TypeAlias and the template parameters.
// The opening angle bracket is before the first parameter and the closing
// angle bracket is after the last parameter.
// The TypeAlias node seems to appear first in the AST, even though lexically
// is comes after the parameters. We don't rely on the order here.
// Note that there is a second pair of angle brackets. That one is part of
// a TemplateSpecialization, which is handled further below.
const auto firstTemplateParam = std::find_if(children.begin(), children.end(),
isTemplateParamDecl);
if (firstTemplateParam == children.end())
return;
const auto lastTemplateParam = std::find_if(children.rbegin(), children.rend(),
isTemplateParamDecl);
QTC_ASSERT(lastTemplateParam != children.rend(), return);
const auto typeAlias = std::find_if(children.begin(), children.end(),
[](const ClangdAstNode &n) { return n.kind() == "TypeAlias"; });
if (typeAlias == children.end())
return;
const int firstTemplateParamStartPos = posForNodeStart(*firstTemplateParam);
const int lastTemplateParamEndPos = posForNodeEnd(*lastTemplateParam);
const int searchEndPos = posForNodeStart(*typeAlias);
insertAngleBracketInfo(nodeStartPos, firstTemplateParamStartPos,
lastTemplateParamEndPos, searchEndPos);
return;
}
if (isDeclaration && node.kind() == "ClassTemplateSpecialization") {
// There is one child of kind TemplateSpecialization. The first pair
// of angle brackets comes before that.
if (children.size() == 1) {
const int childNodePos = posForNodeStart(children.first());
insertAngleBracketInfo(nodeStartPos, childNodePos, nodeStartPos, childNodePos);
}
return;
}
if (isDeclaration && node.kind() == "TemplateTemplateParm") {
// The child nodes are template arguments and template parameters.
// Arguments seem to appear before parameters in the AST, even though they
// come after them in the source code. We don't rely on the order here.
const auto firstTemplateParam = std::find_if(children.begin(), children.end(),
isTemplateParamDecl);
if (firstTemplateParam == children.end())
const auto isTemplateParamDecl = [](const ClangdAstNode &node) {
return node.isTemplateParameterDeclaration();
};
if (isDeclaration && node.kind() == "TypeAliasTemplate") {
// Children are one node of type TypeAlias and the template parameters.
// The opening angle bracket is before the first parameter and the closing
// angle bracket is after the last parameter.
// The TypeAlias node seems to appear first in the AST, even though lexically
// is comes after the parameters. We don't rely on the order here.
// Note that there is a second pair of angle brackets. That one is part of
// a TemplateSpecialization, which is handled further below.
const auto firstTemplateParam = std::find_if(children.begin(), children.end(),
isTemplateParamDecl);
if (firstTemplateParam == children.end())
return;
const auto lastTemplateParam = std::find_if(children.rbegin(), children.rend(),
isTemplateParamDecl);
QTC_ASSERT(lastTemplateParam != children.rend(), return);
const auto typeAlias = std::find_if(children.begin(), children.end(),
[](const ClangdAstNode &n) { return n.kind() == "TypeAlias"; });
if (typeAlias == children.end())
return;
const int firstTemplateParamStartPos = posForNodeStart(*firstTemplateParam);
const int lastTemplateParamEndPos = posForNodeEnd(*lastTemplateParam);
const int searchEndPos = posForNodeStart(*typeAlias);
insertAngleBracketInfo(nodeStartPos, firstTemplateParamStartPos,
lastTemplateParamEndPos, searchEndPos);
return;
const auto lastTemplateParam = std::find_if(children.rbegin(), children.rend(),
isTemplateParamDecl);
QTC_ASSERT(lastTemplateParam != children.rend(), return);
const auto templateArg = std::find_if(children.begin(), children.end(),
[](const ClangdAstNode &n) { return n.role() == "template argument"; });
const int firstTemplateParamStartPos = posForNodeStart(*firstTemplateParam);
const int lastTemplateParamEndPos = posForNodeEnd(*lastTemplateParam);
const int searchEndPos = templateArg == children.end()
? nodeEndPos : posForNodeStart(*templateArg);
insertAngleBracketInfo(nodeStartPos, firstTemplateParamStartPos,
lastTemplateParamEndPos, searchEndPos);
return;
}
// {static,dynamic,reinterpret}_cast<>().
if (isExpression && node.kind().startsWith("CXX") && node.kind().endsWith("Cast")) {
// First child is type, second child is expression.
// The opening angle bracket is before the first child, the closing angle bracket
// is between the two children.
if (children.size() == 2) {
insertAngleBracketInfo(nodeStartPos, posForNodeStart(children.first()),
posForNodeEnd(children.first()),
posForNodeStart(children.last()));
}
return;
}
if (node.kind() == "TemplateSpecialization") {
// First comes the template type, then the template arguments.
// The opening angle bracket is before the first template argument,
// the closing angle bracket is after the last template argument.
// The first child node has no range, so we start searching at the parent node.
if (children.size() >= 2) {
int searchStart2 = posForNodeEnd(children.last());
int searchEnd2 = nodeEndPos;
// There is a weird off-by-one error on the clang side: If there is a
// nested template instantiation *and* there is no space between
// the closing angle brackets, then the inner TemplateSpecialization node's range
// will extend one character too far, covering the outer's closing angle bracket.
// This is what we are correcting for here.
// This issue is tracked at https://github.com/clangd/clangd/issues/871.
if (searchStart2 == searchEnd2)
--searchStart2;
insertAngleBracketInfo(nodeStartPos, posForNodeStart(children.at(1)),
searchStart2, searchEnd2);
if (isDeclaration && node.kind() == "ClassTemplateSpecialization") {
// There is one child of kind TemplateSpecialization. The first pair
// of angle brackets comes before that.
if (children.size() == 1) {
const int childNodePos = posForNodeStart(children.first());
insertAngleBracketInfo(nodeStartPos, childNodePos, nodeStartPos, childNodePos);
}
return;
}
if (isDeclaration && node.kind() == "TemplateTemplateParm") {
// The child nodes are template arguments and template parameters.
// Arguments seem to appear before parameters in the AST, even though they
// come after them in the source code. We don't rely on the order here.
const auto firstTemplateParam = std::find_if(children.begin(), children.end(),
isTemplateParamDecl);
if (firstTemplateParam == children.end())
return;
const auto lastTemplateParam = std::find_if(children.rbegin(), children.rend(),
isTemplateParamDecl);
QTC_ASSERT(lastTemplateParam != children.rend(), return);
const auto templateArg = std::find_if(children.begin(), children.end(),
[](const ClangdAstNode &n) { return n.role() == "template argument"; });
const int firstTemplateParamStartPos = posForNodeStart(*firstTemplateParam);
const int lastTemplateParamEndPos = posForNodeEnd(*lastTemplateParam);
const int searchEndPos = templateArg == children.end()
? nodeEndPos : posForNodeStart(*templateArg);
insertAngleBracketInfo(nodeStartPos, firstTemplateParamStartPos,
lastTemplateParamEndPos, searchEndPos);
return;
}
// {static,dynamic,reinterpret}_cast<>().
if (isExpression && node.kind().startsWith("CXX") && node.kind().endsWith("Cast")) {
// First child is type, second child is expression.
// The opening angle bracket is before the first child, the closing angle bracket
// is between the two children.
if (children.size() == 2) {
insertAngleBracketInfo(nodeStartPos, posForNodeStart(children.first()),
posForNodeEnd(children.first()),
posForNodeStart(children.last()));
}
return;
}
if (node.kind() == "TemplateSpecialization") {
// First comes the template type, then the template arguments.
// The opening angle bracket is before the first template argument,
// the closing angle bracket is after the last template argument.
// The first child node has no range, so we start searching at the parent node.
if (children.size() >= 2) {
int searchStart2 = posForNodeEnd(children.last());
int searchEnd2 = nodeEndPos;
// There is a weird off-by-one error on the clang side: If there is a
// nested template instantiation *and* there is no space between
// the closing angle brackets, then the inner TemplateSpecialization node's range
// will extend one character too far, covering the outer's closing angle bracket.
// This is what we are correcting for here.
// This issue is tracked at https://github.com/clangd/clangd/issues/871.
if (searchStart2 == searchEnd2)
--searchStart2;
insertAngleBracketInfo(nodeStartPos, posForNodeStart(children.at(1)),
searchStart2, searchEnd2);
}
return;
}
return;
}
if (!isExpression && !isDeclaration)