[NativePDB] Add support for reading function signatures.

This adds support for parsing function signature records and returning
them through the native DIA interface.

llvm-svn: 342780
diff --git a/llvm/lib/DebugInfo/PDB/CMakeLists.txt b/llvm/lib/DebugInfo/PDB/CMakeLists.txt
index db39ba3..3ec5d05 100644
--- a/llvm/lib/DebugInfo/PDB/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/PDB/CMakeLists.txt
@@ -54,6 +54,7 @@
   Native/NativeSymbolEnumerator.cpp
   Native/NativeTypeBuiltin.cpp
   Native/NativeTypeEnum.cpp
+  Native/NativeTypeFunctionSig.cpp
   Native/NativeTypePointer.cpp
   Native/NativeTypeUDT.cpp
   Native/NamedStreamMap.cpp
diff --git a/llvm/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp
index 9ec2f74..5fa783d 100644
--- a/llvm/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp
+++ b/llvm/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp
@@ -245,7 +245,7 @@
   RAW_METHOD_DUMP(OS, baseSymbolId);
   RAW_METHOD_DUMP_AS(OS, baseType, PDB_BuiltinType);
   RAW_METHOD_DUMP(OS, bitPosition);
-  RAW_METHOD_DUMP(OS, callingConvention);
+  RAW_METHOD_DUMP_AS(OS, callingConvention, PDB_CallingConv);
   RAW_ID_METHOD_DUMP(OS, classParentId, Session, PdbSymbolIdField::ClassParent,
                      ShowIdFields, RecurseIdFields);
   RAW_METHOD_DUMP(OS, compilerName);
diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp
index f16b776..288a912 100644
--- a/llvm/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp
@@ -48,15 +48,17 @@
   }
 }
 
+NativeEnumTypes::NativeEnumTypes(NativeSession &PDBSession,
+                                 std::vector<codeview::TypeIndex> Indices)
+    : Matches(std::move(Indices)), Index(0), Session(PDBSession) {}
+
 uint32_t NativeEnumTypes::getChildCount() const {
   return static_cast<uint32_t>(Matches.size());
 }
 
