blob: 612ef1b5b41a0fc40145c517da94d0584e33fe45 [file] [log] [blame]
//===--- ClangIndexRecordWriter.cpp - Index record serialization ----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "ClangIndexRecordWriter.h"
#include "FileIndexRecord.h"
#include "clang/Index/IndexSymbol.h"
#include "clang/Index/IndexRecordReader.h"
#include "clang/Index/USRGeneration.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
using namespace clang;
using namespace clang::index;
StringRef ClangIndexRecordWriter::getUSR(const Decl *D) {
assert(D->isCanonicalDecl());
auto Insert = USRByDecl.insert(std::make_pair(D, StringRef()));
if (Insert.second) {
Insert.first->second = getUSRNonCached(D);
}
return Insert.first->second;
}
StringRef ClangIndexRecordWriter::getUSRNonCached(const Decl *D) {
SmallString<256> Buf;
bool Ignore = generateUSRForDecl(D, Buf);
if (Ignore)
return StringRef();
StringRef USR = Buf.str();
char *Ptr = Allocator.Allocate<char>(USR.size());
std::copy(USR.begin(), USR.end(), Ptr);
return StringRef(Ptr, USR.size());
}
ClangIndexRecordWriter::ClangIndexRecordWriter(ASTContext &Ctx,
RecordingOptions Opts)
: Impl(Opts.DataDirPath), Ctx(Ctx), RecordOpts(std::move(Opts)),
Hasher(Ctx) {
if (Opts.RecordSymbolCodeGenName)
CGNameGen.reset(new CodegenNameGenerator(Ctx));
}
ClangIndexRecordWriter::~ClangIndexRecordWriter() {}
bool ClangIndexRecordWriter::writeRecord(StringRef Filename,
const FileIndexRecord &IdxRecord,
std::string &Error,
std::string *OutRecordFile) {
auto RecordHash = Hasher.hashRecord(IdxRecord);
switch (Impl.beginRecord(Filename, RecordHash, Error, OutRecordFile)) {
case IndexRecordWriter::Result::Success:
break; // Continue writing.
case IndexRecordWriter::Result::Failure:
return true;
case IndexRecordWriter::Result::AlreadyExists:
return false;
}
ASTContext &Ctx = getASTContext();
SourceManager &SM = Ctx.getSourceManager();
FileID FID = IdxRecord.getFileID();
auto getLineCol = [&](unsigned Offset) -> std::pair<unsigned, unsigned> {
unsigned LineNo = SM.getLineNumber(FID, Offset);
unsigned ColNo = SM.getColumnNumber(FID, Offset);
return std::make_pair(LineNo, ColNo);
};
for (auto &Occur : IdxRecord.getDeclOccurrences()) {
unsigned Line, Col;
std::tie(Line, Col) = getLineCol(Occur.Offset);
SmallVector<writer::SymbolRelation, 3> Related;
Related.reserve(Occur.Relations.size());
for (auto &Rel : Occur.Relations)
Related.push_back(writer::SymbolRelation{Rel.RelatedSymbol, Rel.Roles});
Impl.addOccurrence(Occur.Dcl, Occur.Roles, Line, Col, Related);
}
PrintingPolicy Policy(Ctx.getLangOpts());
Policy.SuppressTemplateArgsInCXXConstructors = true;
auto Result = Impl.endRecord(Error,
[&](writer::OpaqueDecl OD, SmallVectorImpl<char> &Scratch) {
const Decl *D = static_cast<const Decl *>(OD);
auto Info = getSymbolInfo(D);
writer::Symbol Sym;
Sym.SymInfo = Info;
auto *ND = dyn_cast<NamedDecl>(D);
if (ND) {
llvm::raw_svector_ostream OS(Scratch);
DeclarationName DeclName = ND->getDeclName();
if (!DeclName.isEmpty())
DeclName.print(OS, Policy);
}
unsigned NameLen = Scratch.size();
Sym.Name = StringRef(Scratch.data(), NameLen);
Sym.USR = getUSR(D);
assert(!Sym.USR.empty() && "Recorded decl without USR!");
if (CGNameGen && ND) {
llvm::raw_svector_ostream OS(Scratch);
CGNameGen->writeName(ND, OS);
}
unsigned CGNameLen = Scratch.size() - NameLen;
Sym.CodeGenName = StringRef(Scratch.data() + NameLen, CGNameLen);
return Sym;
});
switch (Result) {
case IndexRecordWriter::Result::Success:
case IndexRecordWriter::Result::AlreadyExists:
return false;
case IndexRecordWriter::Result::Failure:
return true;
}
}