[clang] [ExtractAPI] Format pointers in params correctly (PR #146182)
Prajwal Nadig via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 27 18:02:51 PDT 2025
https://github.com/snprajwal created https://github.com/llvm/llvm-project/pull/146182
Pointer types in function parameters must place the asterisk before the identifier without a space in between. This patch removes the space and also ensures that pointers to pointers are formatted correctly.
rdar://131780418
>From 99508aa0292a04ae5eca6a7e9d43e22f6b7a0cb4 Mon Sep 17 00:00:00 2001
From: Prajwal Nadig <pnadig at apple.com>
Date: Sat, 28 Jun 2025 01:33:42 +0100
Subject: [PATCH] [ExtractAPI] Format pointers in params correctly
Pointer types in function parameters must place the asterisk before the
identifier without a space in between. This patch removes the space and
also ensures that pointers to pointers are formatted correctly.
rdar://131780418
---
clang/lib/ExtractAPI/DeclarationFragments.cpp | 14 +-
clang/test/ExtractAPI/global_record.c | 4 +-
.../test/ExtractAPI/global_record_multifile.c | 4 +-
clang/test/ExtractAPI/macro_undefined.c | 4 +-
clang/test/ExtractAPI/pointers.c | 250 ++++++++++++++++++
5 files changed, 266 insertions(+), 10 deletions(-)
create mode 100644 clang/test/ExtractAPI/pointers.c
diff --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp
index 348e7588690a2..200029ed9e406 100644
--- a/clang/lib/ExtractAPI/DeclarationFragments.cpp
+++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -324,10 +324,16 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType(
// Declaration fragments of a pointer type is the declaration fragments of
// the pointee type followed by a `*`,
- if (T->isPointerType() && !T->isFunctionPointerType())
+ if (T->isPointerType() && !T->isFunctionPointerType()) {
+ QualType PointeeT = T->getPointeeType();
+ Fragments.append(getFragmentsForType(PointeeT, Context, After));
+ // If the pointee is itself a pointer, we do not want to insert a space
+ // before the `*` as the preceding character in the type name is a `*`.
+ if (!PointeeT->isAnyPointerType() && !PointeeT->isObjCObjectPointerType())
+ Fragments.appendSpace();
return Fragments
- .append(getFragmentsForType(T->getPointeeType(), Context, After))
- .append(" *", DeclarationFragments::FragmentKind::Text);
+ .append("*", DeclarationFragments::FragmentKind::Text);
+ }
// For Objective-C `id` and `Class` pointers
// we do not spell out the `*`.
@@ -631,7 +637,7 @@ DeclarationFragmentsBuilder::getFragmentsForParam(const ParmVarDecl *Param) {
DeclarationFragments::FragmentKind::InternalParam);
} else {
Fragments.append(std::move(TypeFragments));
- if (!T->isBlockPointerType())
+ if (!T->isAnyPointerType() && !T->isBlockPointerType())
Fragments.appendSpace();
Fragments
.append(Param->getName(),
diff --git a/clang/test/ExtractAPI/global_record.c b/clang/test/ExtractAPI/global_record.c
index a08d51d21f955..287fa24c4c64e 100644
--- a/clang/test/ExtractAPI/global_record.c
+++ b/clang/test/ExtractAPI/global_record.c
@@ -185,7 +185,7 @@ char unavailable __attribute__((unavailable));
},
{
"kind": "text",
- "spelling": " * "
+ "spelling": " *"
},
{
"kind": "internalParam",
@@ -341,7 +341,7 @@ char unavailable __attribute__((unavailable));
},
{
"kind": "text",
- "spelling": " * "
+ "spelling": " *"
},
{
"kind": "internalParam",
diff --git a/clang/test/ExtractAPI/global_record_multifile.c b/clang/test/ExtractAPI/global_record_multifile.c
index ffdfbcb7eb808..b98cd27b1601e 100644
--- a/clang/test/ExtractAPI/global_record_multifile.c
+++ b/clang/test/ExtractAPI/global_record_multifile.c
@@ -187,7 +187,7 @@ char unavailable __attribute__((unavailable));
},
{
"kind": "text",
- "spelling": " * "
+ "spelling": " *"
},
{
"kind": "internalParam",
@@ -343,7 +343,7 @@ char unavailable __attribute__((unavailable));
},
{
"kind": "text",
- "spelling": " * "
+ "spelling": " *"
},
{
"kind": "internalParam",
diff --git a/clang/test/ExtractAPI/macro_undefined.c b/clang/test/ExtractAPI/macro_undefined.c
index ec60f95d3d6c4..7bb50af380c24 100644
--- a/clang/test/ExtractAPI/macro_undefined.c
+++ b/clang/test/ExtractAPI/macro_undefined.c
@@ -148,7 +148,7 @@ FUNC_GEN(bar, const int *, unsigned);
},
{
"kind": "text",
- "spelling": " * "
+ "spelling": " *"
},
{
"kind": "internalParam",
@@ -195,7 +195,7 @@ FUNC_GEN(bar, const int *, unsigned);
},
{
"kind": "text",
- "spelling": " * "
+ "spelling": " *"
},
{
"kind": "internalParam",
diff --git a/clang/test/ExtractAPI/pointers.c b/clang/test/ExtractAPI/pointers.c
new file mode 100644
index 0000000000000..07c84942c09c6
--- /dev/null
+++ b/clang/test/ExtractAPI/pointers.c
@@ -0,0 +1,250 @@
+// 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 -extract-api --pretty-sgf --product-name=Pointers -target arm64-apple-macosx \
+// RUN: %t/input.h -o %t/output.json | FileCheck -allow-empty %s
+
+// 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
+
+// CHECK-NOT: error:
+// CHECK-NOT: warning:
+
+//--- input.h
+void foo(int *a);
+void bar(int **a);
+
+//--- reference.output.json.in
+{
+ "metadata": {
+ "formatVersion": {
+ "major": 0,
+ "minor": 5,
+ "patch": 3
+ },
+ "generator": "?"
+ },
+ "module": {
+ "name": "Pointers",
+ "platform": {
+ "architecture": "arm64",
+ "operatingSystem": {
+ "minimumVersion": {
+ "major": 11,
+ "minor": 0,
+ "patch": 0
+ },
+ "name": "macosx"
+ },
+ "vendor": "apple"
+ }
+ },
+ "relationships": [],
+ "symbols": [
+ {
+ "accessLevel": "public",
+ "declarationFragments": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:v",
+ "spelling": "void"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "foo"
+ },
+ {
+ "kind": "text",
+ "spelling": "("
+ },
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:I",
+ "spelling": "int"
+ },
+ {
+ "kind": "text",
+ "spelling": " *"
+ },
+ {
+ "kind": "internalParam",
+ "spelling": "a"
+ },
+ {
+ "kind": "text",
+ "spelling": ");"
+ }
+ ],
+ "functionSignature": {
+ "parameters": [
+ {
+ "declarationFragments": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:I",
+ "spelling": "int"
+ },
+ {
+ "kind": "text",
+ "spelling": " *"
+ },
+ {
+ "kind": "internalParam",
+ "spelling": "a"
+ }
+ ],
+ "name": "a"
+ }
+ ],
+ "returns": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:v",
+ "spelling": "void"
+ }
+ ]
+ },
+ "identifier": {
+ "interfaceLanguage": "c",
+ "precise": "c:@F at foo"
+ },
+ "kind": {
+ "displayName": "Function",
+ "identifier": "c.func"
+ },
+ "location": {
+ "position": {
+ "character": 5,
+ "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": "typeIdentifier",
+ "preciseIdentifier": "c:v",
+ "spelling": "void"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "bar"
+ },
+ {
+ "kind": "text",
+ "spelling": "("
+ },
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:I",
+ "spelling": "int"
+ },
+ {
+ "kind": "text",
+ "spelling": " **"
+ },
+ {
+ "kind": "internalParam",
+ "spelling": "a"
+ },
+ {
+ "kind": "text",
+ "spelling": ");"
+ }
+ ],
+ "functionSignature": {
+ "parameters": [
+ {
+ "declarationFragments": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:I",
+ "spelling": "int"
+ },
+ {
+ "kind": "text",
+ "spelling": " **"
+ },
+ {
+ "kind": "internalParam",
+ "spelling": "a"
+ }
+ ],
+ "name": "a"
+ }
+ ],
+ "returns": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:v",
+ "spelling": "void"
+ }
+ ]
+ },
+ "identifier": {
+ "interfaceLanguage": "c",
+ "precise": "c:@F at bar"
+ },
+ "kind": {
+ "displayName": "Function",
+ "identifier": "c.func"
+ },
+ "location": {
+ "position": {
+ "character": 5,
+ "line": 1
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "bar"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "bar"
+ }
+ ],
+ "title": "bar"
+ },
+ "pathComponents": [
+ "bar"
+ ]
+ }
+ ]
+}
More information about the cfe-commits
mailing list