-std::unique_ptr<PDBSymbol>
-NativeEnumTypes::getChildAtIndex(uint32_t Index) const {
-  if (Index < Matches.size()) {
-    SymIndexId Id =
-        Session.getSymbolCache().findSymbolByTypeIndex(Matches[Index]);
+std::unique_ptr<PDBSymbol> NativeEnumTypes::getChildAtIndex(uint32_t N) const {
+  if (N < Matches.size()) {
+    SymIndexId Id = Session.getSymbolCache().findSymbolByTypeIndex(Matches[N]);
     return Session.getSymbolCache().getSymbolById(Id);
   }
   return nullptr;
diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp
index ca17380..bcc2198 100644
--- a/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp
@@ -49,6 +49,10 @@
     return Session.getSymbolCache().createTypeEnumerator(
         {codeview::LF_STRUCTURE, codeview::LF_CLASS, codeview::LF_UNION,
          codeview::LF_INTERFACE});
+  case PDB_SymType::FunctionSig:
+    return Session.getSymbolCache().createTypeEnumerator(
+        {codeview::LF_PROCEDURE, codeview::LF_MFUNCTION});
+
   default:
     break;
   }
diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeTypeBuiltin.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeTypeBuiltin.cpp
index 824d9bd..7b0f13f 100644
--- a/llvm/lib/DebugInfo/PDB/Native/NativeTypeBuiltin.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/NativeTypeBuiltin.cpp
@@ -10,12 +10,13 @@
 #include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h"
 #include "llvm/Support/FormatVariadic.h"
 
-namespace llvm {
-namespace pdb {
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
 
 NativeTypeBuiltin::NativeTypeBuiltin(NativeSession &PDBSession, SymIndexId Id,
-                                     codeview::ModifierOptions Mods,
-                                     PDB_BuiltinType T, uint64_t L)
+                                     ModifierOptions Mods, PDB_BuiltinType T,
+                                     uint64_t L)
     : NativeRawSymbol(PDBSession, PDB_SymType::BuiltinType, Id),
       Session(PDBSession), Mods(Mods), Type(T), Length(L) {}
 
@@ -31,13 +32,16 @@
 
 PDB_BuiltinType NativeTypeBuiltin::getBuiltinType() const { return Type; }
 
-bool NativeTypeBuiltin::isConstType() const { return false; }
+bool NativeTypeBuiltin::isConstType() const {
+  return (Mods & ModifierOptions::Const) != ModifierOptions::None;
+}
 
 uint64_t NativeTypeBuiltin::getLength() const { return Length; }
 
-bool NativeTypeBuiltin::isUnalignedType() const { return false; }
+bool NativeTypeBuiltin::isUnalignedType() const {
+  return (Mods & ModifierOptions::Unaligned) != ModifierOptions::None;
+}
 
-bool NativeTypeBuiltin::isVolatileType() const { return false; }
-
-} // namespace pdb
-} // namespace llvm
+bool NativeTypeBuiltin::isVolatileType() const {
+  return (Mods & ModifierOptions::Volatile) != ModifierOptions::None;
+}
diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeTypeFunctionSig.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeTypeFunctionSig.cpp
new file mode 100644
index 0000000..a798bcd
--- /dev/null
+++ b/llvm/lib/DebugInfo/PDB/Native/NativeTypeFunctionSig.cpp
@@ -0,0 +1,198 @@
+//===- NativeTypeFunctionSig.cpp - info about function signature -*- C++-*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Native/NativeTypeFunctionSig.h"
+
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+namespace {
+// This is kind of a silly class, hence why we keep it private to the file.
+// It's only purpose is to wrap the real type record.  I guess this is so that
+// we can have the lexical parent point to the function instead of the global
+// scope.
+class NativeTypeFunctionArg : public NativeRawSymbol {
+public:
+  NativeTypeFunctionArg(NativeSession &Session,
+                        std::unique_ptr<PDBSymbol> RealType)
+      : NativeRawSymbol(Session, PDB_SymType::FunctionArg, 0),
+        RealType(std::move(RealType)) {}
+
+  void dump(raw_ostream &OS, int Indent, PdbSymbolIdField ShowIdFields,
+            PdbSymbolIdField RecurseIdFields) const override {
+    NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
+
+    dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session,
+                      PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields);
+  }
+
+  SymIndexId getTypeId() const override { return RealType->getSymIndexId(); }
+
+  std::unique_ptr<PDBSymbol> RealType;
+};
+
+class NativeEnumFunctionArgs : public IPDBEnumChildren<PDBSymbol> {
+public:
+  NativeEnumFunctionArgs(NativeSession &Session,
+                         std::unique_ptr<NativeEnumTypes> TypeEnumerator)
+      : Session(Session), TypeEnumerator(std::move(TypeEnumerator)) {}
+
+  uint32_t getChildCount() const override {
+    return TypeEnumerator->getChildCount();
+  }
+  std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override {
+    return wrap(TypeEnumerator->getChildAtIndex(Index));
+  }
+  std::unique_ptr<PDBSymbol> getNext() override {
+    return wrap(TypeEnumerator->getNext());
+  }
+
+  void reset() override { TypeEnumerator->reset(); }
+
+private:
+  std::unique_ptr<PDBSymbol> wrap(std::unique_ptr<PDBSymbol> S) const {
+    if (!S)
+      return nullptr;
+    auto NTFA = llvm::make_unique<NativeTypeFunctionArg>(Session, std::move(S));
+    return PDBSymbol::create(Session, std::move(NTFA));
+  }
+  NativeSession &Session;
+  std::unique_ptr<NativeEnumTypes> TypeEnumerator;
+};
+} // namespace
+
+NativeTypeFunctionSig::NativeTypeFunctionSig(NativeSession &Session,
+                                             SymIndexId Id,
+                                             codeview::TypeIndex Index,
+                                             codeview::ProcedureRecord Proc)
+    : NativeRawSymbol(Session, PDB_SymType::FunctionSig, Id),
+      Proc(std::move(Proc)), Index(Index), IsMemberFunction(false) {}
+
+NativeTypeFunctionSig::NativeTypeFunctionSig(
+    NativeSession &Session, SymIndexId Id, codeview::TypeIndex Index,
+    codeview::MemberFunctionRecord MemberFunc)
+    : NativeRawSymbol(Session, PDB_SymType::FunctionSig, Id),
+      MemberFunc(std::move(MemberFunc)), Index(Index), IsMemberFunction(true) {}
+
+void NativeTypeFunctionSig::initialize() {
+  if (IsMemberFunction) {
+    ClassParentId =
+        Session.getSymbolCache().findSymbolByTypeIndex(MemberFunc.ClassType);
+    initializeArgList(MemberFunc.ArgumentList);
+  } else {
+    initializeArgList(Proc.ArgumentList);
+  }
+}
+
+NativeTypeFunctionSig::~NativeTypeFunctionSig() {}
+
+void NativeTypeFunctionSig::initializeArgList(codeview::TypeIndex ArgListTI) {
+  TpiStream &Tpi = cantFail(Session.getPDBFile().getPDBTpiStream());
+  CVType CVT = Tpi.typeCollection().getType(ArgListTI);
+
+  cantFail(TypeDeserializer::deserializeAs<ArgListRecord>(CVT, ArgList));
+}
+
+void NativeTypeFunctionSig::dump(raw_ostream &OS, int Indent,
+                                 PdbSymbolIdField ShowIdFields,
+                                 PdbSymbolIdField RecurseIdFields) const {
+
+  NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
+
+  dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session,
+                    PdbSymbolIdField::LexicalParent, ShowIdFields,
+                    RecurseIdFields);
+
+  dumpSymbolField(OS, "callingConvention", getCallingConvention(), Indent);
+  dumpSymbolField(OS, "count", getCount(), Indent);
+  dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session,
+                    PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields);
+  if (IsMemberFunction)
+    dumpSymbolField(OS, "thisAdjust", getThisAdjust(), Indent);
+  dumpSymbolField(OS, "constructor", hasConstructor(), Indent);
+  dumpSymbolField(OS, "constType", isConstType(), Indent);
+  dumpSymbolField(OS, "isConstructorVirtualBase", isConstructorVirtualBase(),
+                  Indent);
+  dumpSymbolField(OS, "isCxxReturnUdt", isCxxReturnUdt(), Indent);
+  dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent);
+  dumpSymbolField(OS, "volatileType", isVolatileType(), Indent);
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+NativeTypeFunctionSig::findChildren(PDB_SymType Type) const {
+  if (Type != PDB_SymType::FunctionArg)
+    return llvm::make_unique<NullEnumerator<PDBSymbol>>();
+
+  auto NET = llvm::make_unique<NativeEnumTypes>(Session,
+                                                /* copy */ ArgList.ArgIndices);
+  return std::unique_ptr<IPDBEnumSymbols>(
+      new NativeEnumFunctionArgs(Session, std::move(NET)));
+}
+
+SymIndexId NativeTypeFunctionSig::getClassParentId() const {
+  if (!IsMemberFunction)
+    return 0;
+
+  return ClassParentId;
+}
+
+PDB_CallingConv NativeTypeFunctionSig::getCallingConvention() const {
+  return IsMemberFunction ? MemberFunc.CallConv : Proc.CallConv;
+}
+
+uint32_t NativeTypeFunctionSig::getCount() const {
+  return IsMemberFunction ? (1 + MemberFunc.getParameterCount())
+                          : Proc.getParameterCount();
+}
+
+SymIndexId NativeTypeFunctionSig::getTypeId() const {
+  TypeIndex ReturnTI =
+      IsMemberFunction ? MemberFunc.getReturnType() : Proc.getReturnType();
+
+  return Session.getSymbolCache().findSymbolByTypeIndex(ReturnTI);
+}
+
+int32_t NativeTypeFunctionSig::getThisAdjust() const {
+  return IsMemberFunction ? MemberFunc.getThisPointerAdjustment() : 0;
+}
+
+bool NativeTypeFunctionSig::hasConstructor() const {
+  if (!IsMemberFunction)
+    return false;
+
+  return (MemberFunc.getOptions() & FunctionOptions::Constructor) !=
+         FunctionOptions::None;
+}
+
+bool NativeTypeFunctionSig::isConstType() const { return false; }
+
+bool NativeTypeFunctionSig::isConstructorVirtualBase() const {
+  if (!IsMemberFunction)
+    return false;
+
+  return (MemberFunc.getOptions() &
+          FunctionOptions::ConstructorWithVirtualBases) !=
+         FunctionOptions::None;
+}
+
+bool NativeTypeFunctionSig::isCxxReturnUdt() const {
+  FunctionOptions Options =
+      IsMemberFunction ? MemberFunc.getOptions() : Proc.getOptions();
+  return (Options & FunctionOptions::CxxReturnUdt) != FunctionOptions::None;
+}
+
+bool NativeTypeFunctionSig::isUnalignedType() const { return false; }
+
+bool NativeTypeFunctionSig::isVolatileType() const { return false; }
diff --git a/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp b/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp
index 4fd7adf..d4732fd 100644
--- a/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp
@@ -9,6 +9,7 @@
 #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
 #include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h"
 #include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h"
