]> granicus.if.org Git - clang/commitdiff
Add faux-body support for dispatch_once().
authorTed Kremenek <kremenek@apple.com>
Fri, 21 Sep 2012 00:52:24 +0000 (00:52 +0000)
committerTed Kremenek <kremenek@apple.com>
Fri, 21 Sep 2012 00:52:24 +0000 (00:52 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@164348 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/BodyFarm.cpp
test/Analysis/unix-fns.c

index 217f607d56f50c88a87c7be329e409d8046ae86d..c01d4e6fcba04c472a34221169f32906b4ac6a04 100644 (file)
@@ -22,6 +22,113 @@ using namespace clang;
 
 typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);
 
+static bool isDispatchBlock(QualType Ty) {
+  // Is it a block pointer?
+  const BlockPointerType *BPT = Ty->getAs<BlockPointerType>();
+  if (!BPT)
+    return false;
+
+  // Check if the block pointer type takes no arguments and
+  // returns void.
+  const FunctionProtoType *FT =
+  BPT->getPointeeType()->getAs<FunctionProtoType>();
+  if (!FT || !FT->getResultType()->isVoidType()  ||
+      FT->getNumArgs() != 0)
+    return false;
+
+  return true;
+}
+
+/// Create a fake body for dispatch_once.
+static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
+  // Check if we have at least two parameters.
+  if (D->param_size() != 2)
+    return 0;
+
+  // Check if the first parameter is a pointer to integer type.
+  const ParmVarDecl *Predicate = D->getParamDecl(0);
+  QualType PredicateQPtrTy = Predicate->getType();
+  const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>();
+  if (!PredicatePtrTy)
+    return 0;
+  QualType PredicateTy = PredicatePtrTy->getPointeeType();
+  if (!PredicateTy->isIntegerType())
+    return 0;
+  
+  // Check if the second parameter is the proper block type.
+  const ParmVarDecl *Block = D->getParamDecl(1);
+  QualType Ty = Block->getType();
+  if (!isDispatchBlock(Ty))
+    return 0;
+  
+  // Everything checks out.  Create a fakse body that checks the predicate,
+  // sets it, and calls the block.  Basically, an AST dump of:
+  //
+  // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) {
+  //  if (!*predicate) {
+  //    *predicate = 1;
+  //    block();
+  //  }
+  // }
+  
+  // (1) Create the call.
+  DeclRefExpr *DR = DeclRefExpr::CreateEmpty(C, false, false, false, false);
+  DR->setDecl(const_cast<ParmVarDecl*>(Block));
+  DR->setType(Ty);
+  DR->setValueKind(VK_LValue);
+  ImplicitCastExpr *ICE = ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,
+                                                   DR, 0, VK_RValue);
+  CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy,
+                                  VK_RValue, SourceLocation());
+
+  // (2) Create the assignment to the predicate.
+  IntegerLiteral *IL =
+    IntegerLiteral::Create(C, llvm::APInt(C.getTypeSize(C.IntTy), (uint64_t) 1),
+                           C.IntTy, SourceLocation());
+  ICE = ImplicitCastExpr::Create(C, PredicateTy, CK_IntegralCast, IL, 0,
+                                 VK_RValue);
+  DR = DeclRefExpr::CreateEmpty(C, false, false, false, false);
+  DR->setDecl(const_cast<ParmVarDecl*>(Predicate));
+  DR->setType(PredicateQPtrTy);
+  DR->setValueKind(VK_LValue);
+  ImplicitCastExpr *LValToRval =
+    ImplicitCastExpr::Create(C, PredicateQPtrTy, CK_LValueToRValue, DR,
+                             0, VK_RValue);
+  UnaryOperator *UO = new (C) UnaryOperator(LValToRval, UO_Deref, PredicateTy,
+                                            VK_LValue, OK_Ordinary,
+                                            SourceLocation());
+  BinaryOperator *B = new (C) BinaryOperator(UO, ICE, BO_Assign,
+                                             PredicateTy, VK_RValue,
+                                             OK_Ordinary,
+                                             SourceLocation());
+  // (3) Create the compound statement.
+  Stmt *Stmts[2];
+  Stmts[0] = B;
+  Stmts[1] = CE;  
+  CompoundStmt *CS = new (C) CompoundStmt(C, Stmts, 2, SourceLocation(),
+                                          SourceLocation());
+  
+  // (4) Create the 'if' condition.
+  DR = DeclRefExpr::CreateEmpty(C, false, false, false, false);
+  DR->setDecl(const_cast<ParmVarDecl*>(Predicate));
+  DR->setType(PredicateQPtrTy);
+  DR->setValueKind(VK_LValue);
+  LValToRval = ImplicitCastExpr::Create(C, PredicateQPtrTy, CK_LValueToRValue,
+                                        DR, 0, VK_RValue);
+  UO = new (C) UnaryOperator(LValToRval, UO_Deref, PredicateTy,
+                             VK_LValue, OK_Ordinary,
+                             SourceLocation());
+  LValToRval = ImplicitCastExpr::Create(C, PredicateTy, CK_LValueToRValue,
+                                        UO, 0, VK_RValue);
+  UO = new (C) UnaryOperator(LValToRval, UO_LNot, C.IntTy,
+                             VK_RValue, OK_Ordinary, SourceLocation());
+  
+  // (5) Create the 'if' statement.
+  IfStmt *If = new (C) IfStmt(C, SourceLocation(), 0, UO, CS);
+  return If;
+}
+
+  
 
 /// Create a fake body for dispatch_sync.
 static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
