Clang: Collect source dependencies

It is quite easy because we track the include directives in the
preprocessor callbacks.

Change-Id: I2d7bd67b31f50c0d8d4a46c57e83dffa0c558dc7
Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
This commit is contained in:
Marco Bubke
2018-01-31 13:53:57 +01:00
parent b2d3951bde
commit 048224bef1
13 changed files with 93 additions and 16 deletions

View File

@@ -27,6 +27,7 @@
#include "fileinformation.h" #include "fileinformation.h"
#include "symbolsvisitorbase.h" #include "symbolsvisitorbase.h"
#include "sourcedependency.h"
#include "sourcelocationsutils.h" #include "sourcelocationsutils.h"
#include "sourcelocationentry.h" #include "sourcelocationentry.h"
#include "symbolentry.h" #include "symbolentry.h"
@@ -50,6 +51,7 @@ public:
FilePathIds &sourceFiles, FilePathIds &sourceFiles,
UsedMacros &usedMacros, UsedMacros &usedMacros,
FileInformations &fileInformations, FileInformations &fileInformations,
SourceDependencies &sourceDependencies,
FilePathCachingInterface &filePathCache, FilePathCachingInterface &filePathCache,
const clang::SourceManager &sourceManager, const clang::SourceManager &sourceManager,
std::shared_ptr<clang::Preprocessor> &&preprocessor) std::shared_ptr<clang::Preprocessor> &&preprocessor)
@@ -59,7 +61,8 @@ public:
m_sourceLocationEntries(sourceLocationEntries), m_sourceLocationEntries(sourceLocationEntries),
m_sourceFiles(sourceFiles), m_sourceFiles(sourceFiles),
m_usedMacros(usedMacros), m_usedMacros(usedMacros),
m_fileInformations(fileInformations) m_fileInformations(fileInformations),
m_sourceDependencies(sourceDependencies)
{ {
} }
@@ -73,14 +76,15 @@ public:
const clang::FileEntry *fileEntry = m_sourceManager.getFileEntryForID( const clang::FileEntry *fileEntry = m_sourceManager.getFileEntryForID(
m_sourceManager.getFileID(sourceLocation)); m_sourceManager.getFileID(sourceLocation));
if (fileEntry) { if (fileEntry) {
m_fileInformations.emplace_back(filePathId(sourceLocation), m_fileInformations.emplace_back(filePathId(fileEntry),
fileEntry->getSize(), fileEntry->getSize(),
fileEntry->getModificationTime()); fileEntry->getModificationTime());
addSourceFile(fileEntry);
} }
} }
} }
void InclusionDirective(clang::SourceLocation /*hashLocation*/, void InclusionDirective(clang::SourceLocation hashLocation,
const clang::Token &/*includeToken*/, const clang::Token &/*includeToken*/,
llvm::StringRef /*fileName*/, llvm::StringRef /*fileName*/,
bool /*isAngled*/, bool /*isAngled*/,
@@ -91,7 +95,7 @@ public:
const clang::Module * /*imported*/) override const clang::Module * /*imported*/) override
{ {
if (!m_skipInclude && file) if (!m_skipInclude && file)
addSourceFile(file); addSourceDependency(file, hashLocation);
m_skipInclude = false; m_skipInclude = false;
} }
@@ -268,18 +272,26 @@ public:
void addSourceFile(const clang::FileEntry *file) void addSourceFile(const clang::FileEntry *file)
{ {
auto filePathId = m_filePathCache.filePathId( auto id = filePathId(file);
FilePath::fromNativeFilePath(absolutePath(file->getName())));
auto found = std::find(m_sourceFiles.begin(), m_sourceFiles.end(), filePathId); auto found = std::find(m_sourceFiles.begin(), m_sourceFiles.end(), id);
if (found == m_sourceFiles.end() || *found != filePathId) if (found == m_sourceFiles.end() || *found != id)
m_sourceFiles.insert(found, filePathId); m_sourceFiles.insert(found, id);
}
void addSourceDependency(const clang::FileEntry *file, clang::SourceLocation includeLocation)
{
auto includeFilePathId = filePathId(includeLocation);
auto includedFilePathId = filePathId(file);
m_sourceDependencies.emplace_back(includeFilePathId, includedFilePathId);
} }
private: private:
UsedMacros m_maybeUsedMacros; UsedMacros m_maybeUsedMacros;
std::shared_ptr<clang::Preprocessor> m_preprocessor; std::shared_ptr<clang::Preprocessor> m_preprocessor;
SourceDependencies &m_sourceDependencies;
SymbolEntries &m_symbolEntries; SymbolEntries &m_symbolEntries;
SourceLocationEntries &m_sourceLocationEntries; SourceLocationEntries &m_sourceLocationEntries;
FilePathIds &m_sourceFiles; FilePathIds &m_sourceFiles;

View File

