Clang: On the road to update and preprocessor support

This patch has grown in a quite big change set and it is really hard to
divide it in different parts.
V2::ProjectPartContainer is now using FileIds instead of file paths. This
cleans code up because it is a big step in the direction that internally
only file ids are used. But it is depending on the file cache, so the
file cache has to be provided as an argument. There is now an interface for
transactions too which are ease the testing of them and enables the support
of preprocessor. It adds macros as symbols and is saving used macros. The
used macro support is enabling update improvements because only if a
changed macro is used it needs to be recompiled. This is still in flux
and can be changed in later patches.

Change-Id: I492a2c9af1201d40fdd9f46a0045f7878bbbaa3d
Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
This commit is contained in:
Marco Bubke
2018-01-22 14:21:01 +01:00
parent 3d2db474a4
commit 0f8befacd3
70 changed files with 1543 additions and 531 deletions

View File

@@ -12,7 +12,10 @@ HEADERS += \
$$PWD/storagesqlitestatementfactory.h \
$$PWD/symbolindexing.h \
$$PWD/symbolindexinginterface.h \
$$PWD/collectmacrospreprocessorcallbacks.h
$$PWD/collectmacrospreprocessorcallbacks.h \
$$PWD/projectpartentry.h \
$$PWD/useddefines.h \
$$PWD/symbolsvisitorbase.h
!isEmpty(LIBTOOLING_LIBS) {
SOURCES += \
@@ -58,4 +61,5 @@ HEADERS += \
SOURCES += \
$$PWD/sourcerangefilter.cpp \
$$PWD/symbolindexer.cpp \
$$PWD/symbolentry.cpp
$$PWD/symbolentry.cpp \
$$PWD/symbolstorageinterface.cpp

View File

@@ -58,6 +58,19 @@ void ClangTool::addFile(std::string &&directory,
m_sourceFilePaths.push_back(fileContent.filePath);
}
void ClangTool::addFiles(const FilePaths &filePaths, const Utils::SmallStringVector &arguments)
{
for (const FilePath &filePath : filePaths) {
std::vector<std::string> commandLine(arguments.begin(), arguments.end());
commandLine.push_back(std::string(filePath.name()));
addFile(filePath.directory(),
filePath.name(),
{},
std::move(commandLine));
}
}
template <typename Container>
void ClangTool::addFiles(const Container &filePaths,
const Utils::SmallStringVector &arguments)

View File

@@ -84,6 +84,9 @@ public:
template <typename Container>
void addFiles(const Container &filePaths,
const Utils::SmallStringVector &arguments);
void addFiles(const FilePaths &filePaths,
const Utils::SmallStringVector &arguments);
void addUnsavedFiles(const V2::FileContainers &unsavedFiles);

View File

@@ -25,7 +25,11 @@
#pragma once
#include "symbolsvisitorbase.h"
#include "sourcelocationsutils.h"
#include "sourcelocationentry.h"
#include "symbolentry.h"
#include "useddefines.h"
#include <filepath.h>
#include <filepathid.h>
@@ -36,14 +40,21 @@
namespace ClangBackEnd {
class CollectMacrosPreprocessorCallbacks final : public clang::PPCallbacks
class CollectMacrosPreprocessorCallbacks final : public clang::PPCallbacks,
public SymbolsVisitorBase
{
public:
CollectMacrosPreprocessorCallbacks(FilePathIds &sourceFiles,
FilePathCachingInterface &filePathCache)
: m_sourceFiles(sourceFiles),
m_filePathCache(filePathCache)
CollectMacrosPreprocessorCallbacks(SymbolEntries &symbolEntries,
SourceLocationEntries &sourceLocationEntries,
FilePathIds &sourceFiles,
UsedDefines &usedDefines,
FilePathCachingInterface &filePathCache,
const clang::SourceManager &sourceManager)
: SymbolsVisitorBase(filePathCache, sourceManager),
m_symbolEntries(symbolEntries),
m_sourceLocationEntries(sourceLocationEntries),
m_sourceFiles(sourceFiles),
m_usedDefines(usedDefines)
{
}
@@ -70,6 +81,125 @@ public:
return true;
}
void Ifndef(clang::SourceLocation,
const clang::Token &macroNameToken,
const clang::MacroDefinition &macroDefinition) override
{
addUsedDefine(macroNameToken, macroDefinition);
addMacroAsSymbol(macroNameToken,
firstMacroInfo(macroDefinition.getLocalDirective()),
SymbolType::MacroUsage);
}
void Ifdef(clang::SourceLocation,
const clang::Token &macroNameToken,
const clang::MacroDefinition &macroDefinition) override
{
addUsedDefine( macroNameToken, macroDefinition);
addMacroAsSymbol(macroNameToken,
firstMacroInfo(macroDefinition.getLocalDirective()),
SymbolType::MacroUsage);
}
void Defined(const clang::Token &macroNameToken,
const clang::MacroDefinition &macroDefinition,
clang::SourceRange) override
{
addUsedDefine(macroNameToken, macroDefinition);
addMacroAsSymbol(macroNameToken,
firstMacroInfo(macroDefinition.getLocalDirective()),
SymbolType::MacroUsage);
}
void MacroDefined(const clang::Token &macroNameToken,
const clang::MacroDirective *macroDirective) override
{
addMacroAsSymbol(macroNameToken,
firstMacroInfo(macroDirective),
SymbolType::MacroDefinition);
}
void MacroUndefined(const clang::Token &macroNameToken,
const clang::MacroDefinition &macroDefinition,
const clang::MacroDirective *) override
{
addMacroAsSymbol(macroNameToken,
firstMacroInfo(macroDefinition.getLocalDirective()),
SymbolType::MacroUndefinition);
}
void MacroExpands(const clang::Token &macroNameToken,
const clang::MacroDefinition &macroDefinition,
clang::SourceRange,
const clang::MacroArgs *) override
{
addUsedDefine(macroNameToken, macroDefinition);
addMacroAsSymbol(macroNameToken,
firstMacroInfo(macroDefinition.getLocalDirective()),
SymbolType::MacroUsage);
}
void addUsedDefine(const clang::Token &macroNameToken,
const clang::MacroDefinition &macroDefinition)
{
clang::MacroInfo *macroInfo = macroDefinition.getMacroInfo();
if (macroInfo) {
UsedDefine usedDefine{macroNameToken.getIdentifierInfo()->getName(),
filePathId(macroNameToken.getLocation())};
auto found = std::lower_bound(m_usedDefines.begin(),
m_usedDefines.end(), usedDefine);
if (found == m_usedDefines.end() || *found != usedDefine)
m_usedDefines.insert(found, std::move(usedDefine));
}
}
static const clang::MacroInfo *firstMacroInfo(const clang::MacroDirective *macroDirective)
{
if (macroDirective) {
const clang::MacroDirective *previousDirective = macroDirective;
do {
macroDirective = previousDirective;
previousDirective = macroDirective->getPrevious();
} while (previousDirective);
return macroDirective->getMacroInfo();
}
return nullptr;
}
void addMacroAsSymbol(const clang::Token &macroNameToken,
const clang::MacroInfo *macroInfo,
SymbolType symbolType)
{
clang::SourceLocation sourceLocation = macroNameToken.getLocation();
if (macroInfo && sourceLocation.isFileID()) {
FilePathId fileId = filePathId(sourceLocation);
auto macroName = macroNameToken.getIdentifierInfo()->getName();
if (fileId.isValid()) {
auto macroName = macroNameToken.getIdentifierInfo()->getName();
SymbolIndex globalId = toSymbolIndex(macroInfo);
auto found = m_symbolEntries.find(globalId);
if (found == m_symbolEntries.end()) {
Utils::optional<Utils::PathString> usr = generateUSR(macroName, sourceLocation);
if (usr) {
m_symbolEntries.emplace(std::piecewise_construct,
std::forward_as_tuple(globalId),
std::forward_as_tuple(std::move(usr.value()), macroName));
}
}
m_sourceLocationEntries.emplace_back(globalId,
fileId,
lineColum(sourceLocation),
symbolType);
}
}
}
void addSourceFile(const clang::FileEntry *file)
{
auto filePathId = m_filePathCache.filePathId(
@@ -82,8 +212,10 @@ public:
}
private:
SymbolEntries &m_symbolEntries;
SourceLocationEntries &m_sourceLocationEntries;
FilePathIds &m_sourceFiles;
FilePathCachingInterface &m_filePathCache;
UsedDefines &m_usedDefines;
bool m_skipInclude = false;
};

View File

@@ -33,8 +33,12 @@ namespace ClangBackEnd {
bool CollectMacrosSourceFileCallbacks::handleBeginSource(clang::CompilerInstance &compilerInstance)
{
auto callbacks = std::make_unique<CollectMacrosPreprocessorCallbacks>(m_sourceFiles,
m_filePathCache);
auto callbacks = std::make_unique<CollectMacrosPreprocessorCallbacks>(m_symbolEntries,
m_sourceLocationEntries,
m_sourceFiles,
m_usedDefines,
m_filePathCache,
compilerInstance.getSourceManager());
compilerInstance.getPreprocessorPtr()->addPPCallbacks(std::move(callbacks));

View File

@@ -25,6 +25,10 @@
#pragma once
#include "sourcelocationentry.h"
#include "symbolentry.h"
#include "useddefines.h"
#include <filepathcachinginterface.h>
#include <clang/Tooling/Tooling.h>
@@ -34,8 +38,12 @@ namespace ClangBackEnd {
class CollectMacrosSourceFileCallbacks : public clang::tooling::SourceFileCallbacks
{
public:
CollectMacrosSourceFileCallbacks(FilePathCachingInterface &filePathCache)
: m_filePathCache(filePathCache)
CollectMacrosSourceFileCallbacks(SymbolEntries &symbolEntries,
SourceLocationEntries &sourceLocationEntries,
FilePathCachingInterface &filePathCache)
: m_symbolEntries(symbolEntries),
m_sourceLocationEntries(sourceLocationEntries),
m_filePathCache(filePathCache)
{
}
@@ -46,14 +54,9 @@ public:
return m_sourceFiles;
}
void addSourceFiles(const Utils::PathStringVector &filePaths)
void addSourceFiles(const FilePathIds &filePathIds)
{
std::transform(filePaths.begin(),
filePaths.end(),
std::back_inserter(m_sourceFiles),
[&] (const Utils::PathString &filePath) {
return m_filePathCache.filePathId(FilePathView{filePath});
});
m_sourceFiles = filePathIds;
}
void clearSourceFiles()
@@ -61,8 +64,16 @@ public:
m_sourceFiles.clear();
}
const UsedDefines &usedDefines() const
{
return m_usedDefines;
}
private:
FilePathIds m_sourceFiles;
UsedDefines m_usedDefines;
SymbolEntries &m_symbolEntries;
SourceLocationEntries &m_sourceLocationEntries;
FilePathCachingInterface &m_filePathCache;
};

View File

@@ -42,8 +42,12 @@ namespace ClangBackEnd {
class CollectSymbolsAction
{
public:
CollectSymbolsAction(FilePathCachingInterface &filePathCache)
: m_filePathCache(filePathCache)
CollectSymbolsAction(SymbolEntries &symbolEntries,
SourceLocationEntries &sourceLocationEntries,
FilePathCachingInterface &filePathCache)
: m_symbolEntries(symbolEntries),
m_sourceLocationEntries(sourceLocationEntries),
m_filePathCache(filePathCache)
{}
std::unique_ptr<clang::ASTConsumer> newASTConsumer();
@@ -63,15 +67,9 @@ public:
return m_sourceLocationEntries;
}
void clear()
{
m_symbolEntries.clear();
m_sourceLocationEntries.clear();
}
private:
SymbolEntries m_symbolEntries;
SourceLocationEntries m_sourceLocationEntries;
SymbolEntries &m_symbolEntries;
SourceLocationEntries &m_sourceLocationEntries;
FilePathCachingInterface &m_filePathCache;
};

View File

@@ -25,32 +25,30 @@
#pragma once
#include "symbolentry.h"
#include "sourcelocationentry.h"
#include <filepathcachinginterface.h>
#include "sourcelocationsutils.h"
#include "symbolentry.h"
#include "symbolsvisitorbase.h"
#include <clang/AST/AST.h>
#include <clang/AST/ASTContext.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/Index/USRGeneration.h>
#include <llvm/ADT/SmallVector.h>
#include <vector>
namespace ClangBackEnd {
class CollectSymbolsASTVisitor : public clang::RecursiveASTVisitor<CollectSymbolsASTVisitor>
class CollectSymbolsASTVisitor : public clang::RecursiveASTVisitor<CollectSymbolsASTVisitor>,
public SymbolsVisitorBase
{
public:
CollectSymbolsASTVisitor(SymbolEntries &symbolEntries,
SourceLocationEntries &sourceLocationEntries,
FilePathCachingInterface &filePathCache,
const clang::SourceManager &sourceManager)
: m_symbolEntries(symbolEntries),
m_sourceLocationEntries(sourceLocationEntries),
m_filePathCache(filePathCache),
m_sourceManager(sourceManager)
: SymbolsVisitorBase(filePathCache, sourceManager),
m_symbolEntries(symbolEntries),
m_sourceLocationEntries(sourceLocationEntries)
{}
bool shouldVisitTemplateInstantiations() const
@@ -68,9 +66,12 @@ public:
auto found = m_symbolEntries.find(globalId);
if (found == m_symbolEntries.end()) {
m_symbolEntries.emplace(std::piecewise_construct,
std::forward_as_tuple(globalId),
std::forward_as_tuple(generateUSR(declaration), symbolName(declaration)));
Utils::optional<Utils::PathString> usr = generateUSR(declaration);
if (usr) {
m_symbolEntries.emplace(std::piecewise_construct,
std::forward_as_tuple(globalId),
std::forward_as_tuple(std::move(usr.value()), symbolName(declaration)));
}
}
m_sourceLocationEntries.emplace_back(globalId,
@@ -95,57 +96,15 @@ public:
return true;
}
FilePathId filePathId(clang::SourceLocation sourceLocation)
{
uint clangFileId = m_sourceManager.getFileID(sourceLocation).getHashValue();
auto found = m_filePathIndices.find(clangFileId);
if (found != m_filePathIndices.end())
return found->second;
auto filePath = m_sourceManager.getFilename(sourceLocation);
FilePathId filePathId = m_filePathCache.filePathId(FilePath::fromNativeFilePath(filePath));
m_filePathIndices.emplace(clangFileId, filePathId);
return filePathId;
}
LineColumn lineColum(clang::SourceLocation sourceLocation)
{
return {m_sourceManager.getSpellingLineNumber(sourceLocation),
m_sourceManager.getSpellingColumnNumber(sourceLocation)};
}
Utils::PathString generateUSR(const clang::Decl *declaration)
{
llvm::SmallVector<char, 128> usr;
clang::index::generateUSRForDecl(declaration, usr);
return {usr.data(), usr.size()};
}
Utils::SmallString symbolName(const clang::NamedDecl *declaration)
{
const llvm::StringRef symbolName{declaration->getName()};
return {symbolName.data(), symbolName.size()};
}
static SymbolIndex toSymbolIndex(const void *pointer)
{
return SymbolIndex(reinterpret_cast<std::uintptr_t>(pointer));
return declaration->getName();
}
private:
SymbolEntries &m_symbolEntries;
std::unordered_map<uint, FilePathId> m_filePathIndices;
SourceLocationEntries &m_sourceLocationEntries;
FilePathCachingInterface &m_filePathCache;
const clang::SourceManager &m_sourceManager;
};

View File

@@ -0,0 +1,58 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#pragma once
#include <filepathid.h>
#include <utils/smallstringvector.h>
namespace ClangBackEnd {
class ProjectPartEntry
{
public:
ProjectPartEntry(Utils::SmallStringView projectPathName,
const FilePathIds &filePathIds,
Utils::SmallStringVector &&compilerArguments)
: projectPathName(projectPathName), filePathIds(filePathIds), compilerArguments(compilerArguments)
{}
friend bool operator==(const ProjectPartEntry &first, const ProjectPartEntry &second)
{
return first.projectPathName == second.projectPathName
&& first.filePathIds == second.filePathIds
&& first.compilerArguments == second.compilerArguments;
}
public:
Utils::PathString projectPathName;
FilePathIds filePathIds;
Utils::SmallStringVector compilerArguments;
};
using ProjectPartEntries = std::vector<ProjectPartEntry>;
} // namespace ClangBackEnd

View File

@@ -27,6 +27,8 @@
#include <filepathid.h>
#include <utils/linecolumn.h>
#include <limits>
#include <vector>
@@ -37,19 +39,10 @@ namespace ClangBackEnd {
enum class SymbolType
{
Declaration,
DeclarationReference
};
class LineColumn
{
public:
LineColumn(uint line, uint column)
: line(line),
column(column)
{}
uint line = 0;
uint column = 0;
DeclarationReference,
MacroDefinition,
MacroUsage,
MacroUndefinition
};
using SymbolIndex = long long;
@@ -59,27 +52,24 @@ class SourceLocationEntry
public:
SourceLocationEntry(SymbolIndex symbolId,
FilePathId filePathId,
LineColumn lineColumn,
Utils::LineColumn lineColumn,
SymbolType symbolType)
: symbolId(symbolId),
filePathId(filePathId),
line(lineColumn.line),
column(lineColumn.column),
lineColumn(lineColumn),
symbolType(symbolType)
{}
SymbolIndex symbolId = 0;
FilePathId filePathId;
uint line = 0;
uint column = 0;
Utils::LineColumn lineColumn;
SymbolType symbolType;
friend bool operator==(const SourceLocationEntry &first, const SourceLocationEntry &second)
{
return first.symbolId == second.symbolId
&& first.filePathId == second.filePathId
&& first.line == second.line
&& first.column == second.column
&& first.lineColumn == second.lineColumn
&& first.symbolType == second.symbolType;
}
};

View File

@@ -57,7 +57,7 @@ public:
table.addIndex({usrColumn, symbolNameColumn});
table.addIndex({symbolIdColumn});
Sqlite::ImmediateTransaction<DatabaseType> transaction(database);
Sqlite::ImmediateTransaction transaction(database);
table.initialize(database);
transaction.commit();
@@ -76,7 +76,7 @@ public:
const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer);
table.addIndex({sourceIdColumn});
Sqlite::ImmediateTransaction<DatabaseType> transaction(database);
Sqlite::ImmediateTransaction transaction(database);
table.initialize(database);
transaction.commit();
@@ -128,6 +128,30 @@ public:
"DELETE FROM newLocations",
database
};
WriteStatement insertProjectPart{
"INSERT OR IGNORE INTO projectParts(projectPartName, compilerArguments) VALUES (?,?)",
database
};
WriteStatement updateProjectPart{
"UPDATE projectParts SET compilerArguments = ? WHERE projectPartName = ?",
database
};
ReadStatement getProjectPartId{
"SELECT projectPartId FROM projectParts WHERE projectPartName = ?",
database
};
WriteStatement deleteAllProjectPartsSourcesWithProjectPartId{
"DELETE FROM projectPartsSources WHERE projectPartId = ?",
database
};
WriteStatement insertProjectPartSources{
"INSERT INTO projectPartsSources(projectPartId, sourceId) VALUES (?,?)",
database
};
ReadStatement getCompileArgumentsForFileId{
"SELECT compilerArguments FROM projectParts WHERE projectPartId = (SELECT projectPartId FROM projectPartsSources WHERE sourceId = ?)",
database
};
};
} // namespace ClangBackEnd

