From 74177a559e16c5c260d8934a7f5a7a959e4565b3 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 15 Feb 2021 12:27:23 +0100 Subject: [PATCH] clangbackend: Work around libclang cursor bug ... involving accessing the member of a nested anonymous union from within the surrounding class. libclang reports a CXCursor_CXXThisExpr for this location instead of a CXCursor_MemberRefExpr. However, the latter is still locatable in the AST, so we can correct this. Fixes: QTCREATORBUG-25342 Change-Id: I1eba13d5153205a52b3689d8ad52493a56b76c07 Reviewed-by: Fabian Kosmale --- src/tools/clangbackend/source/clangfollowsymbol.cpp | 10 ++++++++++ tests/unit/unittest/clangfollowsymbol-test.cpp | 7 +++++++ tests/unit/unittest/data/followsymbol_main.cpp | 13 +++++++++++++ 3 files changed, 30 insertions(+) diff --git a/src/tools/clangbackend/source/clangfollowsymbol.cpp b/src/tools/clangbackend/source/clangfollowsymbol.cpp index e2c619ef3fc..81aaeec5c89 100644 --- a/src/tools/clangbackend/source/clangfollowsymbol.cpp +++ b/src/tools/clangbackend/source/clangfollowsymbol.cpp @@ -95,6 +95,16 @@ FollowSymbolResult FollowSymbol::followSymbol(CXTranslationUnit tu, return SourceRangeContainer(); Cursor cursor{cursors[tokenIndex]}; + if (cursor.kind() == CXCursor_CXXThisExpr && tokenSpelling != "this") { // QTCREATORBUG-25342 + cursor.semanticParent().visit([&cursor](CXCursor current, CXCursor parent) { + if (current == cursor && parent.kind == CXCursor_MemberRefExpr + && cursor.sourceLocation() == Cursor(parent).sourceLocation()) { + cursor = parent; + return CXChildVisit_Break; + } + return CXChildVisit_Recurse; + }); + } if (cursor.kind() == CXCursor_InclusionDirective) { CXFile file = clang_getIncludedFile(cursors[tokenIndex].cx()); diff --git a/tests/unit/unittest/clangfollowsymbol-test.cpp b/tests/unit/unittest/clangfollowsymbol-test.cpp index e836cc83c66..29c0a702b37 100644 --- a/tests/unit/unittest/clangfollowsymbol-test.cpp +++ b/tests/unit/unittest/clangfollowsymbol-test.cpp @@ -209,6 +209,13 @@ TEST_F(FollowSymbol, CursorOnMemberReference) ASSERT_THAT(memberDeclaration, MatchesHeaderSourceRange(38, 18, 6)); } +TEST_F(FollowSymbol, CursorOnMemberReferenceAnonymousUnion) +{ + const auto memberDeclaration = followSymbol(91, 20); + + ASSERT_THAT(memberDeclaration, MatchesSourceRange(86, 13, 1)); +} + TEST_F(FollowSymbol, CursorOnMemberDeclaration) { const auto sameMemberDeclaration = followHeaderSymbol(38, 18); diff --git a/tests/unit/unittest/data/followsymbol_main.cpp b/tests/unit/unittest/data/followsymbol_main.cpp index 9b16158e40d..f967d8653be 100644 --- a/tests/unit/unittest/data/followsymbol_main.cpp +++ b/tests/unit/unittest/data/followsymbol_main.cpp @@ -80,3 +80,16 @@ int Bar::operator&() { Bar& Bar::operator[](int) { return *this; } + +struct S { + union { + int i = 12; + void *something; + }; + int func(bool b) { + if (b) + return i; + int i = 42; + return i; + } +};