@@ -32,16 +139,7 @@ static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
   // Check if the second parameter is a block.
   const ParmVarDecl *PV = D->getParamDecl(1);
   QualType Ty = PV->getType();
-  const BlockPointerType *BPT = Ty->getAs<BlockPointerType>();
-  if (!BPT)
-    return 0;
-  
-  // Check if the block pointer type takes no arguments and
-  // returns void.
-  const FunctionProtoType *FT =
-    BPT->getPointeeType()->getAs<FunctionProtoType>();
-  if (!FT || !FT->getResultType()->isVoidType()  ||
-      FT->getNumArgs() != 0)
+  if (!isDispatchBlock(Ty))
     return 0;
 
   // Everything checks out.  Create a fake body that just calls the block.
@@ -53,6 +151,7 @@ static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
   //
   DeclRefExpr *DR = DeclRefExpr::CreateEmpty(C, false, false, false, false);
   DR->setDecl(const_cast<ParmVarDecl*>(PV));
+  DR->setType(Ty);
   DR->setValueKind(VK_LValue);
   ImplicitCastExpr *ICE = ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,
                                                    DR, 0, VK_RValue);
@@ -80,6 +179,7 @@ Stmt *BodyFarm::getBody(const FunctionDecl *D) {
   FunctionFarmer FF =
     llvm::StringSwitch<FunctionFarmer>(Name)
       .Case("dispatch_sync", create_dispatch_sync)
+      .Case("dispatch_once", create_dispatch_once)
       .Default(NULL);
   
   if (FF) {
index 23d08d281ad528463655ded634b9063170b0d1f2..1f1edad799c1b8678cd9a593e9576864788f1f8c 100644 (file)
@@ -181,6 +181,15 @@ void test_dispatch_sync(dispatch_queue_t queue, int *q) {
   });
 }
 
+// Test inlining if dispatch_once.
+void test_inline_dispatch_once() {
+  static dispatch_once_t pred;
+  int *p = 0;
+  dispatch_once(&pred, ^(void) {
+         *p = 1; // expected-warning {{null}}
+  });
+}
+
 // CHECK:  <key>diagnostics</key>
 // CHECK-NEXT:  <array>
 // CHECK-NEXT:   <dict>
