llvm-project/clang/lib/Index/FileIndexRecord.cpp
Ben Langmuir 773ad55a39 [index] Fix performance regression with indexing macros
When using FileIndexRecord with macros, symbol references can be seen
out of source order, which was causing a regression to insert the
symbols into a vector. Instead, we now lazily sort the vector. The
impact is small on most code, but in very large files with many macro
references (M) near the beginning of the file followed by many decl
references (D) it was O(M*D). A particularly bad protobuf-generated
header was observed with a 100% regression in practice.

rdar://78628133
2021-06-16 10:16:26 -07:00

83 lines
2.8 KiB
C++

//===--- FileIndexRecord.cpp - Index data per file --------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "FileIndexRecord.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Path.h"
using namespace clang;
using namespace clang::index;
ArrayRef<DeclOccurrence>
FileIndexRecord::getDeclOccurrencesSortedByOffset() const {
if (!IsSorted) {
llvm::stable_sort(Decls,
[](const DeclOccurrence &A, const DeclOccurrence &B) {
return A.Offset < B.Offset;
});
IsSorted = true;
}
return Decls;
}
void FileIndexRecord::addDeclOccurence(SymbolRoleSet Roles, unsigned Offset,
const Decl *D,
ArrayRef<SymbolRelation> Relations) {
assert(D->isCanonicalDecl() &&
"Occurrences should be associated with their canonical decl");
IsSorted = false;
Decls.emplace_back(Roles, Offset, D, Relations);
}
void FileIndexRecord::addMacroOccurence(SymbolRoleSet Roles, unsigned Offset,
const IdentifierInfo *Name,
const MacroInfo *MI) {
IsSorted = false;
Decls.emplace_back(Roles, Offset, Name, MI);
}
void FileIndexRecord::removeHeaderGuardMacros() {
auto It =
std::remove_if(Decls.begin(), Decls.end(), [](const DeclOccurrence &D) {
if (const auto *MI = D.DeclOrMacro.dyn_cast<const MacroInfo *>())
return MI->isUsedForHeaderGuard();
return false;
});
Decls.erase(It, Decls.end());
}
void FileIndexRecord::print(llvm::raw_ostream &OS, SourceManager &SM) const {
OS << "DECLS BEGIN ---\n";
for (auto &DclInfo : Decls) {
if (const auto *D = DclInfo.DeclOrMacro.dyn_cast<const Decl *>()) {
SourceLocation Loc = SM.getFileLoc(D->getLocation());
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
OS << llvm::sys::path::filename(PLoc.getFilename()) << ':'
<< PLoc.getLine() << ':' << PLoc.getColumn();
if (const auto *ND = dyn_cast<NamedDecl>(D)) {
OS << ' ' << ND->getDeclName();
}
} else {
const auto *MI = DclInfo.DeclOrMacro.get<const MacroInfo *>();
SourceLocation Loc = SM.getFileLoc(MI->getDefinitionLoc());
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
OS << llvm::sys::path::filename(PLoc.getFilename()) << ':'
<< PLoc.getLine() << ':' << PLoc.getColumn();
OS << ' ' << DclInfo.MacroName->getName();
}
OS << '\n';
}
OS << "DECLS END ---\n";
}