@@ -39,6 +39,7 @@ bool CollectMacrosSourceFileCallbacks::handleBeginSource(clang::CompilerInstance
m_sourceFiles, m_sourceFiles,
m_usedMacros, m_usedMacros,
m_fileInformations, m_fileInformations,
m_sourceDependencies,
m_filePathCache, m_filePathCache,
compilerInstance.getSourceManager(), compilerInstance.getSourceManager(),
compilerInstance.getPreprocessorPtr()); compilerInstance.getPreprocessorPtr());

View File

@@ -26,6 +26,7 @@
#pragma once #pragma once
#include "fileinformation.h" #include "fileinformation.h"
#include "sourcedependency.h"
#include "sourcelocationentry.h" #include "sourcelocationentry.h"
#include "symbolentry.h" #include "symbolentry.h"
#include "usedmacro.h" #include "usedmacro.h"
@@ -77,10 +78,16 @@ public:
return m_fileInformations; return m_fileInformations;
} }
const SourceDependencies &sourceDependencies() const
{
return m_sourceDependencies;
}
private: private:
FilePathIds m_sourceFiles; FilePathIds m_sourceFiles;
UsedMacros m_usedMacros; UsedMacros m_usedMacros;
FileInformations m_fileInformations; FileInformations m_fileInformations;
SourceDependencies m_sourceDependencies;
SymbolEntries &m_symbolEntries; SymbolEntries &m_symbolEntries;
SourceLocationEntries &m_sourceLocationEntries; SourceLocationEntries &m_sourceLocationEntries;
FilePathCachingInterface &m_filePathCache; FilePathCachingInterface &m_filePathCache;

View File

@@ -87,4 +87,9 @@ const FileInformations &SymbolsCollector::fileInformations() const
return m_collectMacrosSourceFileCallbacks.fileInformations(); return m_collectMacrosSourceFileCallbacks.fileInformations();
} }
const SourceDependencies &SymbolsCollector::sourceDependencies() const
{
return m_collectMacrosSourceFileCallbacks.sourceDependencies();
}
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -53,6 +53,7 @@ public:
const FilePathIds &sourceFiles() const override; const FilePathIds &sourceFiles() const override;
const UsedMacros &usedMacros() const override; const UsedMacros &usedMacros() const override;
const FileInformations &fileInformations() const override; const FileInformations &fileInformations() const override;
const SourceDependencies &sourceDependencies() const override;
private: private:
ClangTool m_clangTool; ClangTool m_clangTool;

View File

@@ -27,6 +27,7 @@
#include "fileinformation.h" #include "fileinformation.h"
#include "symbolentry.h" #include "symbolentry.h"
#include "sourcedependency.h"
#include "sourcelocationentry.h" #include "sourcelocationentry.h"
#include "usedmacro.h" #include "usedmacro.h"
@@ -56,6 +57,7 @@ public:
virtual const FilePathIds &sourceFiles() const = 0; virtual const FilePathIds &sourceFiles() const = 0;
virtual const UsedMacros &usedMacros() const = 0; virtual const UsedMacros &usedMacros() const = 0;
virtual const FileInformations &fileInformations() const = 0; virtual const FileInformations &fileInformations() const = 0;
virtual const SourceDependencies &sourceDependencies() const = 0;
}; };
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -50,22 +50,30 @@ public:
FilePathId filePathId(clang::SourceLocation sourceLocation) FilePathId filePathId(clang::SourceLocation sourceLocation)
{ {
uint clangFileId = m_sourceManager.getFileID(sourceLocation).getHashValue(); clang::FileID clangFileId = m_sourceManager.getFileID(sourceLocation);
const clang::FileEntry *fileEntry = m_sourceManager.getFileEntryForID(clangFileId);
auto found = m_filePathIndices.find(clangFileId); return filePathId(fileEntry);
}
FilePathId filePathId(const clang::FileEntry *fileEntry)
{
if (fileEntry) {
uint fileHash = fileEntry->getUID();
auto found = m_filePathIndices.find(fileHash);
if (found != m_filePathIndices.end()) if (found != m_filePathIndices.end())
return found->second; return found->second;
auto filePath = m_sourceManager.getFilename(sourceLocation); auto filePath = fileEntry->getName();
if (filePath.size() > 0) {
FilePathId filePathId = m_filePathCache.filePathId(FilePath::fromNativeFilePath(absolutePath(filePath))); FilePathId filePathId = m_filePathCache.filePathId(FilePath::fromNativeFilePath(absolutePath(filePath)));
m_filePathIndices.emplace(clangFileId, filePathId); m_filePathIndices.emplace(fileHash, filePathId);
return filePathId; return filePathId;
} }
return {}; return {};
} }

View File

@@ -0,0 +1,3 @@
#pragma once
#include "symbolscollector_header2.h"

View File

@@ -0,0 +1,5 @@
#include "symbolscollector_header1.h"
#include "symbolscollector_header3.h"
void function();

