forked from qt-creator/qt-creator
		
	If we prefetch data from the database to the caches we reduce the database transaction calls which are quite expensive. Change-Id: I617a0d886807402e0a94291a913a77f989970b55 Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
		
			
				
	
	
		
			239 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			239 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/****************************************************************************
 | 
						|
**
 | 
						|
** Copyright (C) 2016 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 "sourcerangecontainer-matcher.h"
 | 
						|
#include "dynamicastmatcherdiagnosticcontainer-matcher.h"
 | 
						|
#include "filesystem-utilities.h"
 | 
						|
 | 
						|
#include <clangquery.h>
 | 
						|
#include <refactoringdatabaseinitializer.h>
 | 
						|
 | 
						|
#include <sqlitedatabase.h>
 | 
						|
 | 
						|
#include <filepathcaching.h>
 | 
						|
 | 
						|
#include <QDir>
 | 
						|
 | 
						|
#include <mutex>
 | 
						|
 | 
						|
using ClangBackEnd::ClangQuery;
 | 
						|
using ClangBackEnd::FilePath;
 | 
						|
using ClangBackEnd::FilePathCaching;
 | 
						|
using ClangBackEnd::RefactoringDatabaseInitializer;
 | 
						|
 | 
						|
using testing::AllOf;
 | 
						|
using testing::Contains;
 | 
						|
using testing::IsEmpty;
 | 
						|
using testing::Not;
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
class ClangQuery : public ::testing::Test
 | 
						|
{
 | 
						|
protected:
 | 
						|
    void SetUp() override;
 | 
						|
 | 
						|
protected:
 | 
						|
    Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
 | 
						|
    RefactoringDatabaseInitializer<Sqlite::Database> initializer{database};
 | 
						|
    FilePathCaching filePathCache{database};
 | 
						|
    ::ClangQuery simpleFunctionQuery{filePathCache};
 | 
						|
    ::ClangQuery simpleClassQuery{filePathCache};
 | 
						|
};
 | 
						|
 | 
						|
using ClangQuerySlowTest = ClangQuery;
 | 
						|
 | 
						|
TEST_F(ClangQuery, NoSourceRangesForDefaultConstruction)
 | 
						|
{
 | 
						|
    auto sourceRanges = simpleFunctionQuery.takeSourceRanges();
 | 
						|
 | 
						|
    ASSERT_THAT(sourceRanges.sourceRangeWithTextContainers, IsEmpty());
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ClangQuerySlowTest, SourceRangesForSimpleFunctionDeclarationAreNotEmpty)
 | 
						|
{
 | 
						|
    simpleFunctionQuery.setQuery("functionDecl()");
 | 
						|
 | 
						|
    simpleFunctionQuery.findLocations();
 | 
						|
 | 
						|
    ASSERT_THAT(simpleFunctionQuery.takeSourceRanges().sourceRangeWithTextContainers, Not(IsEmpty()));
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ClangQuerySlowTest, RootSourceRangeForSimpleFunctionDeclarationRange)
 | 
						|
{
 | 
						|
    simpleFunctionQuery.setQuery("functionDecl()");
 | 
						|
 | 
						|
    simpleFunctionQuery.findLocations();
 | 
						|
 | 
						|
    ASSERT_THAT(simpleFunctionQuery.takeSourceRanges().sourceRangeWithTextContainers,
 | 
						|
                Contains(IsSourceRangeWithText(1, 1, 8, 2, "int function(int* pointer, int value)\n{\n  if (pointer == nullptr) {\n    return value + 1;\n  } else {\n    return value - 1;\n  }\n}")));
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ClangQuerySlowTest, SourceRangeInUnsavedFileDeclarationRange)
 | 
						|
{
 | 
						|
    ::ClangQuery query(filePathCache);
 | 
						|
    query.addFile({TESTDATA_DIR "/query_simplefunction.cpp"},
 | 
						|
                  "#include \"unsaved.h\"",
 | 
						|
                  {"cc", "-std=c++14"});
 | 
						|
    query.setQuery("functionDecl()");
 | 
						|
    ClangBackEnd::V2::FileContainer unsavedFile{{TESTDATA_DIR, "unsaved.h"},
 | 
						|
                                                filePathCache.filePathId(
 | 
						|
                                                    FilePath{TESTDATA_DIR, "unsaved.h"}),
 | 
						|
                                                "void unsaved();",
 | 
						|
                                                {}};
 | 
						|
    query.addUnsavedFiles({unsavedFile});
 | 
						|
 | 
						|
    query.findLocations();
 | 
						|
 | 
						|
    ASSERT_THAT(query.takeSourceRanges().sourceRangeWithTextContainers,
 | 
						|
                Contains(IsSourceRangeWithText(1, 1, 1, 15, "void unsaved();")));
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ClangQuerySlowTest, FileIsNotExistingButTheUnsavedDataIsParsed)
 | 
						|
{
 | 
						|
    ::ClangQuery query(filePathCache);
 | 
						|
    query.addFile({TESTDATA_DIR "/foo.cpp"}, "void f() {}", {"cc", "-std=c++14"});
 | 
						|
    query.setQuery("functionDecl()");
 | 
						|
 | 
						|
    query.findLocations();
 | 
						|
 | 
						|
    ASSERT_THAT(query.takeSourceRanges().sourceRangeWithTextContainers,
 | 
						|
                Contains(IsSourceRangeWithText(1, 1, 1, 12, "void f() {}")));
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ClangQuerySlowTest, DISABLED_SourceRangeInUnsavedFileDeclarationRangeOverride) // seems not to work in Clang
 | 
						|
{
 | 
						|
    ::ClangQuery query(filePathCache);
 | 
						|
    query.addFile({TESTDATA_DIR "/query_simplefunction.cpp"}, "void f() {}", {"cc", "-std=c++14"});
 | 
						|
    query.setQuery("functionDecl()");
 | 
						|
    ClangBackEnd::V2::FileContainer unsavedFile{{TESTDATA_DIR "/query_simplefunction.cpp"},
 | 
						|
                                                filePathCache.filePathId(
 | 
						|
                                                    FilePath{TESTDATA_DIR, "query_simplefunction.cpp"}),
 | 
						|
                                                "void unsaved();",
 | 
						|
                                                {}};
 | 
						|
    query.addUnsavedFiles({unsavedFile});
 | 
						|
 | 
						|
    query.findLocations();
 | 
						|
 | 
						|
    ASSERT_THAT(query.takeSourceRanges().sourceRangeWithTextContainers,
 | 
						|
                Contains(IsSourceRangeWithText(1, 1, 1, 15, "void unsaved();")));
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ClangQuerySlowTest, RootSourceRangeForSimpleFieldDeclarationRange)
 | 
						|
{
 | 
						|
    simpleClassQuery.setQuery("fieldDecl(hasType(isInteger()))");
 | 
						|
 | 
						|
    simpleClassQuery.findLocations();
 | 
						|
 | 
						|
    ASSERT_THAT(simpleClassQuery.takeSourceRanges().sourceRangeWithTextContainers.at(0),
 | 
						|
                IsSourceRangeWithText(4, 5, 4, 10, "    int x;"));
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ClangQuerySlowTest, NoSourceRangesForEmptyQuery)
 | 
						|
{
 | 
						|
    simpleClassQuery.findLocations();
 | 
						|
 | 
						|
    ASSERT_THAT(simpleClassQuery.takeSourceRanges().sourceRangeWithTextContainers, IsEmpty());
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ClangQuerySlowTest, NoSourceRangesForWrongQuery)
 | 
						|
{
 | 
						|
    simpleClassQuery.setQuery("wrongQuery()");
 | 
						|
 | 
						|
    simpleClassQuery.findLocations();
 | 
						|
 | 
						|
    ASSERT_THAT(simpleClassQuery.takeSourceRanges().sourceRangeWithTextContainers, IsEmpty());
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ClangQuerySlowTest, NoDiagnosticsForDefaultConstruction)
 | 
						|
{
 | 
						|
    auto diagnostics = simpleFunctionQuery.takeDiagnosticContainers();
 | 
						|
 | 
						|
    ASSERT_THAT(diagnostics, IsEmpty());
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ClangQuerySlowTest, DiagnosticsForEmptyQuery)
 | 
						|
{
 | 
						|
    simpleFunctionQuery.findLocations();
 | 
						|
 | 
						|
    ASSERT_THAT(simpleFunctionQuery.takeDiagnosticContainers(),
 | 
						|
                Not(IsEmpty()));
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ClangQuerySlowTest, DiagnosticsForWrongQuery)
 | 
						|
{
 | 
						|
    simpleClassQuery.setQuery("wrongQuery()");
 | 
						|
 | 
						|
    simpleClassQuery.findLocations();
 | 
						|
 | 
						|
    ASSERT_THAT(simpleClassQuery.takeDiagnosticContainers(),
 | 
						|
                Not(IsEmpty()));
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ClangQuerySlowTest, NoDiagnosticsForAccurateQuery)
 | 
						|
{
 | 
						|
    simpleFunctionQuery.setQuery("functionDecl()");
 | 
						|
 | 
						|
    simpleFunctionQuery.findLocations();
 | 
						|
 | 
						|
    ASSERT_THAT(simpleFunctionQuery.takeDiagnosticContainers(),
 | 
						|
                IsEmpty());
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ClangQuerySlowTest, DiagnosticForWrongQuery)
 | 
						|
{
 | 
						|
    simpleClassQuery.setQuery("wrongQuery()");
 | 
						|
 | 
						|
    simpleClassQuery.findLocations();
 | 
						|
 | 
						|
    ASSERT_THAT(simpleClassQuery.takeDiagnosticContainers(),
 | 
						|
                HasDiagnosticMessage("RegistryMatcherNotFound", 1, 1, 1, 11));
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ClangQuerySlowTest, DiagnosticForWrongArgumenType)
 | 
						|
{
 | 
						|
    simpleFunctionQuery.setQuery("functionDecl(1)");
 | 
						|
 | 
						|
    simpleFunctionQuery.findLocations();
 | 
						|
 | 
						|
    ASSERT_THAT(simpleFunctionQuery.takeDiagnosticContainers(),
 | 
						|
                AllOf(HasDiagnosticMessage("RegistryWrongArgType", 1, 14, 1, 15),
 | 
						|
                      HasDiagnosticContext("MatcherConstruct", 1, 1, 1, 13)));
 | 
						|
}
 | 
						|
 | 
						|
void ClangQuery::SetUp()
 | 
						|
{
 | 
						|
    simpleFunctionQuery.addFile({TESTDATA_DIR "/query_simplefunction.cpp"},
 | 
						|
                                "",
 | 
						|
                                {"cc",
 | 
						|
                                 "-std=c++14"});
 | 
						|
    simpleClassQuery.addFile({TESTDATA_DIR "/query_simpleclass.cpp"},
 | 
						|
                             "",
 | 
						|
                             {"cc",
 | 
						|
                              "-std=c++14"});
 | 
						|
}
 | 
						|
} // namespace
 |