| //===--- 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; |
| } |
| } |