]> granicus.if.org Git - clang/commitdiff
Module Debugging: Emit debug type information into clang ObjC modules.
authorAdrian Prantl <aprantl@apple.com>
Tue, 8 Sep 2015 20:41:52 +0000 (20:41 +0000)
committerAdrian Prantl <aprantl@apple.com>
Tue, 8 Sep 2015 20:41:52 +0000 (20:41 +0000)
When -fmodule-format is set to "obj", emit debug info for all types
declared in a module or referenced by a declaration into the module's
object file container.

This patch adds support for Objective-C types and methods.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@247068 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGDebugInfo.cpp
lib/CodeGen/CGDebugInfo.h
lib/CodeGen/ObjectFilePCHContainerOperations.cpp
test/Modules/Inputs/DebugModule.h [deleted file]
test/Modules/Inputs/DebugObjC.h [new file with mode: 0644]
test/Modules/Inputs/module.map
test/Modules/ModuleDebugInfo.m [new file with mode: 0644]
test/Modules/debug-info-moduleimport.m

index d9101f833c716a7d08e491f8300d8807638ebf43..cc57f27d60a169bb5652fa7a64855f49d74e943d 100644 (file)
@@ -2515,11 +2515,17 @@ llvm::DISubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D,
 
     Elts.push_back(getOrCreateType(ResultTy, F));
     // "self" pointer is always first argument.
-    QualType SelfDeclTy = OMethod->getSelfDecl()->getType();
-    Elts.push_back(CreateSelfType(SelfDeclTy, getOrCreateType(SelfDeclTy, F)));
+    QualType SelfDeclTy;
+    if (auto *SelfDecl = OMethod->getSelfDecl())
+      SelfDeclTy = SelfDecl->getType();
+    else if (auto *FPT = dyn_cast<FunctionProtoType>(FnType))
+      if (FPT->getNumParams() > 1)
+        SelfDeclTy = FPT->getParamType(0);
+    if (!SelfDeclTy.isNull())
+      Elts.push_back(CreateSelfType(SelfDeclTy, getOrCreateType(SelfDeclTy, F)));
     // "_cmd" pointer is always second argument.
     Elts.push_back(DBuilder.createArtificialType(
-        getOrCreateType(OMethod->getCmdDecl()->getType(), F)));
+        getOrCreateType(CGM.getContext().getObjCSelType(), F)));
     // Get rest of the arguments.
     for (const auto *PI : OMethod->params())
       Elts.push_back(getOrCreateType(PI->getType(), F));
@@ -2623,6 +2629,49 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc,
     RegionMap[D].reset(SP);
 }
 
+void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc,
+                                   QualType FnType) {
+  StringRef Name;
+  StringRef LinkageName;
+
+  const Decl *D = GD.getDecl();
+  if (!D)
+    return;
+
+  unsigned Flags = 0;
+  llvm::DIFile *Unit = getOrCreateFile(Loc);
+  llvm::DIScope *FDContext = Unit;
+  llvm::DINodeArray TParamsArray;
+  if (isa<FunctionDecl>(D)) {
+    // If there is a DISubprogram for this function available then use it.
+    collectFunctionDeclProps(GD, Unit, Name, LinkageName, FDContext,
+                             TParamsArray, Flags);
+  } else if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) {
+    Name = getObjCMethodName(OMD);
+    Flags |= llvm::DINode::FlagPrototyped;
+  } else {
+    llvm_unreachable("not a function or ObjC method");
+  }
+  if (!Name.empty() && Name[0] == '\01')
+    Name = Name.substr(1);
+
+  if (D->isImplicit()) {
+    Flags |= llvm::DINode::FlagArtificial;
+    // Artificial functions without a location should not silently reuse CurLoc.
+    if (Loc.isInvalid())
+      CurLoc = SourceLocation();
+  }
+  unsigned LineNo = getLineNumber(Loc);
+  unsigned ScopeLine = 0;
+
+  DBuilder.createFunction(FDContext, Name, LinkageName, Unit, LineNo,
+                          getOrCreateFunctionType(D, FnType, Unit),
+                          false /*internalLinkage*/, true /*definition*/,
+                          ScopeLine, Flags, CGM.getLangOpts().Optimize, nullptr,
+                          TParamsArray.get(),
+                          getFunctionDeclaration(D));
+}
+
 void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) {
   // Update our current location
   setLocation(Loc);
index 1880335cc0bdd642dbb45aeb807058126d020f55..99272e60ebd073b835e0849917e27383ecec9a51 100644 (file)
@@ -281,6 +281,9 @@ public:
                          SourceLocation ScopeLoc, QualType FnType,
                          llvm::Function *Fn, CGBuilderTy &Builder);
 
+  /// Emit debug info for a function declaration.
+  void EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc, QualType FnType);
+
   /// Constructs the debug code for exiting a function.
   void EmitFunctionEnd(CGBuilderTy &Builder);
 
index a7c8230dc66e134472dbc9024b534b99d9b62130..54a38308694ebec7fa115d0b60b87c208e149c38 100644 (file)
@@ -76,6 +76,48 @@ class PCHContainerGenerator : public ASTConsumer {
       return true;
     }
 
