Clang: Fix local references for operator arguments

Workaround for wrong cursor annotated by Clang.

Use clang_getCursor in case of the variable used as
operator argument to get the proper cursor.

Task-number: QTCREATORBUG-20966
Change-Id: Idb195bffc2296f3fae27595cf9c43c9e6b2c5cd0
Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
Ivan Donchevskii
2018-08-21 10:23:12 +02:00
parent 8d0391a4f9
commit 8c21a7a396
3 changed files with 74 additions and 4 deletions

View File

@@ -43,8 +43,15 @@ namespace {
class ReferencedCursor
{
public:
static ReferencedCursor find(const Cursor &cursor)
static ReferencedCursor find(const Cursor &cursor, const CXToken &token)
{
if (cursor.spelling().startsWith("operator")
&& clang_getTokenKind(token) == CXToken_Identifier) {
// We are actually inside operator, use clang_getCursor to return a proper cursor instead.
return find(clang_getCursor(cursor.cxTranslationUnit(),
clang_getTokenLocation(cursor.cxTranslationUnit(), token)),
token);
}
// Query the referenced cursor directly instead of first testing with cursor.isReference().
// cursor.isReference() reports false for e.g. CXCursor_DeclRefExpr or CXCursor_CallExpr
// although it returns a valid cursor.
@@ -194,7 +201,7 @@ bool ReferencesCollector::checkToken(unsigned index, const Utf8String &identifie
return false;
{ // For debugging only
// const SourceRange range = clang_getTokenExtent(m_cxTranslationUnit, token);
// const SourceRange range{m_cxTranslationUnit, clang_getTokenExtent(m_cxTranslationUnit, token)};
// const uint line = range.start().line();
// const ClangString spellingCs = clang_getTokenSpelling(m_cxTranslationUnit, token);
// const Utf8String spelling = spellingCs;
@@ -202,7 +209,7 @@ bool ReferencesCollector::checkToken(unsigned index, const Utf8String &identifie
}
const Cursor currentCursor(m_cxCursors[static_cast<int>(index)]);
const ReferencedCursor candidate = ReferencedCursor::find(currentCursor);
const ReferencedCursor candidate = ReferencedCursor::find(currentCursor, token);
return candidate.usr() == usr;
}
@@ -217,7 +224,7 @@ ReferencesResult ReferencesCollector::collect(uint line, uint column, bool local
const Cursor cursorFromUser = m_cxCursors[static_cast<int>(index)];
const ReferencedCursor refCursor = ReferencedCursor::find(cursorFromUser);
const ReferencedCursor refCursor = ReferencedCursor::find(cursorFromUser, m_cxTokens[index]);
const Utf8String usr = refCursor.usr();
if (usr.isEmpty())
return result;

View File

@@ -463,6 +463,54 @@ TEST_F(ReferencesCollector, ArgumentToFunctionLikeMacro)
ASSERT_THAT(actual, expected);
}
TEST_F(ReferencesCollector, OverloadedBraceOperatorArgument)
{
const ReferencesResult expected {
true,
{createSourceRange(171, 7, 1),
createSourceRange(172, 7, 1),
createSourceRange(172, 12, 1),
createSourceRange(173, 7, 1),
createSourceRange(173, 10, 1)},
};
const ReferencesResult actual = getReferences(172, 7);
ASSERT_THAT(actual, expected);
}
TEST_F(ReferencesCollector, OverloadedParenOperatorSecondArgument)
{
const ReferencesResult expected {
true,
{createSourceRange(171, 7, 1),
createSourceRange(172, 7, 1),
createSourceRange(172, 12, 1),
createSourceRange(173, 7, 1),
createSourceRange(173, 10, 1)},
};
const ReferencesResult actual = getReferences(173, 10);
ASSERT_THAT(actual, expected);
}
TEST_F(ReferencesCollector, OverloadedOperatorsArgumentsFromOutside)
{
const ReferencesResult expected {
true,
{createSourceRange(171, 7, 1),
createSourceRange(172, 7, 1),
createSourceRange(172, 12, 1),
createSourceRange(173, 7, 1),
createSourceRange(173, 10, 1)},
};
const ReferencesResult actual = getReferences(171, 7);
ASSERT_THAT(actual, expected);
}
std::unique_ptr<const Data> ReferencesCollector::data;
void ReferencesCollector::SetUpTestCase()

View File

@@ -157,3 +157,18 @@ int functionLikeMacro(int foo)
{
return BAR(foo);
}
template<class T>
class Container
{
public:
T &operator[](int); T &operator()(int, int);
};
int testOperator() {
Container<int> vec;
int n = 10;
vec[n] = n * 100;
vec(n, n) = 100;
}