Skip to content

Conversation

@snprajwal
Copy link
Contributor

Typically, pointer types are formatted in a way where the identifier comes right after the type definition without a space separating them, e.g. int *foo, where the type is int * and the identifier is foo. However, if a type alias to a pointer type is used, the emitted declaration fragments are incorrect due to the missing space between the type and identifier, like in the below example:

typedef int *T;
// The declaration fragment contains `Tbar` instead of `T bar`
void foo(T bar);

This patch checks if pointer types are aliased, and inserts the space correctly if so.

rdar://132022003

Typically, pointer types are formatted in a way where the identifier
comes right after the type definition without a space separating them,
e.g. `int *foo`, where the type is `int *` and the identifier is `foo`.
However, if a type alias to a pointer type is used, the emitted
declaration fragments are incorrect due to the missing space between the
type and identifier, like in the below example:

```
typedef int *T;
// The declaration fragment contains `Tbar` instead of `T bar`
void foo(T bar);
```

This patch checks if pointer types are aliased, and inserts the space
correctly if so.

rdar://132022003
@llvmbot llvmbot added the clang Clang issues not falling into any other category label Dec 9, 2025
@llvmbot
Copy link
Member

llvmbot commented Dec 9, 2025

@llvm/pr-subscribers-clang

Author: Prajwal Nadig (snprajwal)

Changes

Typically, pointer types are formatted in a way where the identifier comes right after the type definition without a space separating them, e.g. int *foo, where the type is int * and the identifier is foo. However, if a type alias to a pointer type is used, the emitted declaration fragments are incorrect due to the missing space between the type and identifier, like in the below example:

typedef int *T;
// The declaration fragment contains `Tbar` instead of `T bar`
void foo(T bar);

This patch checks if pointer types are aliased, and inserts the space correctly if so.

rdar://132022003


Full diff: https://github.com/llvm/llvm-project/pull/171516.diff

2 Files Affected:

  • (modified) clang/lib/ExtractAPI/DeclarationFragments.cpp (+4-1)
  • (modified) clang/test/ExtractAPI/typedef.c (+80-1)
