jkorous updated this revision to Diff 190342.
jkorous marked 2 inline comments as done.
jkorous added a comment.

Addressed some of Dmitri's comments.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D58749/new/

https://reviews.llvm.org/D58749

Files:
  clang/lib/Index/CMakeLists.txt
  clang/lib/Index/IndexRecordHasher.h
  clang/lib/Index/RecordHasher/CMakeLists.txt
  clang/lib/Index/RecordHasher/CachingHasher.cpp
  clang/lib/Index/RecordHasher/CachingHasher.h
  clang/lib/Index/RecordHasher/DeclHasher.cpp
  clang/lib/Index/RecordHasher/DeclHasher.h
  clang/lib/Index/RecordHasher/IndexRecordHasher.cpp

Index: clang/lib/Index/RecordHasher/IndexRecordHasher.cpp
===================================================================
--- /dev/null
+++ clang/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
Index: clang/lib/Index/RecordHasher/DeclHasher.h
===================================================================
--- /dev/null
+++ clang/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<DeclHasher, llvm::hash_code> {
+  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
Index: clang/lib/Index/RecordHasher/DeclHasher.cpp
===================================================================
--- /dev/null
+++ clang/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<OverloadableAttr>()) ||
+      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<Decl>(DC)->getCanonicalDecl();
+  if (auto *ND = dyn_cast<NamedDecl>(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<FileID, unsigned> &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
Index: clang/lib/Index/RecordHasher/CachingHasher.h
===================================================================
--- /dev/null
+++ clang/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<const void *, llvm::hash_code> 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 <typename T> 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
Index: clang/lib/Index/RecordHasher/CachingHasher.cpp
===================================================================
--- /dev/null
+++ clang/lib/Index/RecordHasher/CachingHasher.cpp
@@ -0,0 +1,337 @@
+//===--- 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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RecordHasher/CachingHasher.h"
+#include "RecordHasher/DeclHasher.h"
+
+namespace clang {
+namespace index {
+
+using llvm::hash_code;
+
+hash_code CachingHasher::hash(const Decl *D) {
+  assert(D->isCanonicalDecl());
+
+  if (isa<TagDecl>(D) || isa<ObjCContainerDecl>(D)) {
+    return getCachedHash(D, D);
+  } else  if (auto *NS = dyn_cast<NamespaceDecl>(D)) {
+    if (NS->isAnonymousNamespace())
+      return hash_value(StringRef("@aN"));
+    return getCachedHash(D, D);
+  } else {
+    // There's a balance between caching results and not growing the cache too
+    // much. Measurements showed that avoiding caching hashes for all decls is
+    // beneficial particularly when including all of Cocoa.
+    return hashImpl(D);
+  }
+}
+
+hash_code CachingHasher::hash(QualType NonCanTy) {
+  CanQualType CanTy = Ctx.getCanonicalType(NonCanTy);
+  return hash(CanTy);
+}
+
+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;
+
+  while (true) {
+    Qualifiers Q = CT.getQualifiers();
+    CT = CT.getUnqualifiedType();
+    const Type *T = CT.getTypePtr();
+    unsigned qVal = 0;
+    if (Q.hasConst())
+      qVal |= 0x1;
+    if (Q.hasVolatile())
+      qVal |= 0x2;
+    if (Q.hasRestrict())
+      qVal |= 0x4;
+    if(qVal)
+      Hash = hash_combine(Hash, qVal);
+
+    // FIXME: Hash in ObjC GC qualifiers
+
+    if (const BuiltinType *BT = dyn_cast<BuiltinType>(T)) {
+      return hash_combine(Hash, BT->getKind());
+    }
+    if (const PointerType *PT = dyn_cast<PointerType>(T)) {
+      Hash = hash_combine(Hash, '*');
+      CT = CanQualType::CreateUnsafe(PT->getPointeeType());
+      continue;
+    }
+    if (const ReferenceType *RT = dyn_cast<ReferenceType>(T)) {
+      Hash = hash_combine(Hash, '&');
+      CT = CanQualType::CreateUnsafe(RT->getPointeeType());
+      continue;
+    }
+    if (const BlockPointerType *BT = dyn_cast<BlockPointerType>(T)) {
+      Hash = hash_combine(Hash, 'B');
+      CT = CanQualType::CreateUnsafe(BT->getPointeeType());
+      continue;
+    }
+    if (const ObjCObjectPointerType *OPT = dyn_cast<ObjCObjectPointerType>(T)) {
+      Hash = hash_combine(Hash, '*');
+      CT = CanQualType::CreateUnsafe(OPT->getPointeeType());
+      continue;
+    }
+    if (const TagType *TT = dyn_cast<TagType>(T)) {
+      return hash_combine(Hash, '$', hash(TT->getDecl()->getCanonicalDecl()));
+    }
+    if (const ObjCInterfaceType *OIT = dyn_cast<ObjCInterfaceType>(T)) {
+      return hash_combine(Hash, '$', hash(OIT->getDecl()->getCanonicalDecl()));
+    }
+    if (const ObjCObjectType *OIT = dyn_cast<ObjCObjectType>(T)) {
+      for (auto *Prot : OIT->getProtocols())
+        Hash = hash_combine(Hash, hash(Prot));
+      CT = CanQualType::CreateUnsafe(OIT->getBaseType());
+      continue;
+    }
+    if (const TemplateTypeParmType *TTP = dyn_cast<TemplateTypeParmType>(T)) {
+      return hash_combine(Hash, 't', TTP->getDepth(), TTP->getIndex());
+    }
+    if (const InjectedClassNameType *InjT = dyn_cast<InjectedClassNameType>(T)) {
+      CT = CanQualType::CreateUnsafe(InjT->getInjectedSpecializationType().getCanonicalType());
+      continue;
+    }
+
+    break;
+  }
+
+  return hash_combine(Hash, getCachedHash(CT.getAsOpaquePtr(), CT));
+}
+
+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
+  // improvement or no difference for a couple of C++ single translation unit
+  // files. So we avoid caching DeclarationNames.
+  return hashImpl(Name);
+}
+
+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 getCachedHash(NNS, NNS);
+}
+
+hash_code CachingHasher::hash(const TemplateArgument &Arg) {
+  // No caching.
+  return hashImpl(Arg);
+}
+
+template <typename T>
+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 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.
+  HashByPtr[Ptr] = Hash;
+  return Hash;
+}
+
+hash_code CachingHasher::hashImpl(const Decl *D) {
+  return DeclHasher(*this).Visit(D);
+}
+
+hash_code CachingHasher::hashImpl(const IdentifierInfo *II) {
+  return hash_value(II->getName());
+}
+
+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, hashImpl(II));
+  return Hash;
+}
+
+hash_code CachingHasher::hashImpl(TemplateName Name) {
+  hash_code Hash = InitialHash;
+  if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
+    if (TemplateTemplateParmDecl *TTP
+        = dyn_cast<TemplateTemplateParmDecl>(Template)) {
+      return hash_combine(Hash, 't', TTP->getDepth(), TTP->getIndex());
+    }
+
+    return hash_combine(Hash, hash(Template->getCanonicalDecl()));
+  }
+
+  // FIXME: Hash dependent template names.
+  return Hash;
+}
+
+hash_code CachingHasher::hashImpl(const TemplateArgument &Arg) {
+  hash_code Hash = InitialHash;
+
+  switch (Arg.getKind()) {
+  case TemplateArgument::Null:
+    break;
+
+  case TemplateArgument::Declaration:
+    Hash = hash_combine(Hash, hash(Arg.getAsDecl()));
+    break;
+
+  case TemplateArgument::NullPtr:
+    break;
+
+  case TemplateArgument::TemplateExpansion:
+    Hash = hash_combine(Hash, 'P'); // pack expansion of...
+    LLVM_FALLTHROUGH;
+  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());
+    break;
+  }
+
+  return Hash;
+}
+
+hash_code CachingHasher::hashImpl(CanQualType CQT) {
+  hash_code Hash = InitialHash;
+
+  auto asCanon = [](QualType Ty) -> CanQualType {
+    return CanQualType::CreateUnsafe(Ty);
+  };
+
+  const Type *T = CQT.getTypePtr();
+
+  if (const PackExpansionType *Expansion = dyn_cast<PackExpansionType>(T)) {
+    return hash_combine(Hash, 'P', hash(asCanon(Expansion->getPattern())));
+  }
+  if (const RValueReferenceType *RT = dyn_cast<RValueReferenceType>(T)) {
+    return hash_combine(Hash, '%', hash(asCanon(RT->getPointeeType())));
+  }
+  if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(T)) {
+    Hash = hash_combine(Hash, 'F', hash(asCanon(FT->getReturnType())));
+    for (const auto &I : FT->param_types())
+      Hash = hash_combine(Hash, hash(asCanon(I)));
+    return hash_combine(Hash, FT->isVariadic());
+  }
+  if (const ComplexType *CT = dyn_cast<ComplexType>(T)) {
+    return hash_combine(Hash, '<', hash(asCanon(CT->getElementType())));
+  }
+  if (const TemplateSpecializationType *Spec
+      = dyn_cast<TemplateSpecializationType>(T)) {
+    Hash = hash_combine(Hash, '>', hashImpl(Spec->getTemplateName()));
+    for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
+      Hash = hash_combine(Hash, hashImpl(Spec->getArg(I)));
+    return Hash;
+  }
+  if (const DependentNameType *DNT = dyn_cast<DependentNameType>(T)) {
+    Hash = hash_combine(Hash, '^');
+    if (const NestedNameSpecifier *NNS = DNT->getQualifier())
+      Hash = hash_combine(Hash, hash(NNS));
+    return hash_combine(Hash, hashImpl(DNT->getIdentifier()));
+  }
+
+  // Unhandled type.
+  return Hash;
+}
+
+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, hashImpl(Name.getAsIdentifierInfo()));
+      break;
+    case DeclarationName::ObjCZeroArgSelector:
+    case DeclarationName::ObjCOneArgSelector:
+    case DeclarationName::ObjCMultiArgSelector:
+      Hash = hash_combine(Hash, hashImpl(Name.getObjCSelector()));
+      break;
+    case DeclarationName::CXXConstructorName:
+    case DeclarationName::CXXDestructorName:
+    case DeclarationName::CXXConversionFunctionName:
+      break;
+    case DeclarationName::CXXOperatorName:
+      Hash = hash_combine(Hash, Name.getCXXOverloadedOperator());
+      break;
+    case DeclarationName::CXXLiteralOperatorName:
+      Hash = hash_combine(Hash, hashImpl(Name.getCXXLiteralIdentifier()));
+      break;
+    case DeclarationName::CXXUsingDirective:
+      break;
+    case DeclarationName::CXXDeductionGuideName:
+      Hash = hash_combine(Hash, hashImpl(Name.getCXXDeductionGuideTemplate()
+                                             ->getDeclName()
+                                             .getAsIdentifierInfo()));
+      break;
+  }
+
+  return Hash;
+}
+
+hash_code CachingHasher::hashImpl(const NestedNameSpecifier *NNS) {
+  hash_code Hash = InitialHash;
+  if (auto *Pre = NNS->getPrefix())
+    Hash = hash_combine(Hash, hash(Pre));
+
+  Hash = hash_combine(Hash, NNS->getKind());
+
+  switch (NNS->getKind()) {
+  case NestedNameSpecifier::Identifier:
+    Hash = hash_combine(Hash, hashImpl(NNS->getAsIdentifier()));
+    break;
+
+  case NestedNameSpecifier::Namespace:
+    Hash = hash_combine(Hash, hash(NNS->getAsNamespace()->getCanonicalDecl()));
+    break;
+
+  case NestedNameSpecifier::NamespaceAlias:
+    Hash = hash_combine(Hash,
+                        hash(NNS->getAsNamespaceAlias()->getCanonicalDecl()));
+    break;
+
+  case NestedNameSpecifier::Global:
+    break;
+
+  case NestedNameSpecifier::Super:
+    break;
+
+  case NestedNameSpecifier::TypeSpecWithTemplate:
+  case NestedNameSpecifier::TypeSpec:
+    Hash = hash_combine(Hash, hash(QualType(NNS->getAsType(), 0)));
+    break;
+  }
+
+  return Hash;
+}
+
+} // end namespace index
+} // end namespace clang
Index: clang/lib/Index/RecordHasher/CMakeLists.txt
===================================================================
--- /dev/null
+++ clang/lib/Index/RecordHasher/CMakeLists.txt
@@ -0,0 +1,15 @@
+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
+  )
Index: clang/lib/Index/IndexRecordHasher.h
===================================================================
--- /dev/null
+++ clang/lib/Index/IndexRecordHasher.h
@@ -0,0 +1,25 @@
+//===--- 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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_INDEX_INDEXRECORDHASHER_H
+#define LLVM_CLANG_LIB_INDEX_INDEXRECORDHASHER_H
+
+#include "clang/AST/ASTContext.h"
+#include "llvm/ADT/Hashing.h"
+
+namespace clang {
+namespace index {
+  class FileIndexRecord;
+
+  /// \returns hash of the \p Record
+  llvm::hash_code hashRecord(ASTContext &Ctx, const FileIndexRecord &Record);
+
+} // end namespace index
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_INDEX_INDEXRECORDHASHER_H
Index: clang/lib/Index/CMakeLists.txt
===================================================================
--- clang/lib/Index/CMakeLists.txt
+++ clang/lib/Index/CMakeLists.txt
@@ -28,4 +28,7 @@
   clangRewrite
   clangSerialization
   clangToolingCore
+  clangIndexRecordHasher
   )
+
+add_subdirectory(RecordHasher)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to