View File

@@ -39,6 +39,7 @@
#include <filepath.h> #include <filepath.h>
#include <nativefilepath.h> #include <nativefilepath.h>
#include <precompiledheadersupdatedmessage.h> #include <precompiledheadersupdatedmessage.h>
#include <sourcedependency.h>
#include <sourcelocationentry.h> #include <sourcelocationentry.h>
#include <sourcelocationscontainer.h> #include <sourcelocationscontainer.h>
#include <tokeninfos.h> #include <tokeninfos.h>
@@ -838,6 +839,15 @@ std::ostream &operator<<(std::ostream &out, const FileInformation &fileInformati
<< ")"; << ")";
} }
std::ostream &operator<<(std::ostream &out, const SourceDependency &sourceDependency)
{
return out << "("
<< sourceDependency.filePathId
<< ", "
<< sourceDependency.dependencyFilePathId
<< ")";
}
void PrintTo(const FilePath &filePath, ::std::ostream *os) void PrintTo(const FilePath &filePath, ::std::ostream *os)
{ {
*os << filePath; *os << filePath;

View File

@@ -134,6 +134,7 @@ class ToolTipInfo;
class ProjectPartEntry; class ProjectPartEntry;
class UsedMacro; class UsedMacro;
class FileInformation; class FileInformation;
class SourceDependency;
std::ostream &operator<<(std::ostream &out, const SourceLocationEntry &entry); std::ostream &operator<<(std::ostream &out, const SourceLocationEntry &entry);
std::ostream &operator<<(std::ostream &out, const IdPaths &idPaths); std::ostream &operator<<(std::ostream &out, const IdPaths &idPaths);
@@ -198,6 +199,7 @@ std::ostream &operator<<(std::ostream &out, const NativeFilePathView &nativeFile
std::ostream &operator<<(std::ostream &out, const ProjectPartEntry &projectPartEntry); std::ostream &operator<<(std::ostream &out, const ProjectPartEntry &projectPartEntry);
std::ostream &operator<<(std::ostream &out, const UsedMacro &usedMacro); std::ostream &operator<<(std::ostream &out, const UsedMacro &usedMacro);
std::ostream &operator<<(std::ostream &out, const FileInformation &fileInformation); std::ostream &operator<<(std::ostream &out, const FileInformation &fileInformation);
std::ostream &operator<<(std::ostream &out, const SourceDependency &sourceDependency);
void PrintTo(const FilePath &filePath, ::std::ostream *os); void PrintTo(const FilePath &filePath, ::std::ostream *os);
void PrintTo(const FilePathView &filePathView, ::std::ostream *os); void PrintTo(const FilePathView &filePathView, ::std::ostream *os);

View File

@@ -59,4 +59,7 @@ public:
MOCK_CONST_METHOD0(fileInformations, MOCK_CONST_METHOD0(fileInformations,
const ClangBackEnd::FileInformations &()); const ClangBackEnd::FileInformations &());
MOCK_CONST_METHOD0(sourceDependencies,
const ClangBackEnd::SourceDependencies &());
}; };

View File

@@ -50,6 +50,7 @@ using ClangBackEnd::FilePath;
using ClangBackEnd::FilePathId; using ClangBackEnd::FilePathId;
using ClangBackEnd::FilePathCaching; using ClangBackEnd::FilePathCaching;
using ClangBackEnd::V2::FileContainers; using ClangBackEnd::V2::FileContainers;
using ClangBackEnd::SourceDependency;
using ClangBackEnd::SourceLocationEntry; using ClangBackEnd::SourceLocationEntry;
using ClangBackEnd::SymbolEntry; using ClangBackEnd::SymbolEntry;
using ClangBackEnd::SymbolType; using ClangBackEnd::SymbolType;
@@ -563,4 +564,21 @@ TEST_F(SymbolsCollector, CollectFileInformations)
fileInformation(TESTDATA_DIR "/symbolscollector_header2.h"))); fileInformation(TESTDATA_DIR "/symbolscollector_header2.h")));
} }
TEST_F(SymbolsCollector, CollectSourceDependencies)
{
auto mainFileId = filePathId(TESTDATA_DIR "/symbolscollector_main2.cpp");
auto header1FileId = filePathId(TESTDATA_DIR "/symbolscollector_header1.h");
auto header2FileId = filePathId(TESTDATA_DIR "/symbolscollector_header2.h");
auto header3FileId = filePathId(TESTDATA_DIR "/symbolscollector_header3.h");
collector.addFiles({mainFileId}, {"cc", "-I" TESTDATA_DIR});
collector.collectSymbols();
ASSERT_THAT(collector.sourceDependencies(),
UnorderedElementsAre(SourceDependency(mainFileId, header1FileId),
SourceDependency(mainFileId, header3FileId),
SourceDependency(header3FileId, header2FileId),
SourceDependency(header1FileId, header2FileId)));
}
} }