From e9005dfe794b5159d62ca552e46d1022403e6c0c Mon Sep 17 00:00:00 2001 From: Jan Korous Date: Mon, 11 Mar 2019 15:34:49 -0700 Subject: [PATCH 1/7] [clang][index-while-building][IndexRecordHasher][NFC] License --- lib/Index/IndexRecordHasher.cpp | 9 ++++----- lib/Index/IndexRecordHasher.h | 10 +++++----- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/Index/IndexRecordHasher.cpp b/lib/Index/IndexRecordHasher.cpp index ee22ec8bcf3..5bfa1e54e5e 100644 --- a/lib/Index/IndexRecordHasher.cpp +++ b/lib/Index/IndexRecordHasher.cpp @@ -1,9 +1,8 @@ -//===--- IndexRecordHasher.cpp - Index record hashing ---------------------===// +//===--- IndexRecordHasher.cpp - Index record hashing -----------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/lib/Index/IndexRecordHasher.h b/lib/Index/IndexRecordHasher.h index af3acccff52..c07ea189285 100644 --- a/lib/Index/IndexRecordHasher.h +++ b/lib/Index/IndexRecordHasher.h @@ -1,9 +1,9 @@ -//===--- IndexRecordHasher.h - Index record hashing -----------------------===// -// -// The LLVM Compiler Infrastructure +//===--- IndexRecordHasher.h - Index record hashing -------------*- C++ -*-===// + // -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// From 01ab474383dd172febeb3d98e970c2890a95d4ab Mon Sep 17 00:00:00 2001 From: Jan Korous Date: Mon, 11 Mar 2019 15:35:19 -0700 Subject: [PATCH 2/7] [clang][index-while-building][IndexRecordHasher][NFC] Doxygen --- lib/Index/IndexRecordHasher.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/Index/IndexRecordHasher.h b/lib/Index/IndexRecordHasher.h index c07ea189285..e359a1cb1f0 100644 --- a/lib/Index/IndexRecordHasher.h +++ b/lib/Index/IndexRecordHasher.h @@ -27,6 +27,8 @@ namespace clang { namespace index { class FileIndexRecord; +/// Implements hashing of AST nodes suitable for the index. +/// Caching all produced hashes. class IndexRecordHasher { ASTContext &Ctx; llvm::DenseMap HashByPtr; @@ -35,6 +37,7 @@ class IndexRecordHasher { explicit IndexRecordHasher(ASTContext &Ctx) : Ctx(Ctx) {} ASTContext &getASTContext() { return Ctx; } + /// Returns hash for all declaration occurences in \c Record. llvm::hash_code hashRecord(const FileIndexRecord &Record); llvm::hash_code hash(const Decl *D); llvm::hash_code hash(QualType Ty); From 886b77009bb017586a0133cef405be7cff222eb9 Mon Sep 17 00:00:00 2001 From: Jan Korous Date: Mon, 11 Mar 2019 15:35:44 -0700 Subject: [PATCH 3/7] [clang][index-while-building][IndexRecordHasher][NFCI] Replace macros --- lib/Index/IndexRecordHasher.cpp | 139 ++++++++++++++++---------------- 1 file changed, 69 insertions(+), 70 deletions(-) diff --git a/lib/Index/IndexRecordHasher.cpp b/lib/Index/IndexRecordHasher.cpp index 5bfa1e54e5e..cf699167138 100644 --- a/lib/Index/IndexRecordHasher.cpp +++ b/lib/Index/IndexRecordHasher.cpp @@ -13,8 +13,7 @@ #include "clang/AST/DeclVisitor.h" #include "llvm/Support/Path.h" -#define INITIAL_HASH 5381 -#define COMBINE_HASH(...) (Hash = hash_combine(Hash, __VA_ARGS__)) +constexpr size_t InitialHash = 5381; using namespace clang; using namespace clang::index; @@ -37,9 +36,9 @@ class DeclHashVisitor : public ConstDeclVisitor { hash_code VisitNamedDecl(const NamedDecl *D) { hash_code Hash = VisitDecl(D); if (auto *attr = D->getExternalSourceSymbolAttr()) { - COMBINE_HASH(hash_value(attr->getDefinedIn())); + Hash = hash_combine(Hash, hash_value(attr->getDefinedIn())); } - return COMBINE_HASH(Hasher.hash(D->getDeclName())); + return hash_combine(Hash, Hasher.hash(D->getDeclName())); } hash_code VisitTagDecl(const TagDecl *D) { @@ -49,29 +48,29 @@ class DeclHashVisitor : public ConstDeclVisitor { hash_code Hash = VisitDeclContext(D->getDeclContext()); if (D->isEmbeddedInDeclarator() && !D->isFreeStanding()) { - COMBINE_HASH(hashLoc(D->getLocation(), /*IncludeOffset=*/true)); + Hash = hash_combine(Hash, hashLoc(D->getLocation(), /*IncludeOffset=*/true)); } else - COMBINE_HASH('a'); + Hash = hash_combine(Hash, 'a'); return Hash; } hash_code Hash = VisitTypeDecl(D); - return COMBINE_HASH('T'); + return hash_combine(Hash, 'T'); } hash_code VisitClassTemplateSpecializationDecl(const ClassTemplateSpecializationDecl *D) { hash_code Hash = VisitCXXRecordDecl(D); const TemplateArgumentList &Args = D->getTemplateArgs(); - COMBINE_HASH('>'); + Hash = hash_combine(Hash, '>'); for (unsigned I = 0, N = Args.size(); I != N; ++I) { - COMBINE_HASH(computeHash(Args.get(I), Hasher)); + Hash = hash_combine(Hash, computeHash(Args.get(I), Hasher)); } return Hash; } hash_code VisitObjCContainerDecl(const ObjCContainerDecl *D) { hash_code Hash = VisitNamedDecl(D); - return COMBINE_HASH('I'); + return hash_combine(Hash, 'I'); } hash_code VisitObjCImplDecl(const ObjCImplDecl *D) { @@ -97,20 +96,20 @@ class DeclHashVisitor : public ConstDeclVisitor { return Hash; for (auto param : D->parameters()) { - COMBINE_HASH(Hasher.hash(param->getType())); + Hash = hash_combine(Hash, Hasher.hash(param->getType())); } return Hash; } hash_code VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D) { hash_code Hash = VisitNamedDecl(D); - COMBINE_HASH(Hasher.hash(D->getQualifier())); + Hash = hash_combine(Hash, Hasher.hash(D->getQualifier())); return Hash; } hash_code VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) { hash_code Hash = VisitNamedDecl(D); - COMBINE_HASH(Hasher.hash(D->getQualifier())); + Hash = hash_combine(Hash, Hasher.hash(D->getQualifier())); return Hash; } @@ -128,13 +127,13 @@ class DeclHashVisitor : public ConstDeclVisitor { if (Loc.isInvalid()) { return 0; } - hash_code Hash = INITIAL_HASH; + hash_code Hash = InitialHash; const SourceManager &SM = Hasher.getASTContext().getSourceManager(); Loc = SM.getFileLoc(Loc); const std::pair &Decomposed = SM.getDecomposedLoc(Loc); const FileEntry *FE = SM.getFileEntryForID(Decomposed.first); if (FE) { - COMBINE_HASH(llvm::sys::path::filename(FE->getName())); + Hash = hash_combine(Hash, llvm::sys::path::filename(FE->getName())); } else { // This case really isn't interesting. return 0; @@ -143,7 +142,7 @@ class DeclHashVisitor : public ConstDeclVisitor { // Use the offest into the FileID to represent the location. Using // a line/column can cause us to look back at the original source file, // which is expensive. - COMBINE_HASH(Decomposed.second); + Hash = hash_combine(Hash, Decomposed.second); } return Hash; } @@ -151,11 +150,11 @@ class DeclHashVisitor : public ConstDeclVisitor { } hash_code IndexRecordHasher::hashRecord(const FileIndexRecord &Record) { - hash_code Hash = INITIAL_HASH; + hash_code Hash = InitialHash; for (auto &Info : Record.getDeclOccurrencesSortedByOffset()) { - COMBINE_HASH(Info.Roles, Info.Offset, hash(Info.Dcl)); + Hash = hash_combine(Hash, Info.Roles, Info.Offset, hash(Info.Dcl)); for (auto &Rel : Info.Relations) { - COMBINE_HASH(hash(Rel.RelatedSymbol)); + Hash = hash_combine(Hash, hash(Rel.RelatedSymbol)); } } return Hash; @@ -186,7 +185,7 @@ hash_code IndexRecordHasher::hash(QualType NonCanTy) { hash_code IndexRecordHasher::hash(CanQualType CT) { // Do some hashing without going to the cache, for example we can avoid // storing the hash for both the type and its const-qualified version. - hash_code Hash = INITIAL_HASH; + hash_code Hash = InitialHash; auto asCanon = [](QualType Ty) -> CanQualType { return CanQualType::CreateUnsafe(Ty); @@ -204,47 +203,47 @@ hash_code IndexRecordHasher::hash(CanQualType CT) { if (Q.hasRestrict()) qVal |= 0x4; if(qVal) - COMBINE_HASH(qVal); + Hash = hash_combine(Hash, qVal); // Hash in ObjC GC qualifiers? if (const BuiltinType *BT = dyn_cast(T)) { - return COMBINE_HASH(BT->getKind()); + return hash_combine(Hash, BT->getKind()); } if (const PointerType *PT = dyn_cast(T)) { - COMBINE_HASH('*'); + Hash = hash_combine(Hash, '*'); CT = asCanon(PT->getPointeeType()); continue; } if (const ReferenceType *RT = dyn_cast(T)) { - COMBINE_HASH('&'); + Hash = hash_combine(Hash, '&'); CT = asCanon(RT->getPointeeType()); continue; } if (const BlockPointerType *BT = dyn_cast(T)) { - COMBINE_HASH('B'); + Hash = hash_combine(Hash, 'B'); CT = asCanon(BT->getPointeeType()); continue; } if (const ObjCObjectPointerType *OPT = dyn_cast(T)) { - COMBINE_HASH('*'); + Hash = hash_combine(Hash, '*'); CT = asCanon(OPT->getPointeeType()); continue; } if (const TagType *TT = dyn_cast(T)) { - return COMBINE_HASH('$', hash(TT->getDecl()->getCanonicalDecl())); + return hash_combine(Hash, '$', hash(TT->getDecl()->getCanonicalDecl())); } if (const ObjCInterfaceType *OIT = dyn_cast(T)) { - return COMBINE_HASH('$', hash(OIT->getDecl()->getCanonicalDecl())); + return hash_combine(Hash, '$', hash(OIT->getDecl()->getCanonicalDecl())); } if (const ObjCObjectType *OIT = dyn_cast(T)) { for (auto *Prot : OIT->getProtocols()) - COMBINE_HASH(hash(Prot)); + Hash = hash_combine(Hash, hash(Prot)); CT = asCanon(OIT->getBaseType()); continue; } if (const TemplateTypeParmType *TTP = dyn_cast(T)) { - return COMBINE_HASH('t', TTP->getDepth(), TTP->getIndex()); + return hash_combine(Hash, 't', TTP->getDepth(), TTP->getIndex()); } if (const InjectedClassNameType *InjT = dyn_cast(T)) { CT = asCanon(InjT->getInjectedSpecializationType().getCanonicalType()); @@ -254,7 +253,7 @@ hash_code IndexRecordHasher::hash(CanQualType CT) { break; } - return COMBINE_HASH(tryCache(CT.getAsOpaquePtr(), CT)); + return hash_combine(Hash, tryCache(CT.getAsOpaquePtr(), CT)); } hash_code IndexRecordHasher::hash(DeclarationName Name) { @@ -300,22 +299,22 @@ static hash_code computeHash(Selector Sel) { unsigned N = Sel.getNumArgs(); if (N == 0) ++N; - hash_code Hash = INITIAL_HASH; + hash_code Hash = InitialHash; for (unsigned I = 0; I != N; ++I) if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I)) - COMBINE_HASH(computeHash(II)); + Hash = hash_combine(Hash, computeHash(II)); return Hash; } static hash_code computeHash(TemplateName Name, IndexRecordHasher &Hasher) { - hash_code Hash = INITIAL_HASH; + hash_code Hash = InitialHash; if (TemplateDecl *Template = Name.getAsTemplateDecl()) { if (TemplateTemplateParmDecl *TTP = dyn_cast(Template)) { - return COMBINE_HASH('t', TTP->getDepth(), TTP->getIndex()); + return hash_combine(Hash, 't', TTP->getDepth(), TTP->getIndex()); } - return COMBINE_HASH(Hasher.hash(Template->getCanonicalDecl())); + return hash_combine(Hash, Hasher.hash(Template->getCanonicalDecl())); } // FIXME: Hash dependent template names. @@ -324,24 +323,24 @@ static hash_code computeHash(TemplateName Name, IndexRecordHasher &Hasher) { static hash_code computeHash(const TemplateArgument &Arg, IndexRecordHasher &Hasher) { - hash_code Hash = INITIAL_HASH; + hash_code Hash = InitialHash; switch (Arg.getKind()) { case TemplateArgument::Null: break; case TemplateArgument::Declaration: - COMBINE_HASH(Hasher.hash(Arg.getAsDecl())); + Hash = hash_combine(Hash, Hasher.hash(Arg.getAsDecl())); break; case TemplateArgument::NullPtr: break; case TemplateArgument::TemplateExpansion: - COMBINE_HASH('P'); // pack expansion of... + Hash = hash_combine(Hash, 'P'); // pack expansion of... LLVM_FALLTHROUGH; case TemplateArgument::Template: - COMBINE_HASH(computeHash(Arg.getAsTemplateOrTemplatePattern(), Hasher)); + Hash = hash_combine(Hash, computeHash(Arg.getAsTemplateOrTemplatePattern(), Hasher)); break; case TemplateArgument::Expression: @@ -349,17 +348,17 @@ static hash_code computeHash(const TemplateArgument &Arg, break; case TemplateArgument::Pack: - COMBINE_HASH('p'); + Hash = hash_combine(Hash, 'p'); for (const auto &P : Arg.pack_elements()) - COMBINE_HASH(computeHash(P, Hasher)); + Hash = hash_combine(Hash, computeHash(P, Hasher)); break; case TemplateArgument::Type: - COMBINE_HASH(Hasher.hash(Arg.getAsType())); + Hash = hash_combine(Hash, Hasher.hash(Arg.getAsType())); break; case TemplateArgument::Integral: - COMBINE_HASH('V', Hasher.hash(Arg.getIntegralType()), Arg.getAsIntegral()); + Hash = hash_combine(Hash, 'V', Hasher.hash(Arg.getIntegralType()), Arg.getAsIntegral()); break; } @@ -367,7 +366,7 @@ static hash_code computeHash(const TemplateArgument &Arg, } hash_code IndexRecordHasher::hashImpl(CanQualType CQT) { - hash_code Hash = INITIAL_HASH; + hash_code Hash = InitialHash; auto asCanon = [](QualType Ty) -> CanQualType { return CanQualType::CreateUnsafe(Ty); @@ -376,32 +375,32 @@ hash_code IndexRecordHasher::hashImpl(CanQualType CQT) { const Type *T = CQT.getTypePtr(); if (const PackExpansionType *Expansion = dyn_cast(T)) { - return COMBINE_HASH('P', hash(asCanon(Expansion->getPattern()))); + return hash_combine(Hash, 'P', hash(asCanon(Expansion->getPattern()))); } if (const RValueReferenceType *RT = dyn_cast(T)) { - return COMBINE_HASH('%', hash(asCanon(RT->getPointeeType()))); + return hash_combine(Hash, '%', hash(asCanon(RT->getPointeeType()))); } if (const FunctionProtoType *FT = dyn_cast(T)) { - COMBINE_HASH('F', hash(asCanon(FT->getReturnType()))); + Hash = hash_combine(Hash, 'F', hash(asCanon(FT->getReturnType()))); for (const auto &I : FT->param_types()) - COMBINE_HASH(hash(asCanon(I))); - return COMBINE_HASH(FT->isVariadic()); + Hash = hash_combine(Hash, hash(asCanon(I))); + return hash_combine(Hash, FT->isVariadic()); } if (const ComplexType *CT = dyn_cast(T)) { - return COMBINE_HASH('<', hash(asCanon(CT->getElementType()))); + return hash_combine(Hash, '<', hash(asCanon(CT->getElementType()))); } if (const TemplateSpecializationType *Spec = dyn_cast(T)) { - COMBINE_HASH('>', computeHash(Spec->getTemplateName(), *this)); + Hash = hash_combine(Hash, '>', computeHash(Spec->getTemplateName(), *this)); for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) - COMBINE_HASH(computeHash(Spec->getArg(I), *this)); + Hash = hash_combine(Hash, computeHash(Spec->getArg(I), *this)); return Hash; } if (const DependentNameType *DNT = dyn_cast(T)) { - COMBINE_HASH('^'); + Hash = hash_combine(Hash, '^'); if (const NestedNameSpecifier *NNS = DNT->getQualifier()) - COMBINE_HASH(hash(NNS)); - return COMBINE_HASH(computeHash(DNT->getIdentifier())); + Hash = hash_combine(Hash, hash(NNS)); + return hash_combine(Hash, computeHash(DNT->getIdentifier())); } // Unhandled type. @@ -409,32 +408,32 @@ hash_code IndexRecordHasher::hashImpl(CanQualType CQT) { } hash_code IndexRecordHasher::hashImpl(DeclarationName Name) { - hash_code Hash = INITIAL_HASH; - COMBINE_HASH(Name.getNameKind()); + hash_code Hash = InitialHash; + Hash = hash_combine(Hash, Name.getNameKind()); switch (Name.getNameKind()) { case DeclarationName::Identifier: - COMBINE_HASH(computeHash(Name.getAsIdentifierInfo())); + Hash = hash_combine(Hash, computeHash(Name.getAsIdentifierInfo())); break; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: - COMBINE_HASH(computeHash(Name.getObjCSelector())); + Hash = hash_combine(Hash, computeHash(Name.getObjCSelector())); break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: break; case DeclarationName::CXXOperatorName: - COMBINE_HASH(Name.getCXXOverloadedOperator()); + Hash = hash_combine(Hash, Name.getCXXOverloadedOperator()); break; case DeclarationName::CXXLiteralOperatorName: - COMBINE_HASH(computeHash(Name.getCXXLiteralIdentifier())); + Hash = hash_combine(Hash, computeHash(Name.getCXXLiteralIdentifier())); break; case DeclarationName::CXXUsingDirective: break; case DeclarationName::CXXDeductionGuideName: - COMBINE_HASH(computeHash(Name.getCXXDeductionGuideTemplate() + Hash = hash_combine(Hash, computeHash(Name.getCXXDeductionGuideTemplate() ->getDeclName().getAsIdentifierInfo())); break; } @@ -443,23 +442,23 @@ hash_code IndexRecordHasher::hashImpl(DeclarationName Name) { } hash_code IndexRecordHasher::hashImpl(const NestedNameSpecifier *NNS) { - hash_code Hash = INITIAL_HASH; + hash_code Hash = InitialHash; if (auto *Pre = NNS->getPrefix()) - COMBINE_HASH(hash(Pre)); + Hash = hash_combine(Hash, hash(Pre)); - COMBINE_HASH(NNS->getKind()); + Hash = hash_combine(Hash, NNS->getKind()); switch (NNS->getKind()) { case NestedNameSpecifier::Identifier: - COMBINE_HASH(computeHash(NNS->getAsIdentifier())); + Hash = hash_combine(Hash, computeHash(NNS->getAsIdentifier())); break; case NestedNameSpecifier::Namespace: - COMBINE_HASH(hash(NNS->getAsNamespace()->getCanonicalDecl())); + Hash = hash_combine(Hash, hash(NNS->getAsNamespace()->getCanonicalDecl())); break; case NestedNameSpecifier::NamespaceAlias: - COMBINE_HASH(hash(NNS->getAsNamespaceAlias()->getCanonicalDecl())); + Hash = hash_combine(Hash, hash(NNS->getAsNamespaceAlias()->getCanonicalDecl())); break; case NestedNameSpecifier::Global: @@ -472,7 +471,7 @@ hash_code IndexRecordHasher::hashImpl(const NestedNameSpecifier *NNS) { // Fall through to hash the type. case NestedNameSpecifier::TypeSpec: - COMBINE_HASH(hash(QualType(NNS->getAsType(), 0))); + Hash = hash_combine(Hash, hash(QualType(NNS->getAsType(), 0))); break; } From 5af83a9179131056d3762d0b1e583d7e9e842240 Mon Sep 17 00:00:00 2001 From: Jan Korous Date: Mon, 11 Mar 2019 15:36:09 -0700 Subject: [PATCH 4/7] [clang][index-while-building][IndexRecordHasher][NFC] clang-format --- lib/Index/IndexRecordHasher.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/Index/IndexRecordHasher.cpp b/lib/Index/IndexRecordHasher.cpp index cf699167138..e86ffced55b 100644 --- a/lib/Index/IndexRecordHasher.cpp +++ b/lib/Index/IndexRecordHasher.cpp @@ -48,7 +48,8 @@ class DeclHashVisitor : public ConstDeclVisitor { hash_code Hash = VisitDeclContext(D->getDeclContext()); if (D->isEmbeddedInDeclarator() && !D->isFreeStanding()) { - Hash = hash_combine(Hash, hashLoc(D->getLocation(), /*IncludeOffset=*/true)); + Hash = hash_combine(Hash, + hashLoc(D->getLocation(), /*IncludeOffset=*/true)); } else Hash = hash_combine(Hash, 'a'); return Hash; @@ -340,7 +341,8 @@ static hash_code computeHash(const TemplateArgument &Arg, Hash = hash_combine(Hash, 'P'); // pack expansion of... LLVM_FALLTHROUGH; case TemplateArgument::Template: - Hash = hash_combine(Hash, computeHash(Arg.getAsTemplateOrTemplatePattern(), Hasher)); + Hash = hash_combine( + Hash, computeHash(Arg.getAsTemplateOrTemplatePattern(), Hasher)); break; case TemplateArgument::Expression: @@ -358,7 +360,8 @@ static hash_code computeHash(const TemplateArgument &Arg, break; case TemplateArgument::Integral: - Hash = hash_combine(Hash, 'V', Hasher.hash(Arg.getIntegralType()), Arg.getAsIntegral()); + Hash = hash_combine(Hash, 'V', Hasher.hash(Arg.getIntegralType()), + Arg.getAsIntegral()); break; } @@ -434,7 +437,8 @@ hash_code IndexRecordHasher::hashImpl(DeclarationName Name) { break; case DeclarationName::CXXDeductionGuideName: Hash = hash_combine(Hash, computeHash(Name.getCXXDeductionGuideTemplate() - ->getDeclName().getAsIdentifierInfo())); + ->getDeclName() + .getAsIdentifierInfo())); break; } @@ -458,7 +462,8 @@ hash_code IndexRecordHasher::hashImpl(const NestedNameSpecifier *NNS) { break; case NestedNameSpecifier::NamespaceAlias: - Hash = hash_combine(Hash, hash(NNS->getAsNamespaceAlias()->getCanonicalDecl())); + Hash = hash_combine(Hash, + hash(NNS->getAsNamespaceAlias()->getCanonicalDecl())); break; case NestedNameSpecifier::Global: From 5fa09f9fe7c5417fdd77b1d1382d6ae47ccebf46 Mon Sep 17 00:00:00 2001 From: Jan Korous Date: Mon, 11 Mar 2019 16:08:23 -0700 Subject: [PATCH 5/7] [clang][index-while-building][IndexRecordHasher] Refactor IndexRecord hashing --- lib/Index/CMakeLists.txt | 4 +- lib/Index/ClangIndexRecordWriter.cpp | 7 +- lib/Index/ClangIndexRecordWriter.h | 1 - lib/Index/IndexRecordHasher.h | 46 +--- lib/Index/RecordHasher/CMakeLists.txt | 16 ++ .../CachingHasher.cpp} | 243 ++++-------------- lib/Index/RecordHasher/CachingHasher.h | 60 +++++ lib/Index/RecordHasher/DeclHasher.cpp | 140 ++++++++++ lib/Index/RecordHasher/DeclHasher.h | 51 ++++ lib/Index/RecordHasher/IndexRecordHasher.cpp | 33 +++ 10 files changed, 362 insertions(+), 239 deletions(-) create mode 100644 lib/Index/RecordHasher/CMakeLists.txt rename lib/Index/{IndexRecordHasher.cpp => RecordHasher/CachingHasher.cpp} (53%) create mode 100644 lib/Index/RecordHasher/CachingHasher.h create mode 100644 lib/Index/RecordHasher/DeclHasher.cpp create mode 100644 lib/Index/RecordHasher/DeclHasher.h create mode 100644 lib/Index/RecordHasher/IndexRecordHasher.cpp diff --git a/lib/Index/CMakeLists.txt b/lib/Index/CMakeLists.txt index ff30c74e803..24aef385b62 100644 --- a/lib/Index/CMakeLists.txt +++ b/lib/Index/CMakeLists.txt @@ -14,7 +14,6 @@ add_clang_library(clangIndex IndexDecl.cpp IndexingAction.cpp IndexingContext.cpp - IndexRecordHasher.cpp IndexRecordReader.cpp IndexRecordWriter.cpp IndexSymbol.cpp @@ -36,4 +35,7 @@ add_clang_library(clangIndex clangRewrite clangSerialization clangToolingCore + clangIndexRecordHasher ) + +add_subdirectory(RecordHasher) diff --git a/lib/Index/ClangIndexRecordWriter.cpp b/lib/Index/ClangIndexRecordWriter.cpp index 41d45a0360d..c8177a9e212 100644 --- a/lib/Index/ClangIndexRecordWriter.cpp +++ b/lib/Index/ClangIndexRecordWriter.cpp @@ -41,8 +41,7 @@ StringRef ClangIndexRecordWriter::getUSRNonCached(const Decl *D) { ClangIndexRecordWriter::ClangIndexRecordWriter(ASTContext &Ctx, RecordingOptions Opts) - : Impl(Opts.DataDirPath), Ctx(Ctx), RecordOpts(std::move(Opts)), - Hasher(Ctx) { + : Impl(Opts.DataDirPath), Ctx(Ctx), RecordOpts(std::move(Opts)) { if (Opts.RecordSymbolCodeGenName) CGNameGen.reset(new CodegenNameGenerator(Ctx)); } @@ -54,7 +53,8 @@ bool ClangIndexRecordWriter::writeRecord(StringRef Filename, std::string &Error, std::string *OutRecordFile) { - auto RecordHash = Hasher.hashRecord(IdxRecord); + ASTContext &Ctx = getASTContext(); + auto RecordHash = hashRecord(Ctx, IdxRecord); switch (Impl.beginRecord(Filename, RecordHash, Error, OutRecordFile)) { case IndexRecordWriter::Result::Success: @@ -65,7 +65,6 @@ bool ClangIndexRecordWriter::writeRecord(StringRef Filename, return false; } - ASTContext &Ctx = getASTContext(); SourceManager &SM = Ctx.getSourceManager(); FileID FID = IdxRecord.getFileID(); auto getLineCol = [&](unsigned Offset) -> std::pair { diff --git a/lib/Index/ClangIndexRecordWriter.h b/lib/Index/ClangIndexRecordWriter.h index b68f9875fb3..55908bbe2d7 100644 --- a/lib/Index/ClangIndexRecordWriter.h +++ b/lib/Index/ClangIndexRecordWriter.h @@ -32,7 +32,6 @@ class ClangIndexRecordWriter { std::unique_ptr CGNameGen; llvm::BumpPtrAllocator Allocator; llvm::DenseMap USRByDecl; - IndexRecordHasher Hasher; public: ClangIndexRecordWriter(ASTContext &Ctx, RecordingOptions Opts); diff --git a/lib/Index/IndexRecordHasher.h b/lib/Index/IndexRecordHasher.h index e359a1cb1f0..52937761cf8 100644 --- a/lib/Index/IndexRecordHasher.h +++ b/lib/Index/IndexRecordHasher.h @@ -1,5 +1,4 @@ -//===--- IndexRecordHasher.h - Index record hashing -------------*- C++ -*-===// - +//===--- IndexRecordHasher.h - Hashing of FileIndexRecord -------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -10,52 +9,17 @@ #ifndef LLVM_CLANG_LIB_INDEX_INDEXRECORDHASHER_H #define LLVM_CLANG_LIB_INDEX_INDEXRECORDHASHER_H -#include "clang/Basic/LLVM.h" -#include "llvm/ADT/DenseMap.h" +#include "clang/AST/ASTContext.h" #include "llvm/ADT/Hashing.h" namespace clang { - class ASTContext; - class Decl; - class DeclarationName; - class NestedNameSpecifier; - class QualType; - class Type; - template class CanQual; - typedef CanQual CanQualType; - namespace index { class FileIndexRecord; -/// Implements hashing of AST nodes suitable for the index. -/// Caching all produced hashes. -class IndexRecordHasher { - ASTContext &Ctx; - llvm::DenseMap HashByPtr; - -public: - explicit IndexRecordHasher(ASTContext &Ctx) : Ctx(Ctx) {} - ASTContext &getASTContext() { return Ctx; } - - /// Returns hash for all declaration occurences in \c Record. - llvm::hash_code hashRecord(const FileIndexRecord &Record); - llvm::hash_code hash(const Decl *D); - llvm::hash_code hash(QualType Ty); - llvm::hash_code hash(CanQualType Ty); - llvm::hash_code hash(DeclarationName Name); - llvm::hash_code hash(const NestedNameSpecifier *NNS); - -private: - template - llvm::hash_code tryCache(const void *Ptr, T Obj); - - llvm::hash_code hashImpl(const Decl *D); - llvm::hash_code hashImpl(CanQualType Ty); - llvm::hash_code hashImpl(DeclarationName Name); - llvm::hash_code hashImpl(const NestedNameSpecifier *NNS); -}; + /// \returns hash of the \p Record + llvm::hash_code hashRecord(ASTContext &Ctx, const FileIndexRecord &Record); } // end namespace index } // end namespace clang -#endif +#endif // LLVM_CLANG_LIB_INDEX_INDEXRECORDHASHER_H diff --git a/lib/Index/RecordHasher/CMakeLists.txt b/lib/Index/RecordHasher/CMakeLists.txt new file mode 100644 index 00000000000..b01039948ed --- /dev/null +++ b/lib/Index/RecordHasher/CMakeLists.txt @@ -0,0 +1,16 @@ +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) + +set(LLVM_LINK_COMPONENTS + Support + ) + +add_clang_library(clangIndexRecordHasher + IndexRecordHasher.cpp + DeclHasher.cpp + CachingHasher.cpp + + LINK_LIBS + clangAST + clangBasic + ) + \ No newline at end of file diff --git a/lib/Index/IndexRecordHasher.cpp b/lib/Index/RecordHasher/CachingHasher.cpp similarity index 53% rename from lib/Index/IndexRecordHasher.cpp rename to lib/Index/RecordHasher/CachingHasher.cpp index e86ffced55b..06e18be4512 100644 --- a/lib/Index/IndexRecordHasher.cpp +++ b/lib/Index/RecordHasher/CachingHasher.cpp @@ -1,4 +1,4 @@ -//===--- IndexRecordHasher.cpp - Index record hashing -----------*- C++ -*-===// +//===--- CachingHasher.cpp - Hashing of indexed entities --------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,170 +6,23 @@ // //===----------------------------------------------------------------------===// -#include "IndexRecordHasher.h" -#include "FileIndexRecord.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Decl.h" -#include "clang/AST/DeclVisitor.h" -#include "llvm/Support/Path.h" +#include "RecordHasher/CachingHasher.h" +#include "RecordHasher/DeclHasher.h" -constexpr size_t InitialHash = 5381; +namespace clang { +namespace index { -using namespace clang; -using namespace clang::index; -using namespace llvm; +using llvm::hash_code; -static hash_code computeHash(const TemplateArgument &Arg, - IndexRecordHasher &Hasher); - -namespace { -class DeclHashVisitor : public ConstDeclVisitor { - IndexRecordHasher &Hasher; - -public: - DeclHashVisitor(IndexRecordHasher &Hasher) : Hasher(Hasher) {} - - hash_code VisitDecl(const Decl *D) { - return VisitDeclContext(D->getDeclContext()); - } - - hash_code VisitNamedDecl(const NamedDecl *D) { - hash_code Hash = VisitDecl(D); - if (auto *attr = D->getExternalSourceSymbolAttr()) { - Hash = hash_combine(Hash, hash_value(attr->getDefinedIn())); - } - return hash_combine(Hash, Hasher.hash(D->getDeclName())); - } - - hash_code VisitTagDecl(const TagDecl *D) { - if (D->getDeclName().isEmpty()) { - if (const TypedefNameDecl *TD = D->getTypedefNameForAnonDecl()) - return Visit(TD); - - hash_code Hash = VisitDeclContext(D->getDeclContext()); - if (D->isEmbeddedInDeclarator() && !D->isFreeStanding()) { - Hash = hash_combine(Hash, - hashLoc(D->getLocation(), /*IncludeOffset=*/true)); - } else - Hash = hash_combine(Hash, 'a'); - return Hash; - } - - hash_code Hash = VisitTypeDecl(D); - return hash_combine(Hash, 'T'); - } - - hash_code VisitClassTemplateSpecializationDecl(const ClassTemplateSpecializationDecl *D) { - hash_code Hash = VisitCXXRecordDecl(D); - const TemplateArgumentList &Args = D->getTemplateArgs(); - Hash = hash_combine(Hash, '>'); - for (unsigned I = 0, N = Args.size(); I != N; ++I) { - Hash = hash_combine(Hash, computeHash(Args.get(I), Hasher)); - } - return Hash; - } - - hash_code VisitObjCContainerDecl(const ObjCContainerDecl *D) { - hash_code Hash = VisitNamedDecl(D); - return hash_combine(Hash, 'I'); - } - - hash_code VisitObjCImplDecl(const ObjCImplDecl *D) { - if (auto *ID = D->getClassInterface()) - return VisitObjCInterfaceDecl(ID); - else - return 0; - } - - hash_code VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { - // FIXME: Differentiate between category and the interface ? - if (auto *ID = D->getClassInterface()) - return VisitObjCInterfaceDecl(ID); - else - return 0; - } - - hash_code VisitFunctionDecl(const FunctionDecl *D) { - hash_code Hash = VisitNamedDecl(D); - ASTContext &Ctx = Hasher.getASTContext(); - if ((!Ctx.getLangOpts().CPlusPlus && !D->hasAttr()) - || D->isExternC()) - return Hash; - - for (auto param : D->parameters()) { - Hash = hash_combine(Hash, Hasher.hash(param->getType())); - } - return Hash; - } - - hash_code VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D) { - hash_code Hash = VisitNamedDecl(D); - Hash = hash_combine(Hash, Hasher.hash(D->getQualifier())); - return Hash; - } - - hash_code VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) { - hash_code Hash = VisitNamedDecl(D); - Hash = hash_combine(Hash, Hasher.hash(D->getQualifier())); - return Hash; - } - - hash_code VisitDeclContext(const DeclContext *DC) { - // FIXME: Add location if this is anonymous namespace ? - DC = DC->getRedeclContext(); - const Decl *D = cast(DC)->getCanonicalDecl(); - if (auto *ND = dyn_cast(D)) - return Hasher.hash(ND); - else - return 0; - } - - hash_code hashLoc(SourceLocation Loc, bool IncludeOffset) { - if (Loc.isInvalid()) { - return 0; - } - hash_code Hash = InitialHash; - const SourceManager &SM = Hasher.getASTContext().getSourceManager(); - Loc = SM.getFileLoc(Loc); - const std::pair &Decomposed = SM.getDecomposedLoc(Loc); - const FileEntry *FE = SM.getFileEntryForID(Decomposed.first); - if (FE) { - Hash = hash_combine(Hash, llvm::sys::path::filename(FE->getName())); - } else { - // This case really isn't interesting. - return 0; - } - if (IncludeOffset) { - // Use the offest into the FileID to represent the location. Using - // a line/column can cause us to look back at the original source file, - // which is expensive. - Hash = hash_combine(Hash, Decomposed.second); - } - return Hash; - } -}; -} - -hash_code IndexRecordHasher::hashRecord(const FileIndexRecord &Record) { - hash_code Hash = InitialHash; - for (auto &Info : Record.getDeclOccurrencesSortedByOffset()) { - Hash = hash_combine(Hash, Info.Roles, Info.Offset, hash(Info.Dcl)); - for (auto &Rel : Info.Relations) { - Hash = hash_combine(Hash, hash(Rel.RelatedSymbol)); - } - } - return Hash; -} - -hash_code IndexRecordHasher::hash(const Decl *D) { +hash_code CachingHasher::hash(const Decl *D) { assert(D->isCanonicalDecl()); if (isa(D) || isa(D)) { - return tryCache(D, D); + return getCachedHash(D, D); } else if (auto *NS = dyn_cast(D)) { if (NS->isAnonymousNamespace()) return hash_value(StringRef("@aN")); - return tryCache(D, D); + return getCachedHash(D, D); } else { // There's a balance between caching results and not growing the cache too // much. Measurements showed that avoiding caching all decls is beneficial @@ -178,12 +31,12 @@ hash_code IndexRecordHasher::hash(const Decl *D) { } } -hash_code IndexRecordHasher::hash(QualType NonCanTy) { +hash_code CachingHasher::hash(QualType NonCanTy) { CanQualType CanTy = Ctx.getCanonicalType(NonCanTy); return hash(CanTy); } -hash_code IndexRecordHasher::hash(CanQualType CT) { +hash_code CachingHasher::hash(CanQualType CT) { // Do some hashing without going to the cache, for example we can avoid // storing the hash for both the type and its const-qualified version. hash_code Hash = InitialHash; @@ -254,10 +107,10 @@ hash_code IndexRecordHasher::hash(CanQualType CT) { break; } - return hash_combine(Hash, tryCache(CT.getAsOpaquePtr(), CT)); + return hash_combine(Hash, getCachedHash(CT.getAsOpaquePtr(), CT)); } -hash_code IndexRecordHasher::hash(DeclarationName Name) { +hash_code CachingHasher::hash(DeclarationName Name) { assert(!Name.isEmpty()); // Measurements for using cache or not here, showed significant slowdown when // using the cache for all DeclarationNames when parsing Cocoa, and minor @@ -266,21 +119,26 @@ hash_code IndexRecordHasher::hash(DeclarationName Name) { return hashImpl(Name); } -hash_code IndexRecordHasher::hash(const NestedNameSpecifier *NNS) { +hash_code CachingHasher::hash(const NestedNameSpecifier *NNS) { assert(NNS); // Measurements for the C++ single translation unit files did not show much // difference here; choosing to cache them currently. - return tryCache(NNS, NNS); + return getCachedHash(NNS, NNS); +} + +hash_code CachingHasher::hash(const TemplateArgument &Arg) { + // No caching. + return hashImpl(Arg); } template -hash_code IndexRecordHasher::tryCache(const void *Ptr, T Obj) { +hash_code CachingHasher::getCachedHash(const void *Ptr, T Obj) { auto It = HashByPtr.find(Ptr); if (It != HashByPtr.end()) return It->second; hash_code Hash = hashImpl(Obj); - // hashImpl() may call into tryCache recursively and mutate + // hashImpl() may call into getCachedHash recursively and mutate // HashByPtr, so we use find() earlier and insert the hash with another // lookup here instead of calling insert() earlier and utilizing the iterator // that insert() returns. @@ -288,26 +146,26 @@ hash_code IndexRecordHasher::tryCache(const void *Ptr, T Obj) { return Hash; } -hash_code IndexRecordHasher::hashImpl(const Decl *D) { - return DeclHashVisitor(*this).Visit(D); +hash_code CachingHasher::hashImpl(const Decl *D) { + return DeclHasher(*this).Visit(D); } -static hash_code computeHash(const IdentifierInfo *II) { +hash_code CachingHasher::hashImpl(const IdentifierInfo *II) { return hash_value(II->getName()); } -static hash_code computeHash(Selector Sel) { +hash_code CachingHasher::hashImpl(Selector Sel) { unsigned N = Sel.getNumArgs(); if (N == 0) ++N; hash_code Hash = InitialHash; for (unsigned I = 0; I != N; ++I) if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I)) - Hash = hash_combine(Hash, computeHash(II)); + Hash = hash_combine(Hash, hashImpl(II)); return Hash; } -static hash_code computeHash(TemplateName Name, IndexRecordHasher &Hasher) { +hash_code CachingHasher::hashImpl(TemplateName Name) { hash_code Hash = InitialHash; if (TemplateDecl *Template = Name.getAsTemplateDecl()) { if (TemplateTemplateParmDecl *TTP @@ -315,15 +173,14 @@ static hash_code computeHash(TemplateName Name, IndexRecordHasher &Hasher) { return hash_combine(Hash, 't', TTP->getDepth(), TTP->getIndex()); } - return hash_combine(Hash, Hasher.hash(Template->getCanonicalDecl())); + return hash_combine(Hash, hash(Template->getCanonicalDecl())); } // FIXME: Hash dependent template names. return Hash; } -static hash_code computeHash(const TemplateArgument &Arg, - IndexRecordHasher &Hasher) { +hash_code CachingHasher::hashImpl(const TemplateArgument &Arg) { hash_code Hash = InitialHash; switch (Arg.getKind()) { @@ -331,7 +188,7 @@ static hash_code computeHash(const TemplateArgument &Arg, break; case TemplateArgument::Declaration: - Hash = hash_combine(Hash, Hasher.hash(Arg.getAsDecl())); + Hash = hash_combine(Hash, hash(Arg.getAsDecl())); break; case TemplateArgument::NullPtr: @@ -341,8 +198,7 @@ static hash_code computeHash(const TemplateArgument &Arg, Hash = hash_combine(Hash, 'P'); // pack expansion of... LLVM_FALLTHROUGH; case TemplateArgument::Template: - Hash = hash_combine( - Hash, computeHash(Arg.getAsTemplateOrTemplatePattern(), Hasher)); + Hash = hash_combine(Hash, hashImpl(Arg.getAsTemplateOrTemplatePattern())); break; case TemplateArgument::Expression: @@ -352,15 +208,15 @@ static hash_code computeHash(const TemplateArgument &Arg, case TemplateArgument::Pack: Hash = hash_combine(Hash, 'p'); for (const auto &P : Arg.pack_elements()) - Hash = hash_combine(Hash, computeHash(P, Hasher)); + Hash = hash_combine(Hash, hashImpl(P)); break; case TemplateArgument::Type: - Hash = hash_combine(Hash, Hasher.hash(Arg.getAsType())); + Hash = hash_combine(Hash, hash(Arg.getAsType())); break; case TemplateArgument::Integral: - Hash = hash_combine(Hash, 'V', Hasher.hash(Arg.getIntegralType()), + Hash = hash_combine(Hash, 'V', hash(Arg.getIntegralType()), Arg.getAsIntegral()); break; } @@ -368,7 +224,7 @@ static hash_code computeHash(const TemplateArgument &Arg, return Hash; } -hash_code IndexRecordHasher::hashImpl(CanQualType CQT) { +hash_code CachingHasher::hashImpl(CanQualType CQT) { hash_code Hash = InitialHash; auto asCanon = [](QualType Ty) -> CanQualType { @@ -394,34 +250,34 @@ hash_code IndexRecordHasher::hashImpl(CanQualType CQT) { } if (const TemplateSpecializationType *Spec = dyn_cast(T)) { - Hash = hash_combine(Hash, '>', computeHash(Spec->getTemplateName(), *this)); + Hash = hash_combine(Hash, '>', hashImpl(Spec->getTemplateName())); for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) - Hash = hash_combine(Hash, computeHash(Spec->getArg(I), *this)); + Hash = hash_combine(Hash, hashImpl(Spec->getArg(I))); return Hash; } if (const DependentNameType *DNT = dyn_cast(T)) { Hash = hash_combine(Hash, '^'); if (const NestedNameSpecifier *NNS = DNT->getQualifier()) Hash = hash_combine(Hash, hash(NNS)); - return hash_combine(Hash, computeHash(DNT->getIdentifier())); + return hash_combine(Hash, hashImpl(DNT->getIdentifier())); } // Unhandled type. return Hash; } -hash_code IndexRecordHasher::hashImpl(DeclarationName Name) { +hash_code CachingHasher::hashImpl(DeclarationName Name) { hash_code Hash = InitialHash; Hash = hash_combine(Hash, Name.getNameKind()); switch (Name.getNameKind()) { case DeclarationName::Identifier: - Hash = hash_combine(Hash, computeHash(Name.getAsIdentifierInfo())); + Hash = hash_combine(Hash, hashImpl(Name.getAsIdentifierInfo())); break; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: - Hash = hash_combine(Hash, computeHash(Name.getObjCSelector())); + Hash = hash_combine(Hash, hashImpl(Name.getObjCSelector())); break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: @@ -431,21 +287,21 @@ hash_code IndexRecordHasher::hashImpl(DeclarationName Name) { Hash = hash_combine(Hash, Name.getCXXOverloadedOperator()); break; case DeclarationName::CXXLiteralOperatorName: - Hash = hash_combine(Hash, computeHash(Name.getCXXLiteralIdentifier())); + Hash = hash_combine(Hash, hashImpl(Name.getCXXLiteralIdentifier())); break; case DeclarationName::CXXUsingDirective: break; case DeclarationName::CXXDeductionGuideName: - Hash = hash_combine(Hash, computeHash(Name.getCXXDeductionGuideTemplate() - ->getDeclName() - .getAsIdentifierInfo())); + Hash = hash_combine(Hash, hashImpl(Name.getCXXDeductionGuideTemplate() + ->getDeclName() + .getAsIdentifierInfo())); break; } return Hash; } -hash_code IndexRecordHasher::hashImpl(const NestedNameSpecifier *NNS) { +hash_code CachingHasher::hashImpl(const NestedNameSpecifier *NNS) { hash_code Hash = InitialHash; if (auto *Pre = NNS->getPrefix()) Hash = hash_combine(Hash, hash(Pre)); @@ -454,7 +310,7 @@ hash_code IndexRecordHasher::hashImpl(const NestedNameSpecifier *NNS) { switch (NNS->getKind()) { case NestedNameSpecifier::Identifier: - Hash = hash_combine(Hash, computeHash(NNS->getAsIdentifier())); + Hash = hash_combine(Hash, hashImpl(NNS->getAsIdentifier())); break; case NestedNameSpecifier::Namespace: @@ -482,3 +338,6 @@ hash_code IndexRecordHasher::hashImpl(const NestedNameSpecifier *NNS) { return Hash; } + +} // end namespace index +} // end namespace clang \ No newline at end of file diff --git a/lib/Index/RecordHasher/CachingHasher.h b/lib/Index/RecordHasher/CachingHasher.h new file mode 100644 index 00000000000..adfbe40738e --- /dev/null +++ b/lib/Index/RecordHasher/CachingHasher.h @@ -0,0 +1,60 @@ +//===--- CachingHasher.h - Hashing of indexed entities ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_INDEX_RECORDHASHER_CACHINGHASHER_H +#define LLVM_CLANG_LIB_INDEX_RECORDHASHER_CACHINGHASHER_H + +#include "clang/AST/ASTContext.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Hashing.h" + +namespace clang { +namespace index { + +constexpr size_t InitialHash = 5381; + +/// Utility class implementing hashing and caching of hashes. +class CachingHasher { + ASTContext &Ctx; + llvm::DenseMap HashByPtr; + +public: + explicit CachingHasher(ASTContext &Ctx) : Ctx(Ctx) {} + ASTContext &getASTContext() { return Ctx; } + + /// Public interface that implements caching strategy. + llvm::hash_code hash(const Decl *D); + llvm::hash_code hash(QualType Ty); + llvm::hash_code hash(CanQualType Ty); + llvm::hash_code hash(DeclarationName Name); + llvm::hash_code hash(const NestedNameSpecifier *NNS); + llvm::hash_code hash(const TemplateArgument &Arg); + +private: + /// \returns hash of \p Obj. + /// Uses cached value if it exists otherwise calculates the hash, adds it to + /// the cache and returns. + template llvm::hash_code getCachedHash(const void *Ptr, T Obj); + + // Private methods implement hashing itself. Intentionally hidden from client + // (DeclHasher) to prevent accidental caching bypass. + llvm::hash_code hashImpl(const Decl *D); + llvm::hash_code hashImpl(CanQualType Ty); + llvm::hash_code hashImpl(DeclarationName Name); + llvm::hash_code hashImpl(const NestedNameSpecifier *NNS); + llvm::hash_code hashImpl(const TemplateArgument &Arg); + llvm::hash_code hashImpl(const IdentifierInfo *II); + llvm::hash_code hashImpl(Selector Sel); + llvm::hash_code hashImpl(TemplateName Name); +}; + +} // end namespace index +} // end namespace clang + +#endif // LLVM_CLANG_LIB_INDEX_RECORDHASHER_CACHINGHASHER_H \ No newline at end of file diff --git a/lib/Index/RecordHasher/DeclHasher.cpp b/lib/Index/RecordHasher/DeclHasher.cpp new file mode 100644 index 00000000000..633b3f791e3 --- /dev/null +++ b/lib/Index/RecordHasher/DeclHasher.cpp @@ -0,0 +1,140 @@ +//===--- DeclHasher.cpp - Hashing of Decl nodes in AST ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "RecordHasher/DeclHasher.h" +#include "RecordHasher/CachingHasher.h" + +namespace clang { +namespace index { + +using llvm::hash_code; + +hash_code DeclHasher::VisitDecl(const Decl *D) { + return VisitDeclContext(D->getDeclContext()); +} + +hash_code DeclHasher::VisitNamedDecl(const NamedDecl *D) { + hash_code Hash = VisitDecl(D); + if (auto *attr = D->getExternalSourceSymbolAttr()) { + Hash = hash_combine(Hash, hash_value(attr->getDefinedIn())); + } + return hash_combine(Hash, Hasher.hash(D->getDeclName())); +} + +hash_code DeclHasher::VisitTagDecl(const TagDecl *D) { + if (D->getDeclName().isEmpty()) { + if (const TypedefNameDecl *TD = D->getTypedefNameForAnonDecl()) + return Visit(TD); + + hash_code Hash = VisitDeclContext(D->getDeclContext()); + if (D->isEmbeddedInDeclarator() && !D->isFreeStanding()) { + Hash = + hash_combine(Hash, hashLoc(D->getLocation(), /*IncludeOffset=*/true)); + } else + Hash = hash_combine(Hash, 'a'); + return Hash; + } + + hash_code Hash = VisitTypeDecl(D); + return hash_combine(Hash, 'T'); +} + +hash_code DeclHasher::VisitClassTemplateSpecializationDecl( + const ClassTemplateSpecializationDecl *D) { + hash_code Hash = VisitCXXRecordDecl(D); + const TemplateArgumentList &Args = D->getTemplateArgs(); + Hash = hash_combine(Hash, '>'); + for (unsigned I = 0, N = Args.size(); I != N; ++I) { + Hash = hash_combine(Hash, Hasher.hash(Args.get(I))); + } + return Hash; +} + +hash_code DeclHasher::VisitObjCContainerDecl(const ObjCContainerDecl *D) { + hash_code Hash = VisitNamedDecl(D); + return hash_combine(Hash, 'I'); +} + +hash_code DeclHasher::VisitObjCImplDecl(const ObjCImplDecl *D) { + if (auto *ID = D->getClassInterface()) + return VisitObjCInterfaceDecl(ID); + else + return 0; +} + +hash_code DeclHasher::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { + // FIXME: Differentiate between category and the interface ? + if (auto *ID = D->getClassInterface()) + return VisitObjCInterfaceDecl(ID); + else + return 0; +} + +hash_code DeclHasher::VisitFunctionDecl(const FunctionDecl *D) { + hash_code Hash = VisitNamedDecl(D); + ASTContext &Ctx = Hasher.getASTContext(); + if ((!Ctx.getLangOpts().CPlusPlus && !D->hasAttr()) || + D->isExternC()) + return Hash; + + for (auto param : D->parameters()) { + Hash = hash_combine(Hash, Hasher.hash(param->getType())); + } + return Hash; +} + +hash_code DeclHasher::VisitUnresolvedUsingTypenameDecl( + const UnresolvedUsingTypenameDecl *D) { + hash_code Hash = VisitNamedDecl(D); + Hash = hash_combine(Hash, Hasher.hash(D->getQualifier())); + return Hash; +} + +hash_code +DeclHasher::VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) { + hash_code Hash = VisitNamedDecl(D); + Hash = hash_combine(Hash, Hasher.hash(D->getQualifier())); + return Hash; +} + +hash_code DeclHasher::VisitDeclContext(const DeclContext *DC) { + // FIXME: Add location if this is anonymous namespace ? + DC = DC->getRedeclContext(); + const Decl *D = cast(DC)->getCanonicalDecl(); + if (auto *ND = dyn_cast(D)) + return Hasher.hash(ND); + else + return 0; +} + +hash_code DeclHasher::hashLoc(SourceLocation Loc, bool IncludeOffset) { + if (Loc.isInvalid()) { + return 0; + } + hash_code Hash = InitialHash; + const SourceManager &SM = Hasher.getASTContext().getSourceManager(); + Loc = SM.getFileLoc(Loc); + const std::pair &Decomposed = SM.getDecomposedLoc(Loc); + const FileEntry *FE = SM.getFileEntryForID(Decomposed.first); + if (FE) { + Hash = hash_combine(Hash, llvm::sys::path::filename(FE->getName())); + } else { + // This case really isn't interesting. + return 0; + } + if (IncludeOffset) { + // Use the offest into the FileID to represent the location. Using + // a line/column can cause us to look back at the original source file, + // which is expensive. + Hash = hash_combine(Hash, Decomposed.second); + } + return Hash; +} + +} // end namespace index +} // end namespace clang \ No newline at end of file diff --git a/lib/Index/RecordHasher/DeclHasher.h b/lib/Index/RecordHasher/DeclHasher.h new file mode 100644 index 00000000000..8f78a008200 --- /dev/null +++ b/lib/Index/RecordHasher/DeclHasher.h @@ -0,0 +1,51 @@ +//===--- DeclHasher.h - Hashing of Decl nodes in AST ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_INDEX_RECORDHASHER_DECLHASHER_H +#define LLVM_CLANG_LIB_INDEX_RECORDHASHER_DECLHASHER_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclVisitor.h" +#include "llvm/Support/Path.h" + +namespace clang { +namespace index { + +class CachingHasher; + +/// Implements hashing for declaration nodes in AST. +/// This is just a convenient way how to avoid writing a huge switch for various +/// types derived from Decl. Uses CachingHasher for hashing of atomic entities. + +class DeclHasher : public ConstDeclVisitor { + CachingHasher &Hasher; + +public: + DeclHasher(CachingHasher &Hasher) : Hasher(Hasher) {} + + llvm::hash_code VisitDecl(const Decl *D); + llvm::hash_code VisitNamedDecl(const NamedDecl *D); + llvm::hash_code VisitTagDecl(const TagDecl *D); + llvm::hash_code VisitClassTemplateSpecializationDecl( + const ClassTemplateSpecializationDecl *D); + llvm::hash_code VisitObjCContainerDecl(const ObjCContainerDecl *D); + llvm::hash_code VisitObjCImplDecl(const ObjCImplDecl *D); + llvm::hash_code VisitObjCCategoryDecl(const ObjCCategoryDecl *D); + llvm::hash_code VisitFunctionDecl(const FunctionDecl *D); + llvm::hash_code + VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D); + llvm::hash_code + VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D); + llvm::hash_code VisitDeclContext(const DeclContext *DC); + llvm::hash_code hashLoc(SourceLocation Loc, bool IncludeOffset); +}; + +} // end namespace index +} // end namespace clang + +#endif // LLVM_CLANG_LIB_INDEX_RECORDHASHER_DECLHASHER_H \ No newline at end of file diff --git a/lib/Index/RecordHasher/IndexRecordHasher.cpp b/lib/Index/RecordHasher/IndexRecordHasher.cpp new file mode 100644 index 00000000000..0431df02b44 --- /dev/null +++ b/lib/Index/RecordHasher/IndexRecordHasher.cpp @@ -0,0 +1,33 @@ +//===--- IndexRecordHasher.cpp - Hashing of FileIndexRecord -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "IndexRecordHasher.h" +#include "FileIndexRecord.h" +#include "RecordHasher/CachingHasher.h" + +namespace clang { +namespace index { + +using llvm::hash_code; + +hash_code hashRecord(ASTContext &Ctx, const FileIndexRecord &Record) { + + CachingHasher Hasher(Ctx); + + hash_code Hash = InitialHash; + for (auto &Info : Record.getDeclOccurrencesSortedByOffset()) { + Hash = hash_combine(Hash, Info.Roles, Info.Offset, Hasher.hash(Info.Dcl)); + for (auto &Rel : Info.Relations) { + Hash = hash_combine(Hash, Hasher.hash(Rel.RelatedSymbol)); + } + } + return Hash; +} + +} // end namespace index +} // end namespace clang \ No newline at end of file From 2e97cb06846f57e068864190f3fbb73a5c83dc9c Mon Sep 17 00:00:00 2001 From: Jan Korous Date: Tue, 12 Mar 2019 14:11:11 -0700 Subject: [PATCH 6/7] [clang][index-while-building][IndexRecordHasher][NFC] Whitespace # Conflicts: # lib/Index/RecordHasher/CMakeLists.txt # lib/Index/RecordHasher/CachingHasher.cpp # lib/Index/RecordHasher/CachingHasher.h # lib/Index/RecordHasher/DeclHasher.cpp # lib/Index/RecordHasher/DeclHasher.h # lib/Index/RecordHasher/IndexRecordHasher.cpp --- lib/Index/RecordHasher/CMakeLists.txt | 1 - lib/Index/RecordHasher/CachingHasher.cpp | 10 +++++----- lib/Index/RecordHasher/CachingHasher.h | 2 +- lib/Index/RecordHasher/DeclHasher.cpp | 2 +- lib/Index/RecordHasher/DeclHasher.h | 2 +- lib/Index/RecordHasher/IndexRecordHasher.cpp | 2 +- 6 files changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/Index/RecordHasher/CMakeLists.txt b/lib/Index/RecordHasher/CMakeLists.txt index b01039948ed..239adfd80e9 100644 --- a/lib/Index/RecordHasher/CMakeLists.txt +++ b/lib/Index/RecordHasher/CMakeLists.txt @@ -13,4 +13,3 @@ add_clang_library(clangIndexRecordHasher clangAST clangBasic ) - \ No newline at end of file diff --git a/lib/Index/RecordHasher/CachingHasher.cpp b/lib/Index/RecordHasher/CachingHasher.cpp index 06e18be4512..7fae40c9b61 100644 --- a/lib/Index/RecordHasher/CachingHasher.cpp +++ b/lib/Index/RecordHasher/CachingHasher.cpp @@ -200,21 +200,21 @@ hash_code CachingHasher::hashImpl(const TemplateArgument &Arg) { case TemplateArgument::Template: Hash = hash_combine(Hash, hashImpl(Arg.getAsTemplateOrTemplatePattern())); break; - + case TemplateArgument::Expression: // FIXME: Hash expressions. break; - + case TemplateArgument::Pack: Hash = hash_combine(Hash, 'p'); for (const auto &P : Arg.pack_elements()) Hash = hash_combine(Hash, hashImpl(P)); break; - + case TemplateArgument::Type: Hash = hash_combine(Hash, hash(Arg.getAsType())); break; - + case TemplateArgument::Integral: Hash = hash_combine(Hash, 'V', hash(Arg.getIntegralType()), Arg.getAsIntegral()); @@ -340,4 +340,4 @@ hash_code CachingHasher::hashImpl(const NestedNameSpecifier *NNS) { } } // end namespace index -} // end namespace clang \ No newline at end of file +} // end namespace clang diff --git a/lib/Index/RecordHasher/CachingHasher.h b/lib/Index/RecordHasher/CachingHasher.h index adfbe40738e..dc7557552dd 100644 --- a/lib/Index/RecordHasher/CachingHasher.h +++ b/lib/Index/RecordHasher/CachingHasher.h @@ -57,4 +57,4 @@ class CachingHasher { } // end namespace index } // end namespace clang -#endif // LLVM_CLANG_LIB_INDEX_RECORDHASHER_CACHINGHASHER_H \ No newline at end of file +#endif // LLVM_CLANG_LIB_INDEX_RECORDHASHER_CACHINGHASHER_H diff --git a/lib/Index/RecordHasher/DeclHasher.cpp b/lib/Index/RecordHasher/DeclHasher.cpp index 633b3f791e3..a1746ccf4a3 100644 --- a/lib/Index/RecordHasher/DeclHasher.cpp +++ b/lib/Index/RecordHasher/DeclHasher.cpp @@ -137,4 +137,4 @@ hash_code DeclHasher::hashLoc(SourceLocation Loc, bool IncludeOffset) { } } // end namespace index -} // end namespace clang \ No newline at end of file +} // end namespace clang diff --git a/lib/Index/RecordHasher/DeclHasher.h b/lib/Index/RecordHasher/DeclHasher.h index 8f78a008200..6fff62e60dd 100644 --- a/lib/Index/RecordHasher/DeclHasher.h +++ b/lib/Index/RecordHasher/DeclHasher.h @@ -48,4 +48,4 @@ class DeclHasher : public ConstDeclVisitor { } // end namespace index } // end namespace clang -#endif // LLVM_CLANG_LIB_INDEX_RECORDHASHER_DECLHASHER_H \ No newline at end of file +#endif // LLVM_CLANG_LIB_INDEX_RECORDHASHER_DECLHASHER_H diff --git a/lib/Index/RecordHasher/IndexRecordHasher.cpp b/lib/Index/RecordHasher/IndexRecordHasher.cpp index 0431df02b44..431d9f3a5d0 100644 --- a/lib/Index/RecordHasher/IndexRecordHasher.cpp +++ b/lib/Index/RecordHasher/IndexRecordHasher.cpp @@ -30,4 +30,4 @@ hash_code hashRecord(ASTContext &Ctx, const FileIndexRecord &Record) { } } // end namespace index -} // end namespace clang \ No newline at end of file +} // end namespace clang From c4753a24b7d516d6863c25fc598bef2efa3c1d5f Mon Sep 17 00:00:00 2001 From: Jan Korous Date: Tue, 12 Mar 2019 14:08:46 -0700 Subject: [PATCH 7/7] [clang][index-while-building][IndexRecordHasher][NFC] Small refactoring based on review --- lib/Index/RecordHasher/CachingHasher.cpp | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/lib/Index/RecordHasher/CachingHasher.cpp b/lib/Index/RecordHasher/CachingHasher.cpp index 7fae40c9b61..a644bba6294 100644 --- a/lib/Index/RecordHasher/CachingHasher.cpp +++ b/lib/Index/RecordHasher/CachingHasher.cpp @@ -25,8 +25,8 @@ hash_code CachingHasher::hash(const Decl *D) { return getCachedHash(D, D); } else { // There's a balance between caching results and not growing the cache too - // much. Measurements showed that avoiding caching all decls is beneficial - // particularly when including all of Cocoa. + // much. Measurements showed that avoiding caching hashes for all decls is + // beneficial particularly when including all of Cocoa. return hashImpl(D); } } @@ -41,10 +41,6 @@ hash_code CachingHasher::hash(CanQualType CT) { // storing the hash for both the type and its const-qualified version. hash_code Hash = InitialHash; - auto asCanon = [](QualType Ty) -> CanQualType { - return CanQualType::CreateUnsafe(Ty); - }; - while (true) { Qualifiers Q = CT.getQualifiers(); CT = CT.getUnqualifiedType(); @@ -59,29 +55,29 @@ hash_code CachingHasher::hash(CanQualType CT) { if(qVal) Hash = hash_combine(Hash, qVal); - // Hash in ObjC GC qualifiers? + // FIXME: Hash in ObjC GC qualifiers if (const BuiltinType *BT = dyn_cast(T)) { return hash_combine(Hash, BT->getKind()); } if (const PointerType *PT = dyn_cast(T)) { Hash = hash_combine(Hash, '*'); - CT = asCanon(PT->getPointeeType()); + CT = CanQualType::CreateUnsafe(PT->getPointeeType()); continue; } if (const ReferenceType *RT = dyn_cast(T)) { Hash = hash_combine(Hash, '&'); - CT = asCanon(RT->getPointeeType()); + CT = CanQualType::CreateUnsafe(RT->getPointeeType()); continue; } if (const BlockPointerType *BT = dyn_cast(T)) { Hash = hash_combine(Hash, 'B'); - CT = asCanon(BT->getPointeeType()); + CT = CanQualType::CreateUnsafe(BT->getPointeeType()); continue; } if (const ObjCObjectPointerType *OPT = dyn_cast(T)) { Hash = hash_combine(Hash, '*'); - CT = asCanon(OPT->getPointeeType()); + CT = CanQualType::CreateUnsafe(OPT->getPointeeType()); continue; } if (const TagType *TT = dyn_cast(T)) { @@ -93,14 +89,14 @@ hash_code CachingHasher::hash(CanQualType CT) { if (const ObjCObjectType *OIT = dyn_cast(T)) { for (auto *Prot : OIT->getProtocols()) Hash = hash_combine(Hash, hash(Prot)); - CT = asCanon(OIT->getBaseType()); + CT = CanQualType::CreateUnsafe(OIT->getBaseType()); continue; } if (const TemplateTypeParmType *TTP = dyn_cast(T)) { return hash_combine(Hash, 't', TTP->getDepth(), TTP->getIndex()); } if (const InjectedClassNameType *InjT = dyn_cast(T)) { - CT = asCanon(InjT->getInjectedSpecializationType().getCanonicalType()); + CT = CanQualType::CreateUnsafe(InjT->getInjectedSpecializationType().getCanonicalType()); continue; } @@ -329,8 +325,6 @@ hash_code CachingHasher::hashImpl(const NestedNameSpecifier *NNS) { break; case NestedNameSpecifier::TypeSpecWithTemplate: - // Fall through to hash the type. - case NestedNameSpecifier::TypeSpec: Hash = hash_combine(Hash, hash(QualType(NNS->getAsType(), 0))); break;