llvm-project/clang-tools-extra/clangd/index/SymbolCollector.cpp

101 lines
3.6 KiB
C++

//===--- SymbolCollector.cpp -------------------------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "SymbolCollector.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Index/IndexSymbol.h"
#include "clang/Index/USRGeneration.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
namespace clang {
namespace clangd {
namespace {
// Make the Path absolute using the current working directory of the given
// SourceManager if the Path is not an absolute path.
//
// The Path can be a path relative to the build directory, or retrieved from
// the SourceManager.
std::string makeAbsolutePath(const SourceManager &SM, StringRef Path) {
llvm::SmallString<128> AbsolutePath(Path);
if (std::error_code EC =
SM.getFileManager().getVirtualFileSystem()->makeAbsolute(
AbsolutePath))
llvm::errs() << "Warning: could not make absolute file: '" << EC.message()
<< '\n';
// Handle the symbolic link path case where the current working directory
// (getCurrentWorkingDirectory) is a symlink./ We always want to the real
// file path (instead of the symlink path) for the C++ symbols.
//
// Consider the following example:
//
// src dir: /project/src/foo.h
// current working directory (symlink): /tmp/build -> /project/src/
//
// The file path of Symbol is "/project/src/foo.h" instead of
// "/tmp/build/foo.h"
const DirectoryEntry *Dir = SM.getFileManager().getDirectory(
llvm::sys::path::parent_path(AbsolutePath.str()));
if (Dir) {
StringRef DirName = SM.getFileManager().getCanonicalName(Dir);
SmallVector<char, 128> AbsoluteFilename;
llvm::sys::path::append(AbsoluteFilename, DirName,
llvm::sys::path::filename(AbsolutePath.str()));
return llvm::StringRef(AbsoluteFilename.data(), AbsoluteFilename.size())
.str();
}
return AbsolutePath.str();
}
} // namespace
// Always return true to continue indexing.
bool SymbolCollector::handleDeclOccurence(
const Decl *D, index::SymbolRoleSet Roles,
ArrayRef<index::SymbolRelation> Relations, FileID FID, unsigned Offset,
index::IndexDataConsumer::ASTNodeInfo ASTNode) {
// FIXME: collect all symbol references.
if (!(Roles & static_cast<unsigned>(index::SymbolRole::Declaration) ||
Roles & static_cast<unsigned>(index::SymbolRole::Definition)))
return true;
if (const NamedDecl *ND = llvm::dyn_cast<NamedDecl>(D)) {
// FIXME: Should we include the internal linkage symbols?
if (!ND->hasExternalFormalLinkage() || ND->isInAnonymousNamespace())
return true;
llvm::SmallVector<char, 128> Buff;
if (index::generateUSRForDecl(ND, Buff))
return true;
std::string USR(Buff.data(), Buff.size());
auto ID = SymbolID(USR);
if (Symbols.find(ID) != Symbols.end())
return true;
auto &SM = ND->getASTContext().getSourceManager();
SymbolLocation Location = {
makeAbsolutePath(SM, SM.getFilename(D->getLocation())),
SM.getFileOffset(D->getLocStart()), SM.getFileOffset(D->getLocEnd())};
Symbols.insert({std::move(ID), ND->getQualifiedNameAsString(),
index::getSymbolInfo(D), std::move(Location)});
}
return true;
}
void SymbolCollector::finish() { Symbols.freeze(); }
} // namespace clangd
} // namespace clang