+#include "llvm/DebugInfo/PDB/Native/NativeTypeFunctionSig.h"
 #include "llvm/DebugInfo/PDB/Native/NativeTypePointer.h"
 #include "llvm/DebugInfo/PDB/Native/NativeTypeUDT.h"
 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
@@ -29,6 +30,7 @@
   uint32_t Size;
 } BuiltinTypes[] = {
     {codeview::SimpleTypeKind::None, PDB_BuiltinType::None, 0},
+    {codeview::SimpleTypeKind::Void, PDB_BuiltinType::Void, 0},
     {codeview::SimpleTypeKind::Int16Short, PDB_BuiltinType::Int, 2},
     {codeview::SimpleTypeKind::UInt16Short, PDB_BuiltinType::UInt, 2},
     {codeview::SimpleTypeKind::Int32, PDB_BuiltinType::Int, 4},
@@ -76,24 +78,16 @@
 
 SymIndexId SymbolCache::createSimpleType(TypeIndex Index,
                                          ModifierOptions Mods) {
-  if (Index.getSimpleMode() != codeview::SimpleTypeMode::Direct) {
-    SymIndexId Id = Cache.size();
-    Cache.emplace_back(
-        llvm::make_unique<NativeTypePointer>(Session, Id, Index));
-    return Id;
-  }
+  if (Index.getSimpleMode() != codeview::SimpleTypeMode::Direct)
+    return createSymbol<NativeTypePointer>(Index);
 
-  SymIndexId Id = Cache.size();
   const auto Kind = Index.getSimpleKind();
   const auto It = std::find_if(
       std::begin(BuiltinTypes), std::end(BuiltinTypes),
       [Kind](const BuiltinTypeEntry &Builtin) { return Builtin.Kind == Kind; });
   if (It == std::end(BuiltinTypes))
     return 0;
-  Cache.emplace_back(llvm::make_unique<NativeTypeBuiltin>(Session, Id, Mods,
-                                                          It->Type, It->Size));
-  TypeIndexToSymbolId[Index] = Id;
-  return Id;
+  return createSymbol<NativeTypeBuiltin>(Mods, It->Type, It->Size);
 }
 
 SymIndexId
@@ -135,8 +129,12 @@
     return Entry->second;
 
   // Symbols for built-in types are created on the fly.
-  if (Index.isSimple())
-    return createSimpleType(Index, ModifierOptions::None);
+  if (Index.isSimple()) {
+    SymIndexId Result = createSimpleType(Index, ModifierOptions::None);
+    assert(TypeIndexToSymbolId.count(Index) == 0);
+    TypeIndexToSymbolId[Index] = Result;
+    return Result;
+  }
 
   // We need to instantiate and cache the desired type symbol.
   auto Tpi = Session.getPDBFile().getPDBTpiStream();
@@ -157,6 +155,7 @@
       SymIndexId Result = findSymbolByTypeIndex(*EFD);
       // Record a mapping from ForwardRef -> SymIndex of complete type so that
       // we'll take the fast path next time.
+      assert(TypeIndexToSymbolId.count(Index) == 0);
       TypeIndexToSymbolId[Index] = Result;
       return Result;
     }
@@ -184,12 +183,22 @@
   case codeview::LF_MODIFIER:
     Id = createSymbolForModifiedType(Index, std::move(CVT));
     break;
+  case codeview::LF_PROCEDURE:
+    Id = createSymbolForType<NativeTypeFunctionSig, ProcedureRecord>(
+        Index, std::move(CVT));
+    break;
+  case codeview::LF_MFUNCTION:
+    Id = createSymbolForType<NativeTypeFunctionSig, MemberFunctionRecord>(
+        Index, std::move(CVT));
+    break;
   default:
     Id = createSymbolPlaceholder();
     break;
   }
-  if (Id != 0)
+  if (Id != 0) {
+    assert(TypeIndexToSymbolId.count(Index) == 0);
     TypeIndexToSymbolId[Index] = Id;
+  }
   return Id;
 }