forked from qt-creator/qt-creator
... 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 <fabian.kosmale@qt.io>
368 lines
11 KiB
C++
368 lines
11 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2017 The Qt Company Ltd.
|
|
** Contact: https://www.qt.io/licensing/
|
|
**
|
|
** This file is part of Qt Creator.
|
|
**
|
|
** Commercial License Usage
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
** accordance with the commercial license agreement provided with the
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
|
**
|
|
** GNU General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
** General Public License version 3 as published by the Free Software
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
** included in the packaging of this file. Please review the following
|
|
** information to ensure the GNU General Public License requirements will
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
**
|
|
****************************************************************************/
|
|
|
|
#include "googletest.h"
|
|
#include "unittest-utility-functions.h"
|
|
|
|
#include <clangsupport_global.h>
|
|
#include <clangfollowsymboljob.h>
|
|
#include <clangdocument.h>
|
|
#include <clangdocuments.h>
|
|
#include <clangtranslationunit.h>
|
|
#include <fixitcontainer.h>
|
|
#include <followsymbolmessage.h>
|
|
#include <sourcelocationcontainer.h>
|
|
#include <sourcerangecontainer.h>
|
|
#include <unsavedfiles.h>
|
|
#include <commandlinearguments.h>
|
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
#include <clang-c/Index.h>
|
|
|
|
using ::testing::Contains;
|
|
using ::testing::Not;
|
|
using ::testing::ContainerEq;
|
|
using ::testing::Eq;
|
|
using ::testing::PrintToString;
|
|
|
|
using ::ClangBackEnd::SourceLocationContainer;
|
|
using ::ClangBackEnd::Document;
|
|
using ::ClangBackEnd::UnsavedFiles;
|
|
using ::ClangBackEnd::ReferencesResult;
|
|
using ::ClangBackEnd::SourceRangeContainer;
|
|
using ::ClangBackEnd::FollowSymbolResult;
|
|
|
|
namespace {
|
|
const Utf8String sourceFilePath = Utf8StringLiteral(TESTDATA_DIR"/followsymbol_main.cpp");
|
|
const Utf8String headerFilePath = Utf8StringLiteral(TESTDATA_DIR"/followsymbol_header.h");
|
|
const Utf8String cursorPath = Utf8StringLiteral(TESTDATA_DIR"/cursor.cpp");
|
|
|
|
MATCHER_P3(MatchesHeaderSourceRange, line, column, length,
|
|
std::string(negation ? "isn't " : "is ")
|
|
+ PrintToString(SourceRangeContainer {
|
|
SourceLocationContainer(headerFilePath, line, column),
|
|
SourceLocationContainer(headerFilePath, line, column + length)
|
|
})
|
|
)
|
|
{
|
|
const SourceRangeContainer expected = {
|
|
SourceLocationContainer(headerFilePath, line, column),
|
|
SourceLocationContainer(headerFilePath, line, column + length)
|
|
};
|
|
|
|
return arg == expected;
|
|
}
|
|
|
|
MATCHER_P3(MatchesSourceRange, line, column, length,
|
|
std::string(negation ? "isn't " : "is ")
|
|
+ PrintToString(SourceRangeContainer {
|
|
SourceLocationContainer(sourceFilePath, line, column),
|
|
SourceLocationContainer(sourceFilePath, line, column + length)
|
|
})
|
|
)
|
|
{
|
|
const SourceRangeContainer expected = {
|
|
SourceLocationContainer(sourceFilePath, line, column),
|
|
SourceLocationContainer(sourceFilePath, line, column + length)
|
|
};
|
|
|
|
return arg == expected;
|
|
}
|
|
|
|
MATCHER_P4(MatchesFileSourceRange, filename, line, column, length,
|
|
std::string(negation ? "isn't " : "is ")
|
|
+ PrintToString(SourceRangeContainer {
|
|
SourceLocationContainer(filename, line, column),
|
|
SourceLocationContainer(filename, line, column + length)
|
|
})
|
|
)
|
|
{
|
|
const SourceRangeContainer expected = {
|
|
SourceLocationContainer(filename, line, column),
|
|
SourceLocationContainer(filename, line, column + length)
|
|
};
|
|
|
|
return arg == expected;
|
|
}
|
|
|
|
class Data {
|
|
public:
|
|
ClangBackEnd::UnsavedFiles unsavedFiles;
|
|
ClangBackEnd::Documents documents{unsavedFiles};
|
|
Utf8StringVector compilationArguments{
|
|
UnitTest::addPlatformArguments({Utf8StringLiteral("-std=c++14")})};
|
|
Document document = {sourceFilePath, compilationArguments, {}, documents};
|
|
Document headerDocument = {headerFilePath, compilationArguments, {}, documents};
|
|
QVector<Utf8String> deps{sourceFilePath, cursorPath};
|
|
};
|
|
|
|
class FollowSymbol : public ::testing::Test
|
|
{
|
|
protected:
|
|
FollowSymbolResult followSymbol(uint line, uint column)
|
|
{
|
|
return document.translationUnit().followSymbol(line, column);
|
|
}
|
|
|
|
FollowSymbolResult followHeaderSymbol(uint line, uint column)
|
|
{
|
|
return headerDocument.translationUnit().followSymbol(line, column);
|
|
}
|
|
|
|
static void SetUpTestCase();
|
|
static void TearDownTestCase();
|
|
|
|
private:
|
|
static std::unique_ptr<const Data> data;
|
|
const Document &document{data->document};
|
|
const Document &headerDocument{data->headerDocument};
|
|
const QVector<Utf8String> &deps{data->deps};
|
|
};
|
|
|
|
// NOTE: some tests are disabled because clang code model does not need to follow symbols
|
|
// to other translation units. When there's infrastructure to test database based follow symbol
|
|
// they should be moved there.
|
|
|
|
TEST_F(FollowSymbol, CursorOnNamespace)
|
|
{
|
|
const auto namespaceDefinition = followSymbol(27, 1);
|
|
|
|
ASSERT_THAT(namespaceDefinition, MatchesHeaderSourceRange(28, 11, 6));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, CursorOnClassReference)
|
|
{
|
|
const auto classDefinition = followSymbol(27, 9);
|
|
|
|
ASSERT_THAT(classDefinition, MatchesHeaderSourceRange(34, 7, 3));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, CursorOnClassForwardDeclarationFollowToHeader)
|
|
{
|
|
const auto classDefinition = followHeaderSymbol(32, 7);
|
|
|
|
ASSERT_THAT(classDefinition, MatchesHeaderSourceRange(34, 7, 3));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, DISABLED_CursorOnClassForwardDeclarationFollowToCpp)
|
|
{
|
|
const auto classDefinition = followHeaderSymbol(48, 9);
|
|
|
|
ASSERT_THAT(classDefinition, MatchesSourceRange(54, 7, 8));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, CursorOnClassDefinition)
|
|
{
|
|
const auto classForwardDeclaration = followHeaderSymbol(34, 7);
|
|
|
|
ASSERT_THAT(classForwardDeclaration, MatchesHeaderSourceRange(32, 7, 3));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, CursorOnClassDefinitionInCpp)
|
|
{
|
|
const auto classForwardDeclaration = followSymbol(54, 7);
|
|
|
|
ASSERT_THAT(classForwardDeclaration, MatchesHeaderSourceRange(48, 7, 8));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, DISABLED_CursorOnConstructorDeclaration)
|
|
{
|
|
const auto constructorDefinition = followHeaderSymbol(36, 5);
|
|
|
|
ASSERT_THAT(constructorDefinition, MatchesSourceRange(27, 14, 3));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, CursorOnConstructorDefinition)
|
|
{
|
|
const auto constructorDeclaration = followSymbol(27, 14);
|
|
|
|
ASSERT_THAT(constructorDeclaration, MatchesHeaderSourceRange(36, 5, 3));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, CursorOnMemberReference)
|
|
{
|
|
const auto memberDeclaration = followSymbol(39, 10);
|
|
|
|
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);
|
|
|
|
ASSERT_THAT(sameMemberDeclaration, MatchesHeaderSourceRange(38, 18, 6));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, CursorOnFunctionReference)
|
|
{
|
|
const auto functionDefinition = followSymbol(66, 12);
|
|
|
|
ASSERT_THAT(functionDefinition, MatchesSourceRange(35, 5, 3));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, DISABLED_CursorOnMemberFunctionReference)
|
|
{
|
|
const auto memberFunctionDefinition = followSymbol(42, 12);
|
|
|
|
ASSERT_THAT(memberFunctionDefinition, MatchesSourceRange(49, 21, 3));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, DISABLED_CursorOnFunctionWithoutDefinitionReference)
|
|
{
|
|
const auto functionDeclaration = followSymbol(43, 5);
|
|
|
|
ASSERT_THAT(functionDeclaration, MatchesHeaderSourceRange(59, 5, 3));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, CursorOnFunctionDefinition)
|
|
{
|
|
const auto functionDeclaration = followSymbol(35, 5);
|
|
|
|
ASSERT_THAT(functionDeclaration, MatchesHeaderSourceRange(52, 5, 3));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, CursorOnMemberFunctionDefinition)
|
|
{
|
|
const auto memberFunctionDeclaration = followSymbol(49, 21);
|
|
|
|
ASSERT_THAT(memberFunctionDeclaration, MatchesHeaderSourceRange(43, 9, 3));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, DISABLED_CursorOnMemberFunctionDeclaration)
|
|
{
|
|
const auto memberFunctionDefinition = followHeaderSymbol(43, 9);
|
|
|
|
ASSERT_THAT(memberFunctionDefinition, MatchesSourceRange(49, 21, 3));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, CursorOnInclude)
|
|
{
|
|
const auto startOfIncludeFile = followSymbol(25, 13);
|
|
|
|
ASSERT_THAT(startOfIncludeFile, MatchesHeaderSourceRange(1, 1, 0));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, CursorOnLocalVariable)
|
|
{
|
|
const auto variableDeclaration = followSymbol(39, 6);
|
|
|
|
ASSERT_THAT(variableDeclaration, MatchesSourceRange(36, 9, 3));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, CursorOnClassAlias)
|
|
{
|
|
const auto aliasDefinition = followSymbol(36, 5);
|
|
|
|
ASSERT_THAT(aliasDefinition, MatchesSourceRange(33, 7, 3));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, CursorOnStaticVariable)
|
|
{
|
|
const auto staticVariableDeclaration = followSymbol(40, 27);
|
|
|
|
ASSERT_THAT(staticVariableDeclaration, MatchesHeaderSourceRange(30, 7, 7));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, DISABLED_CursorOnFunctionFromOtherClass)
|
|
{
|
|
const auto functionDefinition = followSymbol(62, 39);
|
|
|
|
ASSERT_THAT(functionDefinition, MatchesFileSourceRange(cursorPath, 104, 22, 8));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, DISABLED_CursorOnDefineReference)
|
|
{
|
|
const auto functionDefinition = followSymbol(66, 43);
|
|
|
|
ASSERT_THAT(functionDefinition, MatchesHeaderSourceRange(27, 9, 11));
|
|
}
|
|
|
|
|
|
TEST_F(FollowSymbol, CursorInTheMiddleOfNamespace)
|
|
{
|
|
const auto namespaceDefinition = followSymbol(27, 3);
|
|
|
|
ASSERT_THAT(namespaceDefinition, MatchesHeaderSourceRange(28, 11, 6));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, CursorAfterNamespace)
|
|
{
|
|
const auto namespaceDefinition = followSymbol(27, 7);
|
|
|
|
ASSERT_THAT(namespaceDefinition, MatchesFileSourceRange(QString(""), 0, 0, 0));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, CursorOnOneSymbolOperatorDefinition)
|
|
{
|
|
const auto namespaceDefinition = followSymbol(76, 13);
|
|
|
|
ASSERT_THAT(namespaceDefinition, MatchesSourceRange(72, 9, 9));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, CursorOnTwoSymbolOperatorDefinition)
|
|
{
|
|
const auto namespaceDefinition = followSymbol(80, 15);
|
|
|
|
ASSERT_THAT(namespaceDefinition, MatchesSourceRange(73, 10, 10));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, CursorOnOneSymbolOperatorDeclaration)
|
|
{
|
|
const auto namespaceDefinition = followSymbol(72, 12);
|
|
|
|
ASSERT_THAT(namespaceDefinition, MatchesSourceRange(76, 10, 9));
|
|
}
|
|
|
|
TEST_F(FollowSymbol, CursorOnTwoSymbolOperatorDeclaration)
|
|
{
|
|
const auto namespaceDefinition = followSymbol(73, 12);
|
|
|
|
ASSERT_THAT(namespaceDefinition, MatchesSourceRange(80, 11, 10));
|
|
}
|
|
|
|
std::unique_ptr<const Data> FollowSymbol::data;
|
|
|
|
void FollowSymbol::SetUpTestCase()
|
|
{
|
|
data = std::make_unique<Data>();
|
|
data->document.parse();
|
|
data->headerDocument.parse();
|
|
}
|
|
|
|
void FollowSymbol::TearDownTestCase()
|
|
{
|
|
data.reset();
|
|
}
|
|
|
|
} // anonymous namespace
|