[clang] 53102a3 - [ExtractAPI] Format pointer types correctly (#146182)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 30 07:55:38 PDT 2025
Author: Prajwal Nadig
Date: 2025-06-30T08:55:35-06:00
New Revision: 53102a395f3bd07762c183c9ecd213a4759559dd
URL: https://github.com/llvm/llvm-project/commit/53102a395f3bd07762c183c9ecd213a4759559dd
DIFF: https://github.com/llvm/llvm-project/commit/53102a395f3bd07762c183c9ecd213a4759559dd.diff
LOG: [ExtractAPI] Format pointer types correctly (#146182)
Pointer types in function signatures 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
rdar://154533037
Added:
clang/test/ExtractAPI/pointers.c
Modified:
clang/lib/ExtractAPI/DeclarationFragments.cpp
clang/test/ExtractAPI/global_record.c
clang/test/ExtractAPI/global_record_multifile.c
clang/test/ExtractAPI/macro_undefined.c
Removed:
################################################################################
diff --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp
index 348e7588690a2..52349324d7829 100644
--- a/clang/lib/ExtractAPI/DeclarationFragments.cpp
+++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -324,10 +324,15 @@ 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())
- return Fragments
- .append(getFragmentsForType(T->getPointeeType(), Context, After))
- .append(" *", DeclarationFragments::FragmentKind::Text);
+ 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())
+ Fragments.appendSpace();
+ return Fragments.append("*", DeclarationFragments::FragmentKind::Text);
+ }
// For Objective-C `id` and `Class` pointers
// we do not spell out the `*`.
@@ -631,7 +636,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(),
@@ -706,18 +711,20 @@ DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) {
// FIXME: Is `after` actually needed here?
DeclarationFragments After;
+ QualType ReturnType = Func->getReturnType();
auto ReturnValueFragment =
- getFragmentsForType(Func->getReturnType(), Func->getASTContext(), After);
+ getFragmentsForType(ReturnType, Func->getASTContext(), After);
if (StringRef(ReturnValueFragment.begin()->Spelling)
.starts_with("type-parameter")) {
- std::string ProperArgName = Func->getReturnType().getAsString();
+ std::string ProperArgName = ReturnType.getAsString();
ReturnValueFragment.begin()->Spelling.swap(ProperArgName);
}
- Fragments.append(std::move(ReturnValueFragment))
- .appendSpace()
- .append(Func->getNameAsString(),
- DeclarationFragments::FragmentKind::Identifier);
+ Fragments.append(std::move(ReturnValueFragment));
+ if (!ReturnType->isAnyPointerType())
+ Fragments.appendSpace();
+ Fragments.append(Func->getNameAsString(),
+ DeclarationFragments::FragmentKind::Identifier);
if (Func->getTemplateSpecializationInfo()) {
Fragments.append("<", DeclarationFragments::FragmentKind::Text);
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..d7baf541ec03e
--- /dev/null
+++ b/clang/test/ExtractAPI/pointers.c
@@ -0,0 +1,388 @@
+// 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);
+void *baz();
+void **qux();
+
+//--- 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"
+ ]
+ },
+ {
+ "accessLevel": "public",
+ "declarationFragments": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:v",
+ "spelling": "void"
+ },
+ {
+ "kind": "text",
+ "spelling": " *"
+ },
+ {
+ "kind": "identifier",
+ "spelling": "baz"
+ },
+ {
+ "kind": "text",
+ "spelling": "();"
+ }
+ ],
+ "functionSignature": {
+ "returns": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:v",
+ "spelling": "void"
+ },
+ {
+ "kind": "text",
+ "spelling": " *"
+ }
+ ]
+ },
+ "identifier": {
+ "interfaceLanguage": "c",
+ "precise": "c:@F at baz"
+ },
+ "kind": {
+ "displayName": "Function",
+ "identifier": "c.func"
+ },
+ "location": {
+ "position": {
+ "character": 6,
+ "line": 2
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "baz"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "baz"
+ }
+ ],
+ "title": "baz"
+ },
+ "pathComponents": [
+ "baz"
+ ]
+ },
+ {
+ "accessLevel": "public",
+ "declarationFragments": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:v",
+ "spelling": "void"
+ },
+ {
+ "kind": "text",
+ "spelling": " **"
+ },
+ {
+ "kind": "identifier",
+ "spelling": "qux"
+ },
+ {
+ "kind": "text",
+ "spelling": "();"
+ }
+ ],
+ "functionSignature": {
+ "returns": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:v",
+ "spelling": "void"
+ },
+ {
+ "kind": "text",
+ "spelling": " **"
+ }
+ ]
+ },
+ "identifier": {
+ "interfaceLanguage": "c",
+ "precise": "c:@F at qux"
+ },
+ "kind": {
+ "displayName": "Function",
+ "identifier": "c.func"
+ },
+ "location": {
+ "position": {
+ "character": 7,
+ "line": 3
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "qux"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "qux"
+ }
+ ],
+ "title": "qux"
+ },
+ "pathComponents": [
+ "qux"
+ ]
+ }
+ ]
+}
More information about the cfe-commits
mailing list