View File

@@ -29,28 +29,47 @@ namespace ClangBackEnd {
SymbolIndexer::SymbolIndexer(SymbolsCollectorInterface &symbolsCollector,
SymbolStorageInterface &symbolStorage,
ClangPathWatcherInterface &pathWatcher)
ClangPathWatcherInterface &pathWatcher,
FilePathCachingInterface &filePathCache,
Sqlite::TransactionInterface &transactionInterface)
: m_symbolsCollector(symbolsCollector),
m_symbolStorage(symbolStorage),
m_pathWatcher(pathWatcher)
m_pathWatcher(pathWatcher),
m_filePathCache(filePathCache),
m_transactionInterface(transactionInterface)
{
pathWatcher.setNotifier(this);
}
void SymbolIndexer::updateProjectParts(V2::ProjectPartContainers &&projectParts,
V2::FileContainers &&generatedFiles)
void SymbolIndexer::updateProjectParts(V2::ProjectPartContainers &&projectParts, V2::FileContainers &&generatedFiles)
{
for (V2::ProjectPartContainer &projectPart : projectParts)
updateProjectPart(std::move(projectPart), generatedFiles);
}
void SymbolIndexer::updateProjectPart(V2::ProjectPartContainer &&projectPart,
const V2::FileContainers &generatedFiles)
{
m_symbolsCollector.clear();
for (const V2::ProjectPartContainer &projectPart : projectParts)
m_symbolsCollector.addFiles(projectPart.sourcePaths(), projectPart.arguments());
m_symbolsCollector.addFiles(projectPart.sourcePathIds(), projectPart.arguments());
m_symbolsCollector.addUnsavedFiles(generatedFiles);
m_symbolsCollector.collectSymbols();
Sqlite::ImmediateTransaction transaction{m_transactionInterface};
m_symbolStorage.addSymbolsAndSourceLocations(m_symbolsCollector.symbols(),
m_symbolsCollector.sourceLocations());
m_symbolStorage.insertOrUpdateProjectPart(projectPart.projectPartId(),
projectPart.arguments());
m_symbolStorage.updateProjectPartSources(projectPart.projectPartId(),
m_symbolsCollector.sourceFiles());
transaction.commit();
}
void SymbolIndexer::pathsWithIdsChanged(const Utils::SmallStringVector &)