diff --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp
index e5eda46df8056..7f2778713eade 100644
--- a/clang/lib/ExtractAPI/DeclarationFragments.cpp
+++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -633,7 +633,10 @@ DeclarationFragmentsBuilder::getFragmentsForParam(const ParmVarDecl *Param) {
                 DeclarationFragments::FragmentKind::InternalParam);
   } else {
     Fragments.append(std::move(TypeFragments));
-    if (!T->isAnyPointerType() && !T->isBlockPointerType())
+    // If the type is a type alias, append the space
+    // even if the underlying type is a pointer type.
+    if (T->isTypedefNameType() ||
+        (!T->isAnyPointerType() && !T->isBlockPointerType()))
       Fragments.appendSpace();
     Fragments
         .append(Param->getName(),
diff --git a/clang/test/ExtractAPI/typedef.c b/clang/test/ExtractAPI/typedef.c
index a4c3619bfd210..6099cd62f8776 100644
--- a/clang/test/ExtractAPI/typedef.c
+++ b/clang/test/ExtractAPI/typedef.c
@@ -1,5 +1,5 @@
 // RUN: rm -rf %t
-// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \
+// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing -fblocks \
 // RUN:   -triple arm64-apple-macosx -x objective-c-header %s -o %t/output.symbols.json -verify
 
 // RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix MYINT
@@ -90,4 +90,83 @@ void foo(BarPtr value);
 void baz(BarPtr *value);
 // CHECK-NOT: struct Bar *
 
+// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix BLOCKPTR
+typedef int (^CustomType)(const unsigned int *, unsigned long);
+void bar(CustomType block);
+
+// BLOCKPTR-LABEL: "!testLabel": "c:@F@bar",
+// BLOCKPTR:           "declarationFragments": [
+// BLOCKPTR-NEXT:        {
+// BLOCKPTR-NEXT:          "kind": "typeIdentifier",
+// BLOCKPTR-NEXT:          "preciseIdentifier": "c:v",
+// BLOCKPTR-NEXT:          "spelling": "void"
+// BLOCKPTR-NEXT:        },
+// BLOCKPTR-NEXT:        {
+// BLOCKPTR-NEXT:          "kind": "text",
+// BLOCKPTR-NEXT:          "spelling": " "
+// BLOCKPTR-NEXT:        },
+// BLOCKPTR-NEXT:        {
+// BLOCKPTR-NEXT:          "kind": "identifier",
+// BLOCKPTR-NEXT:          "spelling": "bar"
+// BLOCKPTR-NEXT:        },
+// BLOCKPTR-NEXT:        {
+// BLOCKPTR-NEXT:          "kind": "text",
+// BLOCKPTR-NEXT:          "spelling": "("
+// BLOCKPTR-NEXT:        },
+// BLOCKPTR-NEXT:        {
+// BLOCKPTR-NEXT:          "kind": "typeIdentifier",
+// BLOCKPTR-NEXT:          "preciseIdentifier": "c:typedef.c@T@CustomType",
+// BLOCKPTR-NEXT:          "spelling": "CustomType"
+// BLOCKPTR-NEXT:        },
+// BLOCKPTR-NEXT:        {
+// BLOCKPTR-NEXT:          "kind": "text",
+// BLOCKPTR-NEXT:          "spelling": " "
+// BLOCKPTR-NEXT:        },
+// BLOCKPTR-NEXT:        {
+// BLOCKPTR-NEXT:          "kind": "internalParam",
+// BLOCKPTR-NEXT:          "spelling": "block"
+// BLOCKPTR-NEXT:        },
+// BLOCKPTR-NEXT:        {
+// BLOCKPTR-NEXT:          "kind": "text",
+// BLOCKPTR-NEXT:          "spelling": ");"
+// BLOCKPTR-NEXT:        }
+// BLOCKPTR-NEXT:      ],
+// BLOCKPTR-NEXT:      "functionSignature": {
+// BLOCKPTR-NEXT:        "parameters": [
+// BLOCKPTR-NEXT:          {
+// BLOCKPTR-NEXT:            "declarationFragments": [
+// BLOCKPTR-NEXT:              {
+// BLOCKPTR-NEXT:                "kind": "typeIdentifier",
+// BLOCKPTR-NEXT:                "preciseIdentifier": "c:typedef.c@T@CustomType",
+// BLOCKPTR-NEXT:                "spelling": "CustomType"
+// BLOCKPTR-NEXT:              },
+// BLOCKPTR-NEXT:              {
+// BLOCKPTR-NEXT:                "kind": "text",
+// BLOCKPTR-NEXT:                "spelling": " "
+// BLOCKPTR-NEXT:              },
+// BLOCKPTR-NEXT:              {
+// BLOCKPTR-NEXT:                "kind": "internalParam",
+// BLOCKPTR-NEXT:                "spelling": "block"
+// BLOCKPTR-NEXT:              }
+// BLOCKPTR-NEXT:            ],
+// BLOCKPTR-NEXT:            "name": "block"
+// BLOCKPTR-NEXT:          }
+// BLOCKPTR-NEXT:        ],
+// BLOCKPTR-NEXT:        "returns": [
+// BLOCKPTR-NEXT:          {
+// BLOCKPTR-NEXT:            "kind": "typeIdentifier",
+// BLOCKPTR-NEXT:            "preciseIdentifier": "c:v",
+// BLOCKPTR-NEXT:            "spelling": "void"
+// BLOCKPTR-NEXT:          }
+// BLOCKPTR-NEXT:        ]
+// BLOCKPTR-NEXT:      },
+// BLOCKPTR:           "identifier": {
+// BLOCKPTR-NEXT:        "interfaceLanguage": "objective-c",
+// BLOCKPTR-NEXT:        "precise": "c:@F@bar"
+// BLOCKPTR-NEXT:      },
+// BLOCKPTR:           "kind": {
+// BLOCKPTR-NEXT:        "displayName": "Function",
+// BLOCKPTR-NEXT:        "identifier": "objective-c.func"
+// BLOCKPTR-NEXT:      },
+
 // expected-no-diagnostics

Copy link
Contributor

@QuietMisdreavus QuietMisdreavus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

@snprajwal snprajwal enabled auto-merge (squash) December 9, 2025 22:40
@snprajwal snprajwal merged commit 794218b into llvm:main Dec 9, 2025
9 of 11 checks passed
@snprajwal snprajwal deleted the extractapi-blockptr branch December 9, 2025 22:41
@snprajwal snprajwal added this to the LLVM 21.x Release milestone Dec 9, 2025
@snprajwal
Copy link
Contributor Author

/cherry-pick 794218b

@llvmbot
Copy link
Member

llvmbot commented Dec 9, 2025

/pull-request #171522

dyung pushed a commit to llvmbot/llvm-project that referenced this pull request Dec 12, 2025
Typically, pointer types are formatted in a way where the identifier
comes right after the type definition without a space separating them,
e.g. `int *foo`, where the type is `int *` and the identifier is `foo`.
However, if a type alias to a pointer type is used, the emitted
declaration fragments are incorrect due to the missing space between the
type and identifier, like in the below example:

```
typedef int *T;
// The declaration fragment contains `Tbar` instead of `T bar`
void foo(T bar);
```

This patch checks if pointer types are aliased, and inserts the space
correctly if so.

rdar://132022003
(cherry picked from commit 794218b)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang Clang issues not falling into any other category

Projects

Development

Successfully merging this pull request may close these issues.

3 participants