+    bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+      QualType QualTy(D->getTypeForDecl(), 0);
+      if (!QualTy.isNull() && CanRepresent(QualTy.getTypePtr()))
+        DI.getOrCreateStandaloneType(QualTy, D->getLocation());
+      return true;
+    }
+
+    bool VisitFunctionDecl(FunctionDecl *D) {
+      if (isa<CXXMethodDecl>(D))
+        // This is not yet supported. Constructing the `this' argument
+        // mandates a CodeGenFunction.
+        return true;
+
+      SmallVector<QualType, 16> ArgTypes;
+      for (auto i : D->params())
+        ArgTypes.push_back(i->getType());
+      QualType RetTy = D->getReturnType();
+      QualType FnTy = Ctx.getFunctionType(RetTy, ArgTypes,
+                                          FunctionProtoType::ExtProtoInfo());
+      if (CanRepresent(FnTy.getTypePtr()))
+        DI.EmitFunctionDecl(D, D->getLocation(), FnTy);
+      return true;
+    }
+
+    bool VisitObjCMethodDecl(ObjCMethodDecl *D) {
+      if (!D->getClassInterface())
+        return true;
+
+      bool selfIsPseudoStrong, selfIsConsumed;
+      SmallVector<QualType, 16> ArgTypes;
+      ArgTypes.push_back(D->getSelfType(Ctx, D->getClassInterface(),
+                                        selfIsPseudoStrong, selfIsConsumed));
+      ArgTypes.push_back(Ctx.getObjCSelType());
+      for (auto i : D->params())
+        ArgTypes.push_back(i->getType());
+      QualType RetTy = D->getReturnType();
+      QualType FnTy = Ctx.getFunctionType(RetTy, ArgTypes,
+                                          FunctionProtoType::ExtProtoInfo());
+      if (CanRepresent(FnTy.getTypePtr()))
+        DI.EmitFunctionDecl(D, D->getLocation(), FnTy);
+      return true;
+    }
   };
 
 public:
diff --git a/test/Modules/Inputs/DebugModule.h b/test/Modules/Inputs/DebugModule.h
deleted file mode 100644 (file)
index 5612b73..0000000
+++ /dev/null
@@ -1 +0,0 @@
-@class F;
diff --git a/test/Modules/Inputs/DebugObjC.h b/test/Modules/Inputs/DebugObjC.h
new file mode 100644 (file)
index 0000000..8802f4b
--- /dev/null
@@ -0,0 +1,11 @@
+@interface ObjCClass {
+  int ivar;
+}
++ classMethod;
+- instanceMethodWithInt:(int)i;
+@property int property;
+@end
+
+@interface ObjCClass (Category)
+- categoryMethod;
+@end
index ba1178efc365e89a6b062dc17cafaded7a43a9f0..79a9a47e5847a0ca25dcca1637941e02b752c0b4 100644 (file)
@@ -328,14 +328,14 @@ module crash {
   header "crash.h"
 }
 
-module DebugModule {
-  header "DebugModule.h"
-}
-
 module DebugCXX {
   header "DebugCXX.h"
 }
 
+module DebugObjC {
+  header "DebugObjC.h"
+}
+
 module ImportNameInDir {
   header "ImportNameInDir.h"
   export *
diff --git a/test/Modules/ModuleDebugInfo.m b/test/Modules/ModuleDebugInfo.m
new file mode 100644 (file)
index 0000000..49ec76d
--- /dev/null
@@ -0,0 +1,27 @@
+// Test that debug info is emitted for an Objective-C module and
+// a precompiled header.
+
+// REQUIRES: asserts, shell
+
+// Modules:
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c -fmodules -fmodule-format=obj -fimplicit-module-maps -DMODULES -fmodules-cache-path=%t %s -I %S/Inputs -I %t -emit-llvm -o %t.ll -mllvm -debug-only=pchcontainer &>%t-mod.ll
+// RUN: cat %t-mod.ll | FileCheck %s
+
+// PCH:
+// RUN: %clang_cc1 -x objective-c -emit-pch -fmodule-format=obj -I %S/Inputs -o %t.pch %S/Inputs/DebugObjC.h -mllvm -debug-only=pchcontainer &>%t-pch.ll
+// RUN: cat %t-pch.ll | FileCheck %s
+
+#ifdef MODULES
+@import DebugObjC;
+#endif
+
+// CHECK: distinct !DICompileUnit(language: DW_LANG_ObjC
+// CHECK-SAME:                    isOptimized: false,
+// CHECK-SAME:                    splitDebugFilename:
+// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "ObjCClass"
+// CHECK: !DIObjCProperty(name: "property",
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "ivar"
+// CHECK: !DISubprogram(name: "+[ObjCClass classMethod]"
+// CHECK: !DISubprogram(name: "-[ObjCClass instanceMethodWithInt:]"
+// CHECK: !DISubprogram(name: "-[ categoryMethod]"
index 1f12b0270be4a063a2d62355715083529a87be4c..ce2257971910bea96f397e286a006793c7e9f04b 100644 (file)
@@ -2,6 +2,6 @@
 // RUN: %clang_cc1 -g -fmodules -DGREETING="Hello World" -UNDEBUG -fimplicit-module-maps -fmodules-cache-path=%t %s -I %S/Inputs -isysroot /tmp/.. -I %t -emit-llvm -o - | FileCheck %s
 
 // CHECK: ![[CU:.*]] = distinct !DICompileUnit
-@import DebugModule;
+@import DebugObjC;
 // CHECK: !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: ![[CU]], entity: ![[MODULE:.*]], line: 5)
-// CHECK: ![[MODULE]] = !DIModule(scope: null, name: "DebugModule", configMacros: "\22-DGREETING=Hello World\22 \22-UNDEBUG\22", includePath: "{{.*}}test{{.*}}Modules{{.*}}Inputs", isysroot: "/tmp/..")
+// CHECK: ![[MODULE]] = !DIModule(scope: null, name: "DebugObjC", configMacros: "\22-DGREETING=Hello World\22 \22-UNDEBUG\22", includePath: "{{.*}}test{{.*}}Modules{{.*}}Inputs", isysroot: "/tmp/..")