View File

@@ -39,10 +39,14 @@ class SymbolIndexer : public ClangPathWatcherNotifier
public:
SymbolIndexer(SymbolsCollectorInterface &symbolsCollector,
SymbolStorageInterface &symbolStorage,
ClangPathWatcherInterface &pathWatcher);
ClangPathWatcherInterface &pathWatcher,
FilePathCachingInterface &filePathCache,
Sqlite::TransactionInterface &transactionInterface);
void updateProjectParts(V2::ProjectPartContainers &&projectParts,
V2::FileContainers &&generatedFiles);
void updateProjectPart(V2::ProjectPartContainer &&projectPart,
const V2::FileContainers &generatedFiles);
void pathsWithIdsChanged(const Utils::SmallStringVector &ids) override;
void pathsChanged(const FilePathIds &filePathIds) override;
@@ -51,6 +55,8 @@ private:
SymbolsCollectorInterface &m_symbolsCollector;
SymbolStorageInterface &m_symbolStorage;
ClangPathWatcherInterface &m_pathWatcher;
FilePathCachingInterface &m_filePathCache;
Sqlite::TransactionInterface &m_transactionInterface;
};
} // namespace ClangBackEnd

View File

@@ -75,7 +75,7 @@ private:
StatementFactory m_statementFactory;
Storage m_symbolStorage{m_statementFactory, m_filePathCache};
ClangPathWatcher<QFileSystemWatcher, QTimer> m_sourceWatcher{m_filePathCache};
SymbolIndexer m_indexer{m_collector, m_symbolStorage, m_sourceWatcher};
SymbolIndexer m_indexer{m_collector, m_symbolStorage, m_sourceWatcher, m_filePathCache, m_statementFactory.database};
};
} // namespace ClangBackEnd

