From 8ad9c0111ccfbac9a06513fa5c9baa6dc4e48970 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 25 Nov 2020 11:12:30 +0100 Subject: [PATCH] clangbackend: Another workaround for libclang cursor weirdness Sometimes, clang_getCursor() erroneously returns an invalid cursor, in which case we may be able to retrieve the real one via clang_annotateTokens(). This is basically the reverse of the issue we recently had, where we had to call clang_getCursor() to get information missing from clang_annotateTokens(). Fixes: QTCREATORBUG-21194 Change-Id: Ie8c4767bca03bd1b27e3ef1f906378fc1d436b90 Reviewed-by: Christian Stenger --- .../clangbackend/source/clangfollowsymbol.cpp | 15 +------------- .../source/clangtooltipinfocollector.cpp | 20 +++++++++++++++++-- src/tools/clangbackend/source/token.cpp | 13 ++++++++++++ src/tools/clangbackend/source/token.h | 4 ++++ 4 files changed, 36 insertions(+), 16 deletions(-) diff --git a/src/tools/clangbackend/source/clangfollowsymbol.cpp b/src/tools/clangbackend/source/clangfollowsymbol.cpp index c38d397eeb1..e2c619ef3fc 100644 --- a/src/tools/clangbackend/source/clangfollowsymbol.cpp +++ b/src/tools/clangbackend/source/clangfollowsymbol.cpp @@ -71,19 +71,6 @@ static SourceRangeContainer extractMatchingTokenRange(const Cursor &cursor, return SourceRangeContainer(); } -static int getTokenIndex(CXTranslationUnit tu, const Tokens &tokens, uint line, uint column) -{ - int tokenIndex = -1; - for (int i = tokens.size() - 1; i >= 0; --i) { - const SourceRange range(tu, tokens[i].extent()); - if (range.contains(line, column)) { - tokenIndex = i; - break; - } - } - return tokenIndex; -} - FollowSymbolResult FollowSymbol::followSymbol(CXTranslationUnit tu, const Cursor &fullCursor, uint line, @@ -100,7 +87,7 @@ FollowSymbolResult FollowSymbol::followSymbol(CXTranslationUnit tu, return SourceRangeContainer(); std::vector cursors = tokens.annotate(); - int tokenIndex = getTokenIndex(tu, tokens, line, column); + const int tokenIndex = tokens.getTokenIndex(tu, line, column); QTC_ASSERT(tokenIndex >= 0, return SourceRangeContainer()); const Utf8String tokenSpelling = tokens[tokenIndex].spelling(); diff --git a/src/tools/clangbackend/source/clangtooltipinfocollector.cpp b/src/tools/clangbackend/source/clangtooltipinfocollector.cpp index af28c7a5a9f..06bc98203b7 100644 --- a/src/tools/clangbackend/source/clangtooltipinfocollector.cpp +++ b/src/tools/clangbackend/source/clangtooltipinfocollector.cpp @@ -512,9 +512,25 @@ Utf8String ToolTipInfoCollector::lineRange(const Utf8String &filePath, ToolTipInfo ToolTipInfoCollector::collect(uint line, uint column) const { - const Cursor cursor = clang_getCursor(m_cxTranslationUnit, toCXSourceLocation(line, column)); + Cursor cursor = clang_getCursor(m_cxTranslationUnit, toCXSourceLocation(line, column)); + if (!cursor.isValid()) { // QTCREATORBUG-21194 + Tokens tokens(Cursor(clang_getTranslationUnitCursor(m_cxTranslationUnit)).sourceRange()); + if (!tokens.size()) + return {}; + + // TODO: Only annotate the tokens up until the location we are interested in? + // Same goes for FollowSymbol. + const std::vector cursors = tokens.annotate(); + + const int tokenIndex = tokens.getTokenIndex(m_cxTranslationUnit, line, column); + QTC_ASSERT(tokenIndex >= 0, return {}); + const Utf8String tokenSpelling = tokens[tokenIndex].spelling(); + if (tokenSpelling.isEmpty()) + return {}; + cursor = cursors[tokenIndex]; + } if (!cursor.isValid()) - return ToolTipInfo(); // E.g. cursor on ifdeffed out range + return {}; const Cursor referenced = referencedCursor(cursor); QTC_CHECK(referenced.isValid()); diff --git a/src/tools/clangbackend/source/token.cpp b/src/tools/clangbackend/source/token.cpp index 1bc773e9d98..5fa31528ecc 100644 --- a/src/tools/clangbackend/source/token.cpp +++ b/src/tools/clangbackend/source/token.cpp @@ -202,6 +202,19 @@ std::vector::iterator Tokens::end() return m_tokens.end(); } +int Tokens::getTokenIndex(CXTranslationUnit tu, uint line, uint column) const +{ + int tokenIndex = -1; + for (int i = size() - 1; i >= 0; --i) { + const SourceRange range(tu, (*this)[i].extent()); + if (range.contains(line, column)) { + tokenIndex = i; + break; + } + } + return tokenIndex; +} + Tokens::~Tokens() { if (m_tokens.empty()) diff --git a/src/tools/clangbackend/source/token.h b/src/tools/clangbackend/source/token.h index ecfb42f6f45..46635c40019 100644 --- a/src/tools/clangbackend/source/token.h +++ b/src/tools/clangbackend/source/token.h @@ -25,6 +25,8 @@ #pragma once +#include + #include #include @@ -81,6 +83,8 @@ public: std::vector::iterator begin(); std::vector::iterator end(); + int getTokenIndex(CXTranslationUnit tu, uint line, uint column) const; + CXTranslationUnit tu() const { return m_cxTranslationUnit; } private: CXTranslationUnit m_cxTranslationUnit;