@@ -1585,4 +1594,307 @@ void test_dispatch_sync(dispatch_queue_t queue, int *q) {
 // CHECK-NEXT:    <key>file</key><integer>0</integer>
 // CHECK-NEXT:   </dict>
 // CHECK-NEXT:   </dict>
+// CHECK-NEXT:   <dict>
+// CHECK-NEXT:    <key>path</key>
+// CHECK-NEXT:    <array>
+// CHECK-NEXT:     <dict>
+// CHECK-NEXT:      <key>kind</key><string>control</string>
+// CHECK-NEXT:      <key>edges</key>
+// CHECK-NEXT:       <array>
+// CHECK-NEXT:        <dict>
+// CHECK-NEXT:         <key>start</key>
+// CHECK-NEXT:          <array>
+// CHECK-NEXT:           <dict>
+// CHECK-NEXT:            <key>line</key><integer>186</integer>
+// CHECK-NEXT:            <key>col</key><integer>3</integer>
+// CHECK-NEXT:            <key>file</key><integer>0</integer>
+// CHECK-NEXT:           </dict>
+// CHECK-NEXT:           <dict>
+// CHECK-NEXT:            <key>line</key><integer>186</integer>
+// CHECK-NEXT:            <key>col</key><integer>8</integer>
+// CHECK-NEXT:            <key>file</key><integer>0</integer>
+// CHECK-NEXT:           </dict>
+// CHECK-NEXT:          </array>
+// CHECK-NEXT:         <key>end</key>
+// CHECK-NEXT:          <array>
+// CHECK-NEXT:           <dict>
+// CHECK-NEXT:            <key>line</key><integer>187</integer>
+// CHECK-NEXT:            <key>col</key><integer>3</integer>
+// CHECK-NEXT:            <key>file</key><integer>0</integer>
+// CHECK-NEXT:           </dict>
+// CHECK-NEXT:           <dict>
+// CHECK-NEXT:            <key>line</key><integer>187</integer>
+// CHECK-NEXT:            <key>col</key><integer>5</integer>
+// CHECK-NEXT:            <key>file</key><integer>0</integer>
+// CHECK-NEXT:           </dict>
+// CHECK-NEXT:          </array>
+// CHECK-NEXT:        </dict>
+// CHECK-NEXT:       </array>
+// CHECK-NEXT:     </dict>
+// CHECK-NEXT:     <dict>
+// CHECK-NEXT:      <key>kind</key><string>event</string>
+// CHECK-NEXT:      <key>location</key>
+// CHECK-NEXT:      <dict>
+// CHECK-NEXT:       <key>line</key><integer>187</integer>
+// CHECK-NEXT:       <key>col</key><integer>3</integer>
+// CHECK-NEXT:       <key>file</key><integer>0</integer>
+// CHECK-NEXT:      </dict>
+// CHECK-NEXT:      <key>ranges</key>
+// CHECK-NEXT:      <array>
+// CHECK-NEXT:        <array>
+// CHECK-NEXT:         <dict>
+// CHECK-NEXT:          <key>line</key><integer>187</integer>
+// CHECK-NEXT:          <key>col</key><integer>3</integer>
+// CHECK-NEXT:          <key>file</key><integer>0</integer>
+// CHECK-NEXT:         </dict>
+// CHECK-NEXT:         <dict>
+// CHECK-NEXT:          <key>line</key><integer>187</integer>
+// CHECK-NEXT:          <key>col</key><integer>8</integer>
+// CHECK-NEXT:          <key>file</key><integer>0</integer>
+// CHECK-NEXT:         </dict>
+// CHECK-NEXT:        </array>
+// CHECK-NEXT:      </array>
+// CHECK-NEXT:      <key>depth</key><integer>0</integer>
+// CHECK-NEXT:      <key>extended_message</key>
+// CHECK-NEXT:      <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT:      <key>message</key>
+// CHECK-NEXT:      <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT:     </dict>
+// CHECK-NEXT:     <dict>
+// CHECK-NEXT:      <key>kind</key><string>event</string>
+// CHECK-NEXT:      <key>location</key>
+// CHECK-NEXT:      <dict>
+// CHECK-NEXT:       <key>line</key><integer>188</integer>
+// CHECK-NEXT:       <key>col</key><integer>3</integer>
+// CHECK-NEXT:       <key>file</key><integer>0</integer>
+// CHECK-NEXT:      </dict>
+// CHECK-NEXT:      <key>ranges</key>
+// CHECK-NEXT:      <array>
+// CHECK-NEXT:        <array>
+// CHECK-NEXT:         <dict>
+// CHECK-NEXT:          <key>line</key><integer>188</integer>
+// CHECK-NEXT:          <key>col</key><integer>3</integer>
+// CHECK-NEXT:          <key>file</key><integer>0</integer>
+// CHECK-NEXT:         </dict>
+// CHECK-NEXT:         <dict>
+// CHECK-NEXT:          <key>line</key><integer>190</integer>
+// CHECK-NEXT:          <key>col</key><integer>4</integer>
+// CHECK-NEXT:          <key>file</key><integer>0</integer>
+// CHECK-NEXT:         </dict>
+// CHECK-NEXT:        </array>
+// CHECK-NEXT:      </array>
+// CHECK-NEXT:      <key>depth</key><integer>0</integer>
+// CHECK-NEXT:      <key>extended_message</key>
+// CHECK-NEXT:      <string>Calling &apos;_dispatch_once&apos;</string>
+// CHECK-NEXT:      <key>message</key>
+// CHECK-NEXT:      <string>Calling &apos;_dispatch_once&apos;</string>
+// CHECK-NEXT:     </dict>
+// CHECK-NEXT:     <dict>
+// CHECK-NEXT:      <key>kind</key><string>event</string>
+// CHECK-NEXT:      <key>location</key>
+// CHECK-NEXT:      <dict>
+// CHECK-NEXT:       <key>line</key><integer>162</integer>
+// CHECK-NEXT:       <key>col</key><integer>1</integer>
+// CHECK-NEXT:       <key>file</key><integer>0</integer>
+// CHECK-NEXT:      </dict>
+// CHECK-NEXT:      <key>depth</key><integer>1</integer>
+// CHECK-NEXT:      <key>extended_message</key>
+// CHECK-NEXT:      <string>Entered call from &apos;test_inline_dispatch_once&apos;</string>
+// CHECK-NEXT:      <key>message</key>
+// CHECK-NEXT:      <string>Entered call from &apos;test_inline_dispatch_once&apos;</string>
+// CHECK-NEXT:     </dict>
+// CHECK-NEXT:     <dict>
+// CHECK-NEXT:      <key>kind</key><string>control</string>
+// CHECK-NEXT:      <key>edges</key>
+// CHECK-NEXT:       <array>
+// CHECK-NEXT:        <dict>
+// CHECK-NEXT:         <key>start</key>
+// CHECK-NEXT:          <array>
+// CHECK-NEXT:           <dict>
+// CHECK-NEXT:            <key>line</key><integer>162</integer>
+// CHECK-NEXT:            <key>col</key><integer>1</integer>
+// CHECK-NEXT:            <key>file</key><integer>0</integer>
+// CHECK-NEXT:           </dict>
+// CHECK-NEXT:           <dict>
+// CHECK-NEXT:            <key>line</key><integer>162</integer>
+// CHECK-NEXT:            <key>col</key><integer>6</integer>
+// CHECK-NEXT:            <key>file</key><integer>0</integer>
+// CHECK-NEXT:           </dict>
+// CHECK-NEXT:          </array>
+// CHECK-NEXT:         <key>end</key>
+// CHECK-NEXT:          <array>
+// CHECK-NEXT:           <dict>
+// CHECK-NEXT:            <key>line</key><integer>164</integer>
+// CHECK-NEXT:            <key>col</key><integer>3</integer>
+// CHECK-NEXT:            <key>file</key><integer>0</integer>
+// CHECK-NEXT:           </dict>
+// CHECK-NEXT:           <dict>
+// CHECK-NEXT:            <key>line</key><integer>164</integer>
+// CHECK-NEXT:            <key>col</key><integer>15</integer>
+// CHECK-NEXT:            <key>file</key><integer>0</integer>
+// CHECK-NEXT:           </dict>
+// CHECK-NEXT:          </array>
+// CHECK-NEXT:        </dict>
+// CHECK-NEXT:       </array>
+// CHECK-NEXT:     </dict>
+// CHECK-NEXT:     <dict>
+// CHECK-NEXT:      <key>kind</key><string>event</string>
+// CHECK-NEXT:      <key>location</key>
+// CHECK-NEXT:      <dict>
+// CHECK-NEXT:       <key>line</key><integer>164</integer>
+// CHECK-NEXT:       <key>col</key><integer>3</integer>
+// CHECK-NEXT:       <key>file</key><integer>0</integer>
+// CHECK-NEXT:      </dict>
+// CHECK-NEXT:      <key>ranges</key>
+// CHECK-NEXT:      <array>
+// CHECK-NEXT:        <array>
+// CHECK-NEXT:         <dict>
+// CHECK-NEXT:          <key>line</key><integer>164</integer>
+// CHECK-NEXT:          <key>col</key><integer>3</integer>
+// CHECK-NEXT:          <key>file</key><integer>0</integer>
+// CHECK-NEXT:         </dict>
+// CHECK-NEXT:         <dict>
+// CHECK-NEXT:          <key>line</key><integer>164</integer>
+// CHECK-NEXT:          <key>col</key><integer>33</integer>
+// CHECK-NEXT:          <key>file</key><integer>0</integer>
+// CHECK-NEXT:         </dict>
+// CHECK-NEXT:        </array>
+// CHECK-NEXT:      </array>
+// CHECK-NEXT:      <key>depth</key><integer>1</integer>
+// CHECK-NEXT:      <key>extended_message</key>
+// CHECK-NEXT:      <string>Calling &apos;dispatch_once&apos;</string>
+// CHECK-NEXT:      <key>message</key>
+// CHECK-NEXT:      <string>Calling &apos;dispatch_once&apos;</string>
+// CHECK-NEXT:     </dict>
+// CHECK-NEXT:     <dict>
+// CHECK-NEXT:      <key>kind</key><string>event</string>
+// CHECK-NEXT:      <key>location</key>
+// CHECK-NEXT:      <dict>
+// CHECK-NEXT:       <key>line</key><integer>38</integer>
+// CHECK-NEXT:       <key>col</key><integer>1</integer>
+// CHECK-NEXT:       <key>file</key><integer>0</integer>
+// CHECK-NEXT:      </dict>
+// CHECK-NEXT:      <key>depth</key><integer>2</integer>
+// CHECK-NEXT:      <key>extended_message</key>
+// CHECK-NEXT:      <string>Entered call from &apos;_dispatch_once&apos;</string>
+// CHECK-NEXT:      <key>message</key>
+// CHECK-NEXT:      <string>Entered call from &apos;_dispatch_once&apos;</string>
+// CHECK-NEXT:     </dict>
+// CHECK-NEXT:     <dict>
+// CHECK-NEXT:      <key>kind</key><string>event</string>
+// CHECK-NEXT:      <key>location</key>
+// CHECK-NEXT:      <dict>
+// CHECK-NEXT:       <key>line</key><integer>164</integer>
+// CHECK-NEXT:       <key>col</key><integer>3</integer>
+// CHECK-NEXT:       <key>file</key><integer>0</integer>
+// CHECK-NEXT:      </dict>
+// CHECK-NEXT:      <key>ranges</key>
+// CHECK-NEXT:      <array>
+// CHECK-NEXT:        <array>
+// CHECK-NEXT:         <dict>
+// CHECK-NEXT:          <key>line</key><integer>164</integer>
+// CHECK-NEXT:          <key>col</key><integer>3</integer>
+// CHECK-NEXT:          <key>file</key><integer>0</integer>
+// CHECK-NEXT:         </dict>
+// CHECK-NEXT:         <dict>
+// CHECK-NEXT:          <key>line</key><integer>164</integer>
+// CHECK-NEXT:          <key>col</key><integer>33</integer>
+// CHECK-NEXT:          <key>file</key><integer>0</integer>
+// CHECK-NEXT:         </dict>
+// CHECK-NEXT:        </array>
+// CHECK-NEXT:      </array>
+// CHECK-NEXT:      <key>depth</key><integer>2</integer>
+// CHECK-NEXT:      <key>extended_message</key>
+// CHECK-NEXT:      <string>Calling anonymous block</string>
+// CHECK-NEXT:      <key>message</key>
+// CHECK-NEXT:      <string>Calling anonymous block</string>
+// CHECK-NEXT:     </dict>
+// CHECK-NEXT:     <dict>
+// CHECK-NEXT:      <key>kind</key><string>event</string>
+// CHECK-NEXT:      <key>location</key>
+// CHECK-NEXT:      <dict>
+// CHECK-NEXT:       <key>line</key><integer>188</integer>
+// CHECK-NEXT:       <key>col</key><integer>24</integer>
+// CHECK-NEXT:       <key>file</key><integer>0</integer>
+// CHECK-NEXT:      </dict>
+// CHECK-NEXT:      <key>depth</key><integer>3</integer>
+// CHECK-NEXT:      <key>extended_message</key>
+// CHECK-NEXT:      <string>Entered call from &apos;dispatch_once&apos;</string>
+// CHECK-NEXT:      <key>message</key>
+// CHECK-NEXT:      <string>Entered call from &apos;dispatch_once&apos;</string>
+// CHECK-NEXT:     </dict>
+// CHECK-NEXT:     <dict>
+// CHECK-NEXT:      <key>kind</key><string>control</string>
+// CHECK-NEXT:      <key>edges</key>
+// CHECK-NEXT:       <array>
+// CHECK-NEXT:        <dict>
+// CHECK-NEXT:         <key>start</key>
+// CHECK-NEXT:          <array>
+// CHECK-NEXT:           <dict>
+// CHECK-NEXT:            <key>line</key><integer>188</integer>
+// CHECK-NEXT:            <key>col</key><integer>24</integer>
+// CHECK-NEXT:            <key>file</key><integer>0</integer>
+// CHECK-NEXT:           </dict>
+// CHECK-NEXT:           <dict>
+// CHECK-NEXT:            <key>line</key><integer>188</integer>
+// CHECK-NEXT:            <key>col</key><integer>24</integer>
+// CHECK-NEXT:            <key>file</key><integer>0</integer>
+// CHECK-NEXT:           </dict>
+// CHECK-NEXT:          </array>
+// CHECK-NEXT:         <key>end</key>
+// CHECK-NEXT:          <array>
+// CHECK-NEXT:           <dict>
+// CHECK-NEXT:            <key>line</key><integer>189</integer>
+// CHECK-NEXT:            <key>col</key><integer>4</integer>
+// CHECK-NEXT:            <key>file</key><integer>0</integer>
+// CHECK-NEXT:           </dict>
+// CHECK-NEXT:           <dict>
+// CHECK-NEXT:            <key>line</key><integer>189</integer>
+// CHECK-NEXT:            <key>col</key><integer>4</integer>
+// CHECK-NEXT:            <key>file</key><integer>0</integer>
+// CHECK-NEXT:           </dict>
+// CHECK-NEXT:          </array>
+// CHECK-NEXT:        </dict>
+// CHECK-NEXT:       </array>
+// CHECK-NEXT:     </dict>
+// CHECK-NEXT:     <dict>
+// CHECK-NEXT:      <key>kind</key><string>event</string>
+// CHECK-NEXT:      <key>location</key>
+// CHECK-NEXT:      <dict>
+// CHECK-NEXT:       <key>line</key><integer>189</integer>
+// CHECK-NEXT:       <key>col</key><integer>4</integer>
+// CHECK-NEXT:       <key>file</key><integer>0</integer>
+// CHECK-NEXT:      </dict>
+// CHECK-NEXT:      <key>ranges</key>
+// CHECK-NEXT:      <array>
+// CHECK-NEXT:        <array>
+// CHECK-NEXT:         <dict>
+// CHECK-NEXT:          <key>line</key><integer>189</integer>
+// CHECK-NEXT:          <key>col</key><integer>5</integer>
+// CHECK-NEXT:          <key>file</key><integer>0</integer>
+// CHECK-NEXT:         </dict>
+// CHECK-NEXT:         <dict>
+// CHECK-NEXT:          <key>line</key><integer>189</integer>
+// CHECK-NEXT:          <key>col</key><integer>5</integer>
+// CHECK-NEXT:          <key>file</key><integer>0</integer>
+// CHECK-NEXT:         </dict>
+// CHECK-NEXT:        </array>
+// CHECK-NEXT:      </array>
+// CHECK-NEXT:      <key>depth</key><integer>3</integer>
+// CHECK-NEXT:      <key>extended_message</key>
+// CHECK-NEXT:      <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT:      <key>message</key>
+// CHECK-NEXT:      <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT:     </dict>
+// CHECK-NEXT:    </array>
+// CHECK-NEXT:    <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT:    <key>category</key><string>Logic error</string>
+// CHECK-NEXT:    <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT:   <key>location</key>
+// CHECK-NEXT:   <dict>
+// CHECK-NEXT:    <key>line</key><integer>189</integer>
+// CHECK-NEXT:    <key>col</key><integer>4</integer>
+// CHECK-NEXT:    <key>file</key><integer>0</integer>
+// CHECK-NEXT:   </dict>
+// CHECK-NEXT:   </dict>
 // CHECK-NEXT:  </array>