View File

@@ -28,15 +28,17 @@
namespace ClangBackEnd {
SymbolsCollector::SymbolsCollector(FilePathCachingInterface &filePathCache)
: m_collectSymbolsAction(filePathCache),
m_collectMacrosSourceFileCallbacks(filePathCache)
: m_collectSymbolsAction(m_symbolEntries, m_sourceLocationEntries, filePathCache),
m_collectMacrosSourceFileCallbacks(m_symbolEntries, m_sourceLocationEntries, filePathCache),
m_filePathCache(filePathCache)
{
}
void SymbolsCollector::addFiles(const Utils::PathStringVector &filePaths, const Utils::SmallStringVector &arguments)
void SymbolsCollector::addFiles(const FilePathIds &filePathIds,
const Utils::SmallStringVector &arguments)
{
m_clangTool.addFiles(filePaths, arguments);
m_collectMacrosSourceFileCallbacks.addSourceFiles(filePaths);
m_clangTool.addFiles(m_filePathCache.filePaths(filePathIds), arguments);
m_collectMacrosSourceFileCallbacks.addSourceFiles(filePathIds);
}
void SymbolsCollector::addUnsavedFiles(const V2::FileContainers &unsavedFiles)
@@ -47,8 +49,8 @@ void SymbolsCollector::addUnsavedFiles(const V2::FileContainers &unsavedFiles)
void SymbolsCollector::clear()
{
m_collectMacrosSourceFileCallbacks.clearSourceFiles();
m_collectSymbolsAction.clear();
m_symbolEntries.clear();
m_sourceLocationEntries.clear();
m_clangTool = ClangTool();
}
@@ -75,4 +77,9 @@ const FilePathIds &SymbolsCollector::sourceFiles() const
return m_collectMacrosSourceFileCallbacks.sourceFiles();
}
const UsedDefines &SymbolsCollector::usedDefines() const
{
return m_collectMacrosSourceFileCallbacks.usedDefines();
}
} // namespace ClangBackEnd

