[clang] [clang][ExtractAPI] Add support for blocks in declaration fragments (PR #73369)

Daniel Grumberg via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 24 12:39:00 PST 2023


https://github.com/daniel-grumberg created https://github.com/llvm/llvm-project/pull/73369

Ensure that block types get represented correctly in declaration fragments, as block parameter names are important for documentation clients we need a separate system from getFragmentsForType in order to have access to full ParmVarDecls for the parameters.

rdar://118257401

>From e0a9db8aa5e511e81836b5f8e59853c0b498cadf Mon Sep 17 00:00:00 2001
From: Daniel Grumberg <dgrumberg at apple.com>
Date: Fri, 24 Nov 2023 20:34:49 +0000
Subject: [PATCH] [clang][ExtractAPI] Add support for blocks in declaration
 fragments

Ensure that block types get represented correctly in declaration
fragments, as block parameter names are important for documentation
clients we need a separate system from getFragmentsForType in order to
have access to full ParmVarDecls for the parameters.

rdar://118257401
---
 .../clang/ExtractAPI/DeclarationFragments.h   |   6 +
 clang/lib/ExtractAPI/DeclarationFragments.cpp | 176 +++-
 clang/test/ExtractAPI/objc_block.m            | 965 ++++++++++++++++++
 clang/test/ExtractAPI/objc_category.m         |   4 +
 clang/test/ExtractAPI/objc_id_protocol.m      |   8 +
 clang/test/ExtractAPI/objc_interface.m        |   4 +
 clang/test/ExtractAPI/objc_property.m         |  24 +
 7 files changed, 1159 insertions(+), 28 deletions(-)
 create mode 100644 clang/test/ExtractAPI/objc_block.m

diff --git a/clang/include/clang/ExtractAPI/DeclarationFragments.h b/clang/include/clang/ExtractAPI/DeclarationFragments.h
index 316d83df13e9359..d719196b9a43ecb 100644
--- a/clang/include/clang/ExtractAPI/DeclarationFragments.h
+++ b/clang/include/clang/ExtractAPI/DeclarationFragments.h
@@ -24,6 +24,7 @@
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/TypeLoc.h"
 #include "clang/Basic/Specifiers.h"
 #include "clang/Lex/MacroInfo.h"
 #include "llvm/ADT/SmallVector.h"
@@ -410,6 +411,11 @@ class DeclarationFragmentsBuilder {
   /// Build DeclarationFragments for a parameter variable declaration
   /// ParmVarDecl.
   static DeclarationFragments getFragmentsForParam(const ParmVarDecl *);
+
+  static DeclarationFragments
+  getFragmentsForBlock(const NamedDecl *BlockDecl, FunctionTypeLoc &Block,
+                       FunctionProtoTypeLoc &BlockProto,
+                       DeclarationFragments &After);
 };
 
 template <typename FunctionT>
diff --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp
index 02fa6cd6119ecac..eb6eea0aaf54655 100644
--- a/clang/lib/ExtractAPI/DeclarationFragments.cpp
+++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -15,6 +15,8 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/QualTypeNames.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeLoc.h"
 #include "clang/Basic/OperatorKinds.h"
 #include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h"
 #include "clang/Index/USRGeneration.h"
@@ -24,6 +26,40 @@
 using namespace clang::extractapi;
 using namespace llvm;
 
+namespace {
+
+void findTypeLocForBlockDecl(const clang::TypeSourceInfo *TSInfo,
+                             clang::FunctionTypeLoc &Block,
+                             clang::FunctionProtoTypeLoc &BlockProto) {
+  if (!TSInfo)
+    return;
+
+  clang::TypeLoc TL = TSInfo->getTypeLoc().getUnqualifiedLoc();
+  while (true) {
+    // Look through qualified types
+    if (auto QualifiedTL = TL.getAs<clang::QualifiedTypeLoc>()) {
+      TL = QualifiedTL.getUnqualifiedLoc();
+      continue;
+    }
+
+    if (auto AttrTL = TL.getAs<clang::AttributedTypeLoc>()) {
+      TL = AttrTL.getModifiedLoc();
+      continue;
+    }
+
+    // Try to get the function prototype behind the block pointer type,
+    // then we're done.
+    if (auto BlockPtr = TL.getAs<clang::BlockPointerTypeLoc>()) {
+      TL = BlockPtr.getPointeeLoc().IgnoreParens();
+      Block = TL.getAs<clang::FunctionTypeLoc>();
+      BlockProto = TL.getAs<clang::FunctionProtoTypeLoc>();
+    }
+    break;
+  }
+}
+
+} // namespace
+
 DeclarationFragments &DeclarationFragments::appendSpace() {
   if (!Fragments.empty()) {
     Fragment &Last = Fragments.back();
@@ -218,7 +254,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType(
 
   // Declaration fragments of a pointer type is the declaration fragments of
   // the pointee type followed by a `*`,
-  if (T->isPointerType())
+  if (T->isPointerType() && !T->isFunctionPointerType())
     return Fragments
         .append(getFragmentsForType(T->getPointeeType(), Context, After))
         .append(" *", DeclarationFragments::FragmentKind::Text);
@@ -449,10 +485,6 @@ DeclarationFragmentsBuilder::getFragmentsForVar(const VarDecl *Var) {
         .append(VarDecl::getStorageClassSpecifierString(SC),
                 DeclarationFragments::FragmentKind::Keyword)
         .appendSpace();
-  QualType T =
-      Var->getTypeSourceInfo()
-          ? Var->getTypeSourceInfo()->getType()
-          : Var->getASTContext().getUnqualifiedObjCPointerType(Var->getType());
 
   // Capture potential fragments that needs to be placed after the variable name
   // ```
@@ -460,8 +492,23 @@ DeclarationFragmentsBuilder::getFragmentsForVar(const VarDecl *Var) {
   // char (*ptr_to_array)[6];
   // ```
   DeclarationFragments After;
-  return Fragments.append(getFragmentsForType(T, Var->getASTContext(), After))
-      .appendSpace()
+  FunctionTypeLoc BlockLoc;
+  FunctionProtoTypeLoc BlockProtoLoc;
+  findTypeLocForBlockDecl(Var->getTypeSourceInfo(), BlockLoc, BlockProtoLoc);
+
+  if (!BlockLoc) {
+    QualType T = Var->getTypeSourceInfo()
+                     ? Var->getTypeSourceInfo()->getType()
+                     : Var->getASTContext().getUnqualifiedObjCPointerType(
+                           Var->getType());
+
+    Fragments.append(getFragmentsForType(T, Var->getASTContext(), After))
+        .appendSpace();
+  } else {
+    Fragments.append(getFragmentsForBlock(Var, BlockLoc, BlockProtoLoc, After));
+  }
+
+  return Fragments
       .append(Var->getName(), DeclarationFragments::FragmentKind::Identifier)
       .append(std::move(After))
       .append(";", DeclarationFragments::FragmentKind::Text);
@@ -504,13 +551,23 @@ DeclarationFragments
 DeclarationFragmentsBuilder::getFragmentsForParam(const ParmVarDecl *Param) {
   DeclarationFragments Fragments, After;
 
-  QualType T = Param->getTypeSourceInfo()
-                   ? Param->getTypeSourceInfo()->getType()
-                   : Param->getASTContext().getUnqualifiedObjCPointerType(
-                         Param->getType());
+  auto *TSInfo = Param->getTypeSourceInfo();
+
+  QualType T = TSInfo ? TSInfo->getType()
+                      : Param->getASTContext().getUnqualifiedObjCPointerType(
+                            Param->getType());
+
+  FunctionTypeLoc BlockLoc;
+  FunctionProtoTypeLoc BlockProtoLoc;
+  findTypeLocForBlockDecl(TSInfo, BlockLoc, BlockProtoLoc);
+
+  DeclarationFragments TypeFragments;
+  if (BlockLoc)
+    TypeFragments.append(
+        getFragmentsForBlock(Param, BlockLoc, BlockProtoLoc, After));
+  else
+    TypeFragments.append(getFragmentsForType(T, Param->getASTContext(), After));
 
-  DeclarationFragments TypeFragments =
-      getFragmentsForType(T, Param->getASTContext(), After);
   if (TypeFragments.begin()->Spelling.substr(0, 14).compare("type-parameter") ==
       0) {
     std::string ProperArgName = getNameForTemplateArgument(
@@ -522,17 +579,60 @@ DeclarationFragmentsBuilder::getFragmentsForParam(const ParmVarDecl *Param) {
     TypeFragments.begin()->Spelling.swap(ProperArgName);
   }
 
-  if (Param->isObjCMethodParameter())
+  if (Param->isObjCMethodParameter()) {
     Fragments.append("(", DeclarationFragments::FragmentKind::Text)
         .append(std::move(TypeFragments))
-        .append(") ", DeclarationFragments::FragmentKind::Text);
-  else
-    Fragments.append(std::move(TypeFragments)).appendSpace();
+        .append(std::move(After))
+        .append(") ", DeclarationFragments::FragmentKind::Text)
+        .append(Param->getName(),
+                DeclarationFragments::FragmentKind::InternalParam);
+  } else {
+    Fragments.append(std::move(TypeFragments));
+    if (!T->isBlockPointerType())
+      Fragments.appendSpace();
+    Fragments
+        .append(Param->getName(),
+                DeclarationFragments::FragmentKind::InternalParam)
+        .append(std::move(After));
+  }
+  return Fragments;
+}
 
-  return Fragments
-      .append(Param->getName(),
-              DeclarationFragments::FragmentKind::InternalParam)
-      .append(std::move(After));
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForBlock(
+    const NamedDecl *BlockDecl, FunctionTypeLoc &Block,
+    FunctionProtoTypeLoc &BlockProto, DeclarationFragments &After) {
+  DeclarationFragments Fragments;
+
+  DeclarationFragments RetTyAfter;
+  auto ReturnValueFragment = getFragmentsForType(
+      Block.getTypePtr()->getReturnType(), BlockDecl->getASTContext(), After);
+
+  Fragments.append(std::move(ReturnValueFragment))
+      .append(std::move(RetTyAfter))
+      .appendSpace()
+      .append("(^", DeclarationFragments::FragmentKind::Text);
+
+  After.append(")", DeclarationFragments::FragmentKind::Text);
+  unsigned NumParams = Block.getNumParams();
+
+  if (!BlockProto || NumParams == 0) {
+    if (BlockProto && BlockProto.getTypePtr()->isVariadic())
+      After.append("(...)", DeclarationFragments::FragmentKind::Text);
+    else
+      After.append("()", DeclarationFragments::FragmentKind::Text);
+  } else {
+    After.append("(", DeclarationFragments::FragmentKind::Text);
+    for (unsigned I = 0; I != NumParams; ++I) {
+      if (I)
+        After.append(", ", DeclarationFragments::FragmentKind::Text);
+      After.append(getFragmentsForParam(Block.getParam(I)));
+      if (I == NumParams - 1 && BlockProto.getTypePtr()->isVariadic())
+        After.append(", ...", DeclarationFragments::FragmentKind::Text);
+    }
+    After.append(")", DeclarationFragments::FragmentKind::Text);
+  }
+
+  return Fragments;
 }
 
 DeclarationFragments
@@ -595,11 +695,18 @@ DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) {
   Fragments.append(std::move(After));
 
   Fragments.append("(", DeclarationFragments::FragmentKind::Text);
-  for (unsigned i = 0, end = Func->getNumParams(); i != end; ++i) {
+  unsigned NumParams = Func->getNumParams();
+  for (unsigned i = 0; i != NumParams; ++i) {
     if (i)
       Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
     Fragments.append(getFragmentsForParam(Func->getParamDecl(i)));
   }
+
+  if (Func->isVariadic()) {
+    if (NumParams > 0)
+      Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
+    Fragments.append("...", DeclarationFragments::FragmentKind::Text);
+  }
   Fragments.append(")", DeclarationFragments::FragmentKind::Text);
 
   Fragments.append(DeclarationFragments::getExceptionSpecificationString(
@@ -1248,14 +1355,27 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProperty(
     Fragments.append(")", DeclarationFragments::FragmentKind::Text);
   }
 
-  // Build the property type and name, and return the completed fragments.
-  return Fragments.appendSpace()
-      .append(getFragmentsForType(Property->getType(),
-                                  Property->getASTContext(), After))
-      .appendSpace()
+  Fragments.appendSpace();
+
+  FunctionTypeLoc BlockLoc;
+  FunctionProtoTypeLoc BlockProtoLoc;
+  findTypeLocForBlockDecl(Property->getTypeSourceInfo(), BlockLoc,
+                          BlockProtoLoc);
+
+  auto PropType = Property->getType();
+  if (!BlockLoc)
+    Fragments
+        .append(getFragmentsForType(PropType, Property->getASTContext(), After))
+        .appendSpace();
+  else
+    Fragments.append(
+        getFragmentsForBlock(Property, BlockLoc, BlockProtoLoc, After));
+
+  return Fragments
       .append(Property->getName(),
               DeclarationFragments::FragmentKind::Identifier)
-      .append(std::move(After));
+      .append(std::move(After))
+      .append(";", DeclarationFragments::FragmentKind::Text);
 }
 
 DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(
diff --git a/clang/test/ExtractAPI/objc_block.m b/clang/test/ExtractAPI/objc_block.m
new file mode 100644
index 000000000000000..a7a4f5696333c18
--- /dev/null
+++ b/clang/test/ExtractAPI/objc_block.m
@@ -0,0 +1,965 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: sed -e "s at INPUT_DIR@%{/t:regex_replacement}@g" \
+// RUN: %t/reference.output.json.in >> %t/reference.output.json
+// RUN: %clang_cc1 -extract-api -fblocks -triple arm64-apple-macosx \
+// RUN: -x objective-c-header %t/input.h -o %t/output.json -verify
+
+// Generator version is not consistent across test runs, normalize it.
+// RUN: sed -e "s@\"generator\": \".*\"@\"generator\": \"?\"@g" \
+// RUN: %t/output.json >> %t/output-normalized.json
+// RUN: diff %t/reference.output.json %t/output-normalized.json
+
+//--- input.h
+ at interface Foo
+-(void)methodBlockNoParam:(void (^)())block;
+-(void)methodBlockWithParam:(int (^)(int foo))block;
+-(void)methodBlockWithMultipleParam:(int (^)(int foo, unsigned baz))block;
+-(void)methodBlockVariadic:(int (^)(int foo, ...))block;
+ at end
+
+void func(int (^arg)(int foo));
+
+int (^global)(int foo);
+
+///expected-no-diagnostics
+
+//--- reference.output.json.in
+{
+  "metadata": {
+    "formatVersion": {
+      "major": 0,
+      "minor": 5,
+      "patch": 3
+    },
+    "generator": "?"
+  },
+  "module": {
+    "name": "",
+    "platform": {
+      "architecture": "arm64",
+      "operatingSystem": {
+        "minimumVersion": {
+          "major": 11,
+          "minor": 0,
+          "patch": 0
+        },
+        "name": "macosx"
+      },
+      "vendor": "apple"
+    }
+  },
+  "relationships": [
+    {
+      "kind": "memberOf",
+      "source": "c:objc(cs)Foo(im)methodBlockNoParam:",
+      "target": "c:objc(cs)Foo",
+      "targetFallback": "Foo"
+    },
+    {
+      "kind": "memberOf",
+      "source": "c:objc(cs)Foo(im)methodBlockWithParam:",
+      "target": "c:objc(cs)Foo",
+      "targetFallback": "Foo"
+    },
+    {
+      "kind": "memberOf",
+      "source": "c:objc(cs)Foo(im)methodBlockWithMultipleParam:",
+      "target": "c:objc(cs)Foo",
+      "targetFallback": "Foo"
+    },
+    {
+      "kind": "memberOf",
+      "source": "c:objc(cs)Foo(im)methodBlockVariadic:",
+      "target": "c:objc(cs)Foo",
+      "targetFallback": "Foo"
+    }
+  ],
+  "symbols": [
+    {
+      "accessLevel": "public",
+      "declarationFragments": [
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:I",
+          "spelling": "int"
+        },
+        {
+          "kind": "text",
+          "spelling": " (^"
+        },
+        {
+          "kind": "identifier",
+          "spelling": "global"
+        },
+        {
+          "kind": "text",
+          "spelling": ")("
+        },
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:I",
+          "spelling": "int"
+        },
+        {
+          "kind": "text",
+          "spelling": " "
+        },
+        {
+          "kind": "internalParam",
+          "spelling": "foo"
+        },
+        {
+          "kind": "text",
+          "spelling": ");"
+        }
+      ],
+      "identifier": {
+        "interfaceLanguage": "objective-c",
+        "precise": "c:@global"
+      },
+      "kind": {
+        "displayName": "Global Variable",
+        "identifier": "objective-c.var"
+      },
+      "location": {
+        "position": {
+          "character": 6,
+          "line": 9
+        },
+        "uri": "file://INPUT_DIR/input.h"
+      },
+      "names": {
+        "navigator": [
+          {
+            "kind": "identifier",
+            "spelling": "global"
+          }
+        ],
+        "subHeading": [
+          {
+            "kind": "identifier",
+            "spelling": "global"
+          }
+        ],
+        "title": "global"
+      },
+      "pathComponents": [
+        "global"
+      ]
+    },
+    {
+      "accessLevel": "public",
+      "declarationFragments": [
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:v",
+          "spelling": "void"
+        },
+        {
+          "kind": "text",
+          "spelling": " "
+        },
+        {
+          "kind": "identifier",
+          "spelling": "func"
+        },
+        {
+          "kind": "text",
+          "spelling": "("
+        },
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:I",
+          "spelling": "int"
+        },
+        {
+          "kind": "text",
+          "spelling": " (^"
+        },
+        {
+          "kind": "internalParam",
+          "spelling": "arg"
+        },
+        {
+          "kind": "text",
+          "spelling": ")("
+        },
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:I",
+          "spelling": "int"
+        },
+        {
+          "kind": "text",
+          "spelling": " "
+        },
+        {
+          "kind": "internalParam",
+          "spelling": "foo"
+        },
+        {
+          "kind": "text",
+          "spelling": "));"
+        }
+      ],
+      "functionSignature": {
+        "parameters": [
+          {
+            "declarationFragments": [
+              {
+                "kind": "typeIdentifier",
+                "preciseIdentifier": "c:I",
+                "spelling": "int"
+              },
+              {
+                "kind": "text",
+                "spelling": " (^"
+              },
+              {
+                "kind": "internalParam",
+                "spelling": "arg"
+              },
+              {
+                "kind": "text",
+                "spelling": ")("
+              },
+              {
+                "kind": "typeIdentifier",
+                "preciseIdentifier": "c:I",
+                "spelling": "int"
+              },
+              {
+                "kind": "text",
+                "spelling": " "
+              },
+              {
+                "kind": "internalParam",
+                "spelling": "foo"
+              },
+              {
+                "kind": "text",
+                "spelling": ")"
+              }
+            ],
+            "name": "arg"
+          }
+        ],
+        "returns": [
+          {
+            "kind": "typeIdentifier",
+            "preciseIdentifier": "c:v",
+            "spelling": "void"
+          }
+        ]
+      },
+      "identifier": {
+        "interfaceLanguage": "objective-c",
+        "precise": "c:@F at func"
+      },
+      "kind": {
+        "displayName": "Function",
+        "identifier": "objective-c.func"
+      },
+      "location": {
+        "position": {
+          "character": 5,
+          "line": 7
+        },
+        "uri": "file://INPUT_DIR/input.h"
+      },
+      "names": {
+        "navigator": [
+          {
+            "kind": "identifier",
+            "spelling": "func"
+          }
+        ],
+        "subHeading": [
+          {
+            "kind": "identifier",
+            "spelling": "func"
+          }
+        ],
+        "title": "func"
+      },
+      "pathComponents": [
+        "func"
+      ]
+    },
+    {
+      "accessLevel": "public",
+      "declarationFragments": [
+        {
+          "kind": "keyword",
+          "spelling": "@interface"
+        },
+        {
+          "kind": "text",
+          "spelling": " "
+        },
+        {
+          "kind": "identifier",
+          "spelling": "Foo"
+        }
+      ],
+      "identifier": {
+        "interfaceLanguage": "objective-c",
+        "precise": "c:objc(cs)Foo"
+      },
+      "kind": {
+        "displayName": "Class",
+        "identifier": "objective-c.class"
+      },
+      "location": {
+        "position": {
+          "character": 11,
+          "line": 0
+        },
+        "uri": "file://INPUT_DIR/input.h"
+      },
+      "names": {
+        "navigator": [
+          {
+            "kind": "identifier",
+            "spelling": "Foo"
+          }
+        ],
+        "subHeading": [
+          {
+            "kind": "identifier",
+            "spelling": "Foo"
+          }
+        ],
+        "title": "Foo"
+      },
+      "pathComponents": [
+        "Foo"
+      ]
+    },
+    {
+      "accessLevel": "public",
+      "declarationFragments": [
+        {
+          "kind": "text",
+          "spelling": "- ("
+        },
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:v",
+          "spelling": "void"
+        },
+        {
+          "kind": "text",
+          "spelling": ") "
+        },
+        {
+          "kind": "identifier",
+          "spelling": "methodBlockNoParam:"
+        },
+        {
+          "kind": "text",
+          "spelling": "("
+        },
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:v",
+          "spelling": "void"
+        },
+        {
+          "kind": "text",
+          "spelling": " (^"
+        },
+        {
+          "kind": "text",
+          "spelling": ")()) "
+        },
+        {
+          "kind": "internalParam",
+          "spelling": "block"
+        },
+        {
+          "kind": "text",
+          "spelling": ";"
+        }
+      ],
+      "functionSignature": {
+        "parameters": [
+          {
+            "declarationFragments": [
+              {
+                "kind": "text",
+                "spelling": "("
+              },
+              {
+                "kind": "typeIdentifier",
+                "preciseIdentifier": "c:v",
+                "spelling": "void"
+              },
+              {
+                "kind": "text",
+                "spelling": " (^"
+              },
+              {
+                "kind": "text",
+                "spelling": ")()) "
+              },
+              {
+                "kind": "internalParam",
+                "spelling": "block"
+              }
+            ],
+            "name": "block"
+          }
+        ],
+        "returns": [
+          {
+            "kind": "typeIdentifier",
+            "preciseIdentifier": "c:v",
+            "spelling": "void"
+          }
+        ]
+      },
+      "identifier": {
+        "interfaceLanguage": "objective-c",
+        "precise": "c:objc(cs)Foo(im)methodBlockNoParam:"
+      },
+      "kind": {
+        "displayName": "Instance Method",
+        "identifier": "objective-c.method"
+      },
+      "location": {
+        "position": {
+          "character": 0,
+          "line": 1
+        },
+        "uri": "file://INPUT_DIR/input.h"
+      },
+      "names": {
+        "navigator": [
+          {
+            "kind": "identifier",
+            "spelling": "methodBlockNoParam:"
+          }
+        ],
+        "subHeading": [
+          {
+            "kind": "text",
+            "spelling": "- "
+          },
+          {
+            "kind": "identifier",
+            "spelling": "methodBlockNoParam:"
+          }
+        ],
+        "title": "methodBlockNoParam:"
+      },
+      "pathComponents": [
+        "Foo",
+        "methodBlockNoParam:"
+      ]
+    },
+    {
+      "accessLevel": "public",
+      "declarationFragments": [
+        {
+          "kind": "text",
+          "spelling": "- ("
+        },
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:v",
+          "spelling": "void"
+        },
+        {
+          "kind": "text",
+          "spelling": ") "
+        },
+        {
+          "kind": "identifier",
+          "spelling": "methodBlockWithParam:"
+        },
+        {
+          "kind": "text",
+          "spelling": "("
+        },
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:I",
+          "spelling": "int"
+        },
+        {
+          "kind": "text",
+          "spelling": " (^"
+        },
+        {
+          "kind": "text",
+          "spelling": ")("
+        },
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:I",
+          "spelling": "int"
+        },
+        {
+          "kind": "text",
+          "spelling": " "
+        },
+        {
+          "kind": "internalParam",
+          "spelling": "foo"
+        },
+        {
+          "kind": "text",
+          "spelling": ")) "
+        },
+        {
+          "kind": "internalParam",
+          "spelling": "block"
+        },
+        {
+          "kind": "text",
+          "spelling": ";"
+        }
+      ],
+      "functionSignature": {
+        "parameters": [
+          {
+            "declarationFragments": [
+              {
+                "kind": "text",
+                "spelling": "("
+              },
+              {
+                "kind": "typeIdentifier",
+                "preciseIdentifier": "c:I",
+                "spelling": "int"
+              },
+              {
+                "kind": "text",
+                "spelling": " (^"
+              },
+              {
+                "kind": "text",
+                "spelling": ")("
+              },
+              {
+                "kind": "typeIdentifier",
+                "preciseIdentifier": "c:I",
+                "spelling": "int"
+              },
+              {
+                "kind": "text",
+                "spelling": " "
+              },
+              {
+                "kind": "internalParam",
+                "spelling": "foo"
+              },
+              {
+                "kind": "text",
+                "spelling": ")) "
+              },
+              {
+                "kind": "internalParam",
+                "spelling": "block"
+              }
+            ],
+            "name": "block"
+          }
+        ],
+        "returns": [
+          {
+            "kind": "typeIdentifier",
+            "preciseIdentifier": "c:v",
+            "spelling": "void"
+          }
+        ]
+      },
+      "identifier": {
+        "interfaceLanguage": "objective-c",
+        "precise": "c:objc(cs)Foo(im)methodBlockWithParam:"
+      },
+      "kind": {
+        "displayName": "Instance Method",
+        "identifier": "objective-c.method"
+      },
+      "location": {
+        "position": {
+          "character": 0,
+          "line": 2
+        },
+        "uri": "file://INPUT_DIR/input.h"
+      },
+      "names": {
+        "navigator": [
+          {
+            "kind": "identifier",
+            "spelling": "methodBlockWithParam:"
+          }
+        ],
+        "subHeading": [
+          {
+            "kind": "text",
+            "spelling": "- "
+          },
+          {
+            "kind": "identifier",
+            "spelling": "methodBlockWithParam:"
+          }
+        ],
+        "title": "methodBlockWithParam:"
+      },
+      "pathComponents": [
+        "Foo",
+        "methodBlockWithParam:"
+      ]
+    },
+    {
+      "accessLevel": "public",
+      "declarationFragments": [
+        {
+          "kind": "text",
+          "spelling": "- ("
+        },
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:v",
+          "spelling": "void"
+        },
+        {
+          "kind": "text",
+          "spelling": ") "
+        },
+        {
+          "kind": "identifier",
+          "spelling": "methodBlockWithMultipleParam:"
+        },
+        {
+          "kind": "text",
+          "spelling": "("
+        },
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:I",
+          "spelling": "int"
+        },
+        {
+          "kind": "text",
+          "spelling": " (^"
+        },
+        {
+          "kind": "text",
+          "spelling": ")("
+        },
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:I",
+          "spelling": "int"
+        },
+        {
+          "kind": "text",
+          "spelling": " "
+        },
+        {
+          "kind": "internalParam",
+          "spelling": "foo"
+        },
+        {
+          "kind": "text",
+          "spelling": ", "
+        },
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:i",
+          "spelling": "unsigned int"
+        },
+        {
+          "kind": "text",
+          "spelling": " "
+        },
+        {
+          "kind": "internalParam",
+          "spelling": "baz"
+        },
+        {
+          "kind": "text",
+          "spelling": ")) "
+        },
+        {
+          "kind": "internalParam",
+          "spelling": "block"
+        },
+        {
+          "kind": "text",
+          "spelling": ";"
+        }
+      ],
+      "functionSignature": {
+        "parameters": [
+          {
+            "declarationFragments": [
+              {
+                "kind": "text",
+                "spelling": "("
+              },
+              {
+                "kind": "typeIdentifier",
+                "preciseIdentifier": "c:I",
+                "spelling": "int"
+              },
+              {
+                "kind": "text",
+                "spelling": " (^"
+              },
+              {
+                "kind": "text",
+                "spelling": ")("
+              },
+              {
+                "kind": "typeIdentifier",
+                "preciseIdentifier": "c:I",
+                "spelling": "int"
+              },
+              {
+                "kind": "text",
+                "spelling": " "
+              },
+              {
+                "kind": "internalParam",
+                "spelling": "foo"
+              },
+              {
+                "kind": "text",
+                "spelling": ", "
+              },
+              {
+                "kind": "typeIdentifier",
+                "preciseIdentifier": "c:i",
+                "spelling": "unsigned int"
+              },
+              {
+                "kind": "text",
+                "spelling": " "
+              },
+              {
+                "kind": "internalParam",
+                "spelling": "baz"
+              },
+              {
+                "kind": "text",
+                "spelling": ")) "
+              },
+              {
+                "kind": "internalParam",
+                "spelling": "block"
+              }
+            ],
+            "name": "block"
+          }
+        ],
+        "returns": [
+          {
+            "kind": "typeIdentifier",
+            "preciseIdentifier": "c:v",
+            "spelling": "void"
+          }
+        ]
+      },
+      "identifier": {
+        "interfaceLanguage": "objective-c",
+        "precise": "c:objc(cs)Foo(im)methodBlockWithMultipleParam:"
+      },
+      "kind": {
+        "displayName": "Instance Method",
+        "identifier": "objective-c.method"
+      },
+      "location": {
+        "position": {
+          "character": 0,
+          "line": 3
+        },
+        "uri": "file://INPUT_DIR/input.h"
+      },
+      "names": {
+        "navigator": [
+          {
+            "kind": "identifier",
+            "spelling": "methodBlockWithMultipleParam:"
+          }
+        ],
+        "subHeading": [
+          {
+            "kind": "text",
+            "spelling": "- "
+          },
+          {
+            "kind": "identifier",
+            "spelling": "methodBlockWithMultipleParam:"
+          }
+        ],
+        "title": "methodBlockWithMultipleParam:"
+      },
+      "pathComponents": [
+        "Foo",
+        "methodBlockWithMultipleParam:"
+      ]
+    },
+    {
+      "accessLevel": "public",
+      "declarationFragments": [
+        {
+          "kind": "text",
+          "spelling": "- ("
+        },
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:v",
+          "spelling": "void"
+        },
+        {
+          "kind": "text",
+          "spelling": ") "
+        },
+        {
+          "kind": "identifier",
+          "spelling": "methodBlockVariadic:"
+        },
+        {
+          "kind": "text",
+          "spelling": "("
+        },
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:I",
+          "spelling": "int"
+        },
+        {
+          "kind": "text",
+          "spelling": " (^"
+        },
+        {
+          "kind": "text",
+          "spelling": ")("
+        },
+        {
+          "kind": "typeIdentifier",
+          "preciseIdentifier": "c:I",
+          "spelling": "int"
+        },
+        {
+          "kind": "text",
+          "spelling": " "
+        },
+        {
+          "kind": "internalParam",
+          "spelling": "foo"
+        },
+        {
+          "kind": "text",
+          "spelling": ", ...)) "
+        },
+        {
+          "kind": "internalParam",
+          "spelling": "block"
+        },
+        {
+          "kind": "text",
+          "spelling": ";"
+        }
+      ],
+      "functionSignature": {
+        "parameters": [
+          {
+            "declarationFragments": [
+              {
+                "kind": "text",
+                "spelling": "("
+              },
+              {
+                "kind": "typeIdentifier",
+                "preciseIdentifier": "c:I",
+                "spelling": "int"
+              },
+              {
+                "kind": "text",
+                "spelling": " (^"
+              },
+              {
+                "kind": "text",
+                "spelling": ")("
+              },
+              {
+                "kind": "typeIdentifier",
+                "preciseIdentifier": "c:I",
+                "spelling": "int"
+              },
+              {
+                "kind": "text",
+                "spelling": " "
+              },
+              {
+                "kind": "internalParam",
+                "spelling": "foo"
+              },
+              {
+                "kind": "text",
+                "spelling": ", ...)) "
+              },
+              {
+                "kind": "internalParam",
+                "spelling": "block"
+              }
+            ],
+            "name": "block"
+          }
+        ],
+        "returns": [
+          {
+            "kind": "typeIdentifier",
+            "preciseIdentifier": "c:v",
+            "spelling": "void"
+          }
+        ]
+      },
+      "identifier": {
+        "interfaceLanguage": "objective-c",
+        "precise": "c:objc(cs)Foo(im)methodBlockVariadic:"
+      },
+      "kind": {
+        "displayName": "Instance Method",
+        "identifier": "objective-c.method"
+      },
+      "location": {
+        "position": {
+          "character": 0,
+          "line": 4
+        },
+        "uri": "file://INPUT_DIR/input.h"
+      },
+      "names": {
+        "navigator": [
+          {
+            "kind": "identifier",
+            "spelling": "methodBlockVariadic:"
+          }
+        ],
+        "subHeading": [
+          {
+            "kind": "text",
+            "spelling": "- "
+          },
+          {
+            "kind": "identifier",
+            "spelling": "methodBlockVariadic:"
+          }
+        ],
+        "title": "methodBlockVariadic:"
+      },
+      "pathComponents": [
+        "Foo",
+        "methodBlockVariadic:"
+      ]
+    }
+  ]
+}
diff --git a/clang/test/ExtractAPI/objc_category.m b/clang/test/ExtractAPI/objc_category.m
index 897bc082fdc033b..34b0a9e31f553c9 100644
--- a/clang/test/ExtractAPI/objc_category.m
+++ b/clang/test/ExtractAPI/objc_category.m
@@ -296,6 +296,10 @@ + (void)ClassMethod;
         {
           "kind": "identifier",
           "spelling": "Property"
+        },
+        {
+          "kind": "text",
+          "spelling": ";"
         }
       ],
       "identifier": {
diff --git a/clang/test/ExtractAPI/objc_id_protocol.m b/clang/test/ExtractAPI/objc_id_protocol.m
index 4014541278a36b7..0b0f1b39d2bd61f 100644
--- a/clang/test/ExtractAPI/objc_id_protocol.m
+++ b/clang/test/ExtractAPI/objc_id_protocol.m
@@ -150,6 +150,10 @@ @interface MyInterface
         {
           "kind": "identifier",
           "spelling": "obj1"
+        },
+        {
+          "kind": "text",
+          "spelling": ";"
         }
       ],
       "identifier": {
@@ -218,6 +222,10 @@ @interface MyInterface
         {
           "kind": "identifier",
           "spelling": "obj2"
+        },
+        {
+          "kind": "text",
+          "spelling": ";"
         }
       ],
       "identifier": {
diff --git a/clang/test/ExtractAPI/objc_interface.m b/clang/test/ExtractAPI/objc_interface.m
index c04f87998bb066c..ab1772a0c529bba 100644
--- a/clang/test/ExtractAPI/objc_interface.m
+++ b/clang/test/ExtractAPI/objc_interface.m
@@ -468,6 +468,10 @@ - (char)getIvar;
         {
           "kind": "identifier",
           "spelling": "Property"
+        },
+        {
+          "kind": "text",
+          "spelling": ";"
         }
       ],
       "identifier": {
diff --git a/clang/test/ExtractAPI/objc_property.m b/clang/test/ExtractAPI/objc_property.m
index 5a19ba2460196eb..5712abc15393b61 100644
--- a/clang/test/ExtractAPI/objc_property.m
+++ b/clang/test/ExtractAPI/objc_property.m
@@ -177,6 +177,10 @@ @interface Interface (Category) <Protocol>
         {
           "kind": "identifier",
           "spelling": "myInterfaceTypeProp"
+        },
+        {
+          "kind": "text",
+          "spelling": ";"
         }
       ],
       "identifier": {
@@ -237,6 +241,10 @@ @interface Interface (Category) <Protocol>
         {
           "kind": "identifier",
           "spelling": "myInterfaceInstanceProp"
+        },
+        {
+          "kind": "text",
+          "spelling": ";"
         }
       ],
       "identifier": {
@@ -305,6 +313,10 @@ @interface Interface (Category) <Protocol>
         {
           "kind": "identifier",
           "spelling": "myCategoryTypeProp"
+        },
+        {
+          "kind": "text",
+          "spelling": ";"
         }
       ],
       "identifier": {
@@ -365,6 +377,10 @@ @interface Interface (Category) <Protocol>
         {
           "kind": "identifier",
           "spelling": "myCategoryInstanceProp"
+        },
+        {
+          "kind": "text",
+          "spelling": ";"
         }
       ],
       "identifier": {
@@ -483,6 +499,10 @@ @interface Interface (Category) <Protocol>
         {
           "kind": "identifier",
           "spelling": "myProtocolTypeProp"
+        },
+        {
+          "kind": "text",
+          "spelling": ";"
         }
       ],
       "identifier": {
@@ -543,6 +563,10 @@ @interface Interface (Category) <Protocol>
         {
           "kind": "identifier",
           "spelling": "myProtocolInstanceProp"
+        },
+        {
+          "kind": "text",
+          "spelling": ";"
         }
       ],
       "identifier": {



More information about the cfe-commits mailing list