forked from qt-creator/qt-creator
ClangCodeModel: Do not traverse the AST in the semantic highlighter
... with clangd >= 17. We do not need to look at AST nodes anymore; everything comes from the server. Change-Id: I46eb91f26515e31b752020edbc32f1b23c1d79c7 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -1468,7 +1468,10 @@ void ClangdClient::Private::handleSemanticTokens(TextDocument *doc,
|
|||||||
data.highlighter->setHighlightingRunner(runner);
|
data.highlighter->setHighlightingRunner(runner);
|
||||||
data.highlighter->run();
|
data.highlighter->run();
|
||||||
};
|
};
|
||||||
getAndHandleAst(doc, astHandler, AstCallbackMode::SyncIfPossible);
|
if (q->versionNumber().majorVersion() >= 17)
|
||||||
|
astHandler({}, {});
|
||||||
|
else
|
||||||
|
getAndHandleAst(doc, astHandler, AstCallbackMode::SyncIfPossible);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<QList<CodeAction> > ClangdDiagnostic::codeActions() const
|
std::optional<QList<CodeAction> > ClangdDiagnostic::codeActions() const
|
||||||
|
@@ -461,6 +461,7 @@ void ExtraHighlightingResultsCollector::collect()
|
|||||||
|
|
||||||
if (!m_ast.isValid())
|
if (!m_ast.isValid())
|
||||||
return;
|
return;
|
||||||
|
QTC_ASSERT(m_clangdVersion < 17, return);
|
||||||
visitNode(m_ast);
|
visitNode(m_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -656,126 +657,124 @@ void ExtraHighlightingResultsCollector::collectFromNode(const ClangdAstNode &nod
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_clangdVersion < 17) {
|
if (isDeclaration && (node.kind() == "FunctionTemplate" || node.kind() == "ClassTemplate")) {
|
||||||
if (isDeclaration && (node.kind() == "FunctionTemplate" || node.kind() == "ClassTemplate")) {
|
// The child nodes are the template parameters and and the function or class.
|
||||||
// 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
|
||||||
// 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.
|
||||||
// bracket is before the function child node and after the last param node.
|
const QString classOrFunctionKind = QLatin1String(node.kind() == "FunctionTemplate"
|
||||||
const QString classOrFunctionKind = QLatin1String(node.kind() == "FunctionTemplate"
|
? "Function" : "CXXRecord");
|
||||||
? "Function" : "CXXRecord");
|
const auto functionOrClassIt = std::find_if(children.begin(), children.end(),
|
||||||
const auto functionOrClassIt = std::find_if(children.begin(), children.end(),
|
[&classOrFunctionKind](const ClangdAstNode &n) {
|
||||||
[&classOrFunctionKind](const ClangdAstNode &n) {
|
return n.role() == "declaration" && n.kind() == classOrFunctionKind;
|
||||||
return n.role() == "declaration" && n.kind() == classOrFunctionKind;
|
});
|
||||||
});
|
if (functionOrClassIt == children.end() || functionOrClassIt == children.begin())
|
||||||
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;
|
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) {
|
const auto isTemplateParamDecl = [](const ClangdAstNode &node) {
|
||||||
return node.isTemplateParameterDeclaration();
|
return node.isTemplateParameterDeclaration();
|
||||||
};
|
};
|
||||||
if (isDeclaration && node.kind() == "TypeAliasTemplate") {
|
if (isDeclaration && node.kind() == "TypeAliasTemplate") {
|
||||||
// Children are one node of type TypeAlias and the template parameters.
|
// Children are one node of type TypeAlias and the template parameters.
|
||||||
// The opening angle bracket is before the first parameter and the closing
|
// The opening angle bracket is before the first parameter and the closing
|
||||||
// angle bracket is after the last parameter.
|
// angle bracket is after the last parameter.
|
||||||
// The TypeAlias node seems to appear first in the AST, even though lexically
|
// 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.
|
// 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
|
// Note that there is a second pair of angle brackets. That one is part of
|
||||||
// a TemplateSpecialization, which is handled further below.
|
// a TemplateSpecialization, which is handled further below.
|
||||||
const auto firstTemplateParam = std::find_if(children.begin(), children.end(),
|
const auto firstTemplateParam = std::find_if(children.begin(), children.end(),
|
||||||
isTemplateParamDecl);
|
isTemplateParamDecl);
|
||||||
if (firstTemplateParam == children.end())
|
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;
|
return;
|
||||||
}
|
const auto lastTemplateParam = std::find_if(children.rbegin(), children.rend(),
|
||||||
|
isTemplateParamDecl);
|
||||||
if (isDeclaration && node.kind() == "ClassTemplateSpecialization") {
|
QTC_ASSERT(lastTemplateParam != children.rend(), return);
|
||||||
// There is one child of kind TemplateSpecialization. The first pair
|
const auto typeAlias = std::find_if(children.begin(), children.end(),
|
||||||
// of angle brackets comes before that.
|
[](const ClangdAstNode &n) { return n.kind() == "TypeAlias"; });
|
||||||
if (children.size() == 1) {
|
if (typeAlias == children.end())
|
||||||
const int childNodePos = posForNodeStart(children.first());
|
|
||||||
insertAngleBracketInfo(nodeStartPos, childNodePos, nodeStartPos, childNodePos);
|
|
||||||
}
|
|
||||||
return;
|
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") {
|
if (isDeclaration && node.kind() == "TemplateTemplateParm") {
|
||||||
// The child nodes are template arguments and template parameters.
|
// The child nodes are template arguments and template parameters.
|
||||||
// Arguments seem to appear before parameters in the AST, even though they
|
// 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.
|
// 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(),
|
const auto firstTemplateParam = std::find_if(children.begin(), children.end(),
|
||||||
isTemplateParamDecl);
|
isTemplateParamDecl);
|
||||||
if (firstTemplateParam == children.end())
|
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;
|
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"; });
|
||||||
|
|
||||||
// {static,dynamic,reinterpret}_cast<>().
|
const int firstTemplateParamStartPos = posForNodeStart(*firstTemplateParam);
|
||||||
if (isExpression && node.kind().startsWith("CXX") && node.kind().endsWith("Cast")) {
|
const int lastTemplateParamEndPos = posForNodeEnd(*lastTemplateParam);
|
||||||
// First child is type, second child is expression.
|
const int searchEndPos = templateArg == children.end()
|
||||||
// The opening angle bracket is before the first child, the closing angle bracket
|
? nodeEndPos : posForNodeStart(*templateArg);
|
||||||
// is between the two children.
|
insertAngleBracketInfo(nodeStartPos, firstTemplateParamStartPos,
|
||||||
if (children.size() == 2) {
|
lastTemplateParamEndPos, searchEndPos);
|
||||||
insertAngleBracketInfo(nodeStartPos, posForNodeStart(children.first()),
|
return;
|
||||||
posForNodeEnd(children.first()),
|
}
|
||||||
posForNodeStart(children.last()));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.kind() == "TemplateSpecialization") {
|
// {static,dynamic,reinterpret}_cast<>().
|
||||||
// First comes the template type, then the template arguments.
|
if (isExpression && node.kind().startsWith("CXX") && node.kind().endsWith("Cast")) {
|
||||||
// The opening angle bracket is before the first template argument,
|
// First child is type, second child is expression.
|
||||||
// the closing angle bracket is after the last template argument.
|
// The opening angle bracket is before the first child, the closing angle bracket
|
||||||
// The first child node has no range, so we start searching at the parent node.
|
// is between the two children.
|
||||||
if (children.size() >= 2) {
|
if (children.size() == 2) {
|
||||||
int searchStart2 = posForNodeEnd(children.last());
|
insertAngleBracketInfo(nodeStartPos, posForNodeStart(children.first()),
|
||||||
int searchEnd2 = nodeEndPos;
|
posForNodeEnd(children.first()),
|
||||||
|
posForNodeStart(children.last()));
|
||||||
// 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 (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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isExpression && !isDeclaration)
|
if (!isExpression && !isDeclaration)
|
||||||
|
Reference in New Issue
Block a user