From a68ec8ae24b38f4327fa02a1b6a241dea0a320aa Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 2 Nov 2020 17:01:26 +0100 Subject: [PATCH] clangbackend: Work around wrong cursor info from libclang Alias type declarations of in-place struct definitions are not reliably getting their cursor exposed, so the surrounding context is reported instead, which causes the wrong lexical parent to be deduced. To the user, this manifests itself as a wrong hierarchy being displayed in the outline. We try to detect this condition and correct it manually. Task-number: QTCREATORBUG-24875 Change-Id: Ib4e177efa9148697eddde986a91fdd5d7b272d76 Reviewed-by: Christian Stenger --- src/tools/clangbackend/source/token.cpp | 33 +++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/tools/clangbackend/source/token.cpp b/src/tools/clangbackend/source/token.cpp index f69497b9899..8eee278ac62 100644 --- a/src/tools/clangbackend/source/token.cpp +++ b/src/tools/clangbackend/source/token.cpp @@ -90,8 +90,37 @@ std::vector Tokens::annotate() const std::vector cxCursors; cxCursors.resize(m_tokens.size()); - clang_annotateTokens(m_cxTranslationUnit, m_tokens.front().cx(), - static_cast(m_tokens.size()), cxCursors.data()); + + clang_annotateTokens(m_cxTranslationUnit, m_tokens.front().cx(), m_tokens.size(), cxCursors.data()); + + // The alias declaration "using S = struct {}" results in libclang reporting the type + // of the surrounding scope (e.g. a namespace or class) for the cursor corresponding to + // the token "S" (QTCREATORBUG-24875). We need to correct this manually. + // TODO: Investigate whether we can fix this in libclang itself. + for (int i = 1; i < int(m_tokens.size()) - 2; ++i) { + const Token &tok = m_tokens.at(i); + const Token &prevTok = m_tokens.at(i - 1); + const Token &nextTok = m_tokens.at(i + 1); + if (tok.kind() == CXToken_Identifier + && prevTok.kind() == CXToken_Keyword + && prevTok.spelling() == "using" + && nextTok.spelling() == "=" + && cxCursors.at(i).kind != CXCursor_TypeAliasDecl) { + // If the surrounding scope is a namespace, the correct type is reported for the token + // after the identifier, i.e. the "=" symbol. Otherwise, it's not reported at all, + // and we have to use the cursor after that, which should be the aliased type. + // Note that we cannot use the next cursors in the cxCursors array, because + // clang_annotateTokens() reports the surrounding scope for all of these. + CXCursor nextCursor = clang_getCursor(m_cxTranslationUnit, clang_getTokenLocation( + m_cxTranslationUnit, *nextTok.cx())); + if (nextCursor.kind != CXCursor_TypeAliasDecl) { + nextCursor = clang_getCursor(m_cxTranslationUnit, clang_getTokenLocation( + m_cxTranslationUnit, *m_tokens.at(i + 2).cx())); + } + cxCursors[i] = nextCursor; + } + } + cursors.reserve(cxCursors.size()); for (const CXCursor &cxCursor : cxCursors) cursors.emplace_back(cxCursor);