View File

@@ -29,7 +29,6 @@
#include "collectmacrossourcefilecallbacks.h"
#include "collectsymbolsaction.h"
#include "symbolscollectorinterface.h"
#include "symbolentry.h"
#include <filepathcachingfwd.h>
@@ -40,7 +39,7 @@ class SymbolsCollector : public SymbolsCollectorInterface
public:
SymbolsCollector(FilePathCachingInterface &filePathCache);
void addFiles(const Utils::PathStringVector &filePaths,
void addFiles(const FilePathIds &filePathIds,
const Utils::SmallStringVector &arguments) override;
void addUnsavedFiles(const V2::FileContainers &unsavedFiles) override;
@@ -52,11 +51,15 @@ public:
const SymbolEntries &symbols() const override;
const SourceLocationEntries &sourceLocations() const override;
const FilePathIds &sourceFiles() const override;
const UsedDefines &usedDefines() const override;
private:
ClangTool m_clangTool;
SymbolEntries m_symbolEntries;
SourceLocationEntries m_sourceLocationEntries;
CollectSymbolsAction m_collectSymbolsAction;
CollectMacrosSourceFileCallbacks m_collectMacrosSourceFileCallbacks;
FilePathCachingInterface &m_filePathCache;
};
} // namespace ClangBackEnd

View File

@@ -27,6 +27,7 @@
#include "symbolentry.h"
#include "sourcelocationentry.h"
#include "useddefines.h"
#include <filecontainerv2.h>
@@ -40,7 +41,7 @@ namespace ClangBackEnd {
class SymbolsCollectorInterface
{
public:
virtual void addFiles(const Utils::PathStringVector &filePaths,
virtual void addFiles(const FilePathIds &filePathIds,
const Utils::SmallStringVector &arguments) = 0;
virtual void addUnsavedFiles(const V2::FileContainers &unsavedFiles) = 0;
@@ -52,6 +53,7 @@ public:
virtual const SymbolEntries &symbols() const = 0;
virtual const SourceLocationEntries &sourceLocations() const = 0;
virtual const FilePathIds &sourceFiles() const = 0;
virtual const UsedDefines &usedDefines() const = 0;
};
} // namespace ClangBackEnd

View File

@@ -31,12 +31,14 @@
#include <sqlitetransaction.h>
#include <filepathcachingfwd.h>
#include <QJsonDocument>
#include <QJsonArray>
namespace ClangBackEnd {
template <typename StatementFactory>
class SymbolStorage : public SymbolStorageInterface
class SymbolStorage final : public SymbolStorageInterface
{
using Transaction = Sqlite::ImmediateTransaction<typename StatementFactory::DatabaseType>;
using ReadStatement = typename StatementFactory::ReadStatementType;
using WriteStatement = typename StatementFactory::WriteStatementType;
using Database = typename StatementFactory::DatabaseType;
@@ -52,8 +54,6 @@ public:
void addSymbolsAndSourceLocations(const SymbolEntries &symbolEntries,
const SourceLocationEntries &sourceLocations) override
{
Transaction transaction{m_statementFactory.database};
fillTemporarySymbolsTable(symbolEntries);
fillTemporaryLocationsTable(sourceLocations);
addNewSymbolsToSymbols();
@@ -63,8 +63,50 @@ public:
insertNewLocationsInLocations();
deleteNewSymbolsTable();
deleteNewLocationsTable();
}
transaction.commit();
void insertOrUpdateProjectPart(Utils::SmallStringView projectPartName,
const Utils::SmallStringVector &commandLineArguments) override
{
m_statementFactory.database.setLastInsertedRowId(-1);
Utils::SmallString compilerArguementsAsJson = toJson(commandLineArguments);
WriteStatement &insertStatement = m_statementFactory.insertProjectPart;
insertStatement.write(projectPartName, compilerArguementsAsJson);
if (m_statementFactory.database.lastInsertedRowId() == -1) {
WriteStatement &updateStatement = m_statementFactory.updateProjectPart;
updateStatement.write(compilerArguementsAsJson, projectPartName);
}
}
void updateProjectPartSources(Utils::SmallStringView projectPartName,
const FilePathIds &sourceFilePathIds) override
{
ReadStatement &getProjectPartIdStatement = m_statementFactory.getProjectPartId;
int projectPartId = getProjectPartIdStatement.template value<int>(projectPartName).value();
WriteStatement &deleteStatement = m_statementFactory.deleteAllProjectPartsSourcesWithProjectPartId;
deleteStatement.write(projectPartId);
WriteStatement &insertStatement = m_statementFactory.insertProjectPartSources;
for (const FilePathId &sourceFilePathId : sourceFilePathIds)
insertStatement.write(projectPartId, sourceFilePathId.filePathId);
}
static Utils::SmallString toJson(const Utils::SmallStringVector &strings)
{
QJsonDocument document;
QJsonArray array;
std::transform(strings.begin(), strings.end(), std::back_inserter(array), [] (const auto &string) {
return QJsonValue(string.data());
});
document.setArray(array);
return document.toJson(QJsonDocument::Compact);
}
void fillTemporarySymbolsTable(const SymbolEntries &symbolEntries)
@@ -84,8 +126,8 @@ public:
for (const auto &locationsEntry : sourceLocations) {
statement.write(locationsEntry.symbolId,
locationsEntry.line,
locationsEntry.column,
locationsEntry.lineColumn.line,
locationsEntry.lineColumn.column,
locationsEntry.filePathId.filePathId);
}
}

View File

@@ -0,0 +1,34 @@
/****************************************************************************
**
** Copyright (C) 2018 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 "symbolstorageinterface.h"
namespace ClangBackEnd {
SymbolStorageInterface::~SymbolStorageInterface()
{
}
}

View File

@@ -25,16 +25,28 @@
#pragma once
#include "projectpartentry.h"
#include "sourcelocationentry.h"
#include "symbolentry.h"
#include <sqlitetransaction.h>
namespace ClangBackEnd {
class SymbolStorageInterface
{
public:
SymbolStorageInterface() = default;
virtual ~SymbolStorageInterface();
SymbolStorageInterface(const SymbolStorageInterface &) = delete;
SymbolStorageInterface &operator=(const SymbolStorageInterface &) = delete;
virtual void addSymbolsAndSourceLocations(const SymbolEntries &symbolEntries,
const SourceLocationEntries &sourceLocations) = 0;
virtual void insertOrUpdateProjectPart(Utils::SmallStringView projectPartName,
const Utils::SmallStringVector &commandLineArguments) = 0;
virtual void updateProjectPartSources(Utils::SmallStringView projectPartName,
const FilePathIds &sourceFilePathIds) = 0;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,121 @@
/****************************************************************************
**
** Copyright (C) 2018 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.
**
****************************************************************************/
#pragma once
#include "sourcelocationsutils.h"
#include <filepathcachinginterface.h>
#include <utils/linecolumn.h>
#include <utils/optional.h>
#include <clang/Basic/SourceLocation.h>
#include <clang/Basic/SourceManager.h>
#include <clang/Index/USRGeneration.h>
#include <llvm/ADT/SmallVector.h>
namespace ClangBackEnd {
class SymbolsVisitorBase
{
public:
SymbolsVisitorBase(FilePathCachingInterface &filePathCache,
const clang::SourceManager &sourceManager)
: m_filePathCache(filePathCache),
m_sourceManager(sourceManager)
{}
FilePathId filePathId(clang::SourceLocation sourceLocation)
{
uint clangFileId = m_sourceManager.getFileID(sourceLocation).getHashValue();
auto found = m_filePathIndices.find(clangFileId);
if (found != m_filePathIndices.end())
return found->second;
auto filePath = m_sourceManager.getFilename(sourceLocation);
if (filePath.size() > 0) {
FilePathId filePathId = m_filePathCache.filePathId(FilePath::fromNativeFilePath(absolutePath(filePath)));
m_filePathIndices.emplace(clangFileId, filePathId);
return filePathId;
}
return {};
}
Utils::LineColumn lineColum(clang::SourceLocation sourceLocation)
{
return {int(m_sourceManager.getSpellingLineNumber(sourceLocation)),
int(m_sourceManager.getSpellingColumnNumber(sourceLocation))};
}
static Utils::optional<Utils::PathString> generateUSR(const clang::Decl *declaration)
{
llvm::SmallVector<char, 128> usr;
Utils::optional<Utils::PathString> usrOptional;
bool wasNotWorking = clang::index::generateUSRForDecl(declaration, usr);
if (!wasNotWorking)
usrOptional.emplace(usr.data(), usr.size());
return usrOptional;
}
Utils::optional<Utils::PathString> generateUSR(clang::StringRef macroName,
clang::SourceLocation sourceLocation)
{
llvm::SmallVector<char, 128> usr;
Utils::optional<Utils::PathString> usrOptional;
bool wasNotWorking = clang::index::generateUSRForMacro(macroName,
sourceLocation,
m_sourceManager,
usr);
if (!wasNotWorking)
usrOptional.emplace(usr.data(), usr.size());
return usrOptional;
}
static SymbolIndex toSymbolIndex(const void *pointer)
{
return SymbolIndex(reinterpret_cast<std::uintptr_t>(pointer));
}
protected:
std::unordered_map<uint, FilePathId> m_filePathIndices;
FilePathCachingInterface &m_filePathCache;
const clang::SourceManager &m_sourceManager;
};
} // namespace ClangBackend

View File

@@ -0,0 +1,66 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#pragma once
#include <filepathid.h>
#include <utils/smallstring.h>
#include <vector>
namespace ClangBackEnd {
class UsedDefine
{
public:
UsedDefine(Utils::SmallStringView defineName, FilePathId filePathId)
: defineName(defineName),
filePathId(filePathId)
{}
friend bool operator<(const UsedDefine &first, const UsedDefine &second)
{
return std::tie(first.filePathId, first.defineName)
< std::tie(second.filePathId, second.defineName);
}
friend bool operator==(const UsedDefine &first, const UsedDefine &second)
{
return first.filePathId == second.filePathId && first.defineName == second.defineName;
}
friend bool operator!=(const UsedDefine &first, const UsedDefine &second)
{
return !(first == second);
}
public:
Utils::SmallString defineName;
FilePathId filePathId;
};
using UsedDefines = std::vector<UsedDefine>;
} // ClangBackEnd