[clang] [clang][ExtractAPI] Ensure typedef to pointer types are preserved (PR #78584)
Daniel Grumberg via cfe-commits
cfe-commits at lists.llvm.org
Thu Jan 18 06:06:01 PST 2024
https://github.com/daniel-grumberg created https://github.com/llvm/llvm-project/pull/78584
When generating declaration fragments for types that use typedefs to pointer types ensure that we keep the user-defined typedef form instead of desugaring the typedef.
rdar://102137655
>From d3c4ca8092fcec8c8ebea26826cdf7e724edf7a7 Mon Sep 17 00:00:00 2001
From: Daniel Grumberg <dgrumberg at apple.com>
Date: Thu, 18 Jan 2024 13:13:13 +0000
Subject: [PATCH] [clang][ExtractAPI] Ensure typedef to pointer types are
preserved
When generating declaration fragments for types that use typedefs to
pointer types ensure that we keep the user-defined typedef form instead
of desugaring the typedef.
rdar://102137655
---
clang/lib/ExtractAPI/DeclarationFragments.cpp | 80 ++---
clang/test/ExtractAPI/typedef.c | 280 ++++++++++++++++++
2 files changed, 320 insertions(+), 40 deletions(-)
diff --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp
index eb6eea0aaf5465..ae6b2eff5c8a29 100644
--- a/clang/lib/ExtractAPI/DeclarationFragments.cpp
+++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -252,6 +252,46 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType(
DeclarationFragments Fragments;
+ // An ElaboratedType is a sugar for types that are referred to using an
+ // elaborated keyword, e.g., `struct S`, `enum E`, or (in C++) via a
+ // qualified name, e.g., `N::M::type`, or both.
+ if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(T)) {
+ ElaboratedTypeKeyword Keyword = ET->getKeyword();
+ if (Keyword != ElaboratedTypeKeyword::None) {
+ Fragments
+ .append(ElaboratedType::getKeywordName(Keyword),
+ DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace();
+ }
+
+ if (const NestedNameSpecifier *NNS = ET->getQualifier())
+ Fragments.append(getFragmentsForNNS(NNS, Context, After));
+
+ // After handling the elaborated keyword or qualified name, build
+ // declaration fragments for the desugared underlying type.
+ return Fragments.append(getFragmentsForType(ET->desugar(), Context, After));
+ }
+
+ // If the type is a typedefed type, get the underlying TypedefNameDecl for a
+ // direct reference to the typedef instead of the wrapped type.
+
+ // 'id' type is a typedef for an ObjCObjectPointerType
+ // we treat it as a typedef
+ if (const TypedefType *TypedefTy = dyn_cast<TypedefType>(T)) {
+ const TypedefNameDecl *Decl = TypedefTy->getDecl();
+ TypedefUnderlyingTypeResolver TypedefResolver(Context);
+ std::string USR = TypedefResolver.getUSRForType(QualType(T, 0));
+
+ if (T->isObjCIdType()) {
+ return Fragments.append(Decl->getName(),
+ DeclarationFragments::FragmentKind::Keyword);
+ }
+
+ return Fragments.append(
+ Decl->getName(), DeclarationFragments::FragmentKind::TypeIdentifier,
+ USR, TypedefResolver.getUnderlyingTypeDecl(QualType(T, 0)));
+ }
+
// Declaration fragments of a pointer type is the declaration fragments of
// the pointee type followed by a `*`,
if (T->isPointerType() && !T->isFunctionPointerType())
@@ -328,46 +368,6 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType(
getFragmentsForType(AT->getElementType(), Context, After));
}
- // An ElaboratedType is a sugar for types that are referred to using an
- // elaborated keyword, e.g., `struct S`, `enum E`, or (in C++) via a
- // qualified name, e.g., `N::M::type`, or both.
- if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(T)) {
- ElaboratedTypeKeyword Keyword = ET->getKeyword();
- if (Keyword != ElaboratedTypeKeyword::None) {
- Fragments
- .append(ElaboratedType::getKeywordName(Keyword),
- DeclarationFragments::FragmentKind::Keyword)
- .appendSpace();
- }
-
- if (const NestedNameSpecifier *NNS = ET->getQualifier())
- Fragments.append(getFragmentsForNNS(NNS, Context, After));
-
- // After handling the elaborated keyword or qualified name, build
- // declaration fragments for the desugared underlying type.
- return Fragments.append(getFragmentsForType(ET->desugar(), Context, After));
- }
-
- // If the type is a typedefed type, get the underlying TypedefNameDecl for a
- // direct reference to the typedef instead of the wrapped type.
-
- // 'id' type is a typedef for an ObjCObjectPointerType
- // we treat it as a typedef
- if (const TypedefType *TypedefTy = dyn_cast<TypedefType>(T)) {
- const TypedefNameDecl *Decl = TypedefTy->getDecl();
- TypedefUnderlyingTypeResolver TypedefResolver(Context);
- std::string USR = TypedefResolver.getUSRForType(QualType(T, 0));
-
- if (T->isObjCIdType()) {
- return Fragments.append(Decl->getName(),
- DeclarationFragments::FragmentKind::Keyword);
- }
-
- return Fragments.append(
- Decl->getName(), DeclarationFragments::FragmentKind::TypeIdentifier,
- USR, TypedefResolver.getUnderlyingTypeDecl(QualType(T, 0)));
- }
-
// Everything we care about has been handled now, reduce to the canonical
// unqualified base type.
QualType Base = T->getCanonicalTypeUnqualified();
diff --git a/clang/test/ExtractAPI/typedef.c b/clang/test/ExtractAPI/typedef.c
index 7f30b4bc9bb0c2..c30e65549f2b74 100644
--- a/clang/test/ExtractAPI/typedef.c
+++ b/clang/test/ExtractAPI/typedef.c
@@ -16,6 +16,12 @@
//--- input.h
typedef int MyInt;
+typedef struct Bar *BarPtr;
+
+void foo(BarPtr value);
+
+void baz(BarPtr *value);
+
//--- reference.output.json.in
{
"metadata": {
@@ -43,6 +49,208 @@ typedef int MyInt;
},
"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:input.h at T@BarPtr",
+ "spelling": "BarPtr"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "internalParam",
+ "spelling": "value"
+ },
+ {
+ "kind": "text",
+ "spelling": ");"
+ }
+ ],
+ "functionSignature": {
+ "parameters": [
+ {
+ "declarationFragments": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:input.h at T@BarPtr",
+ "spelling": "BarPtr"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "internalParam",
+ "spelling": "value"
+ }
+ ],
+ "name": "value"
+ }
+ ],
+ "returns": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:v",
+ "spelling": "void"
+ }
+ ]
+ },
+ "identifier": {
+ "interfaceLanguage": "objective-c",
+ "precise": "c:@F at foo"
+ },
+ "kind": {
+ "displayName": "Function",
+ "identifier": "objective-c.func"
+ },
+ "location": {
+ "position": {
+ "character": 5,
+ "line": 4
+ },
+ "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": "baz"
+ },
+ {
+ "kind": "text",
+ "spelling": "("
+ },
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:input.h at T@BarPtr",
+ "spelling": "BarPtr"
+ },
+ {
+ "kind": "text",
+ "spelling": " * "
+ },
+ {
+ "kind": "internalParam",
+ "spelling": "value"
+ },
+ {
+ "kind": "text",
+ "spelling": ");"
+ }
+ ],
+ "functionSignature": {
+ "parameters": [
+ {
+ "declarationFragments": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:input.h at T@BarPtr",
+ "spelling": "BarPtr"
+ },
+ {
+ "kind": "text",
+ "spelling": " * "
+ },
+ {
+ "kind": "internalParam",
+ "spelling": "value"
+ }
+ ],
+ "name": "value"
+ }
+ ],
+ "returns": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:v",
+ "spelling": "void"
+ }
+ ]
+ },
+ "identifier": {
+ "interfaceLanguage": "objective-c",
+ "precise": "c:@F at baz"
+ },
+ "kind": {
+ "displayName": "Function",
+ "identifier": "objective-c.func"
+ },
+ "location": {
+ "position": {
+ "character": 5,
+ "line": 6
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "baz"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "baz"
+ }
+ ],
+ "title": "baz"
+ },
+ "pathComponents": [
+ "baz"
+ ]
+ },
{
"accessLevel": "public",
"declarationFragments": [
@@ -106,6 +314,78 @@ typedef int MyInt;
"MyInt"
],
"type": "c:I"
+ },
+ {
+ "accessLevel": "public",
+ "declarationFragments": [
+ {
+ "kind": "keyword",
+ "spelling": "typedef"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "keyword",
+ "spelling": "struct"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:@S at Bar",
+ "spelling": "Bar"
+ },
+ {
+ "kind": "text",
+ "spelling": " * "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "BarPtr"
+ },
+ {
+ "kind": "text",
+ "spelling": ";"
+ }
+ ],
+ "identifier": {
+ "interfaceLanguage": "objective-c",
+ "precise": "c:input.h at T@BarPtr"
+ },
+ "kind": {
+ "displayName": "Type Alias",
+ "identifier": "objective-c.typealias"
+ },
+ "location": {
+ "position": {
+ "character": 20,
+ "line": 2
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "BarPtr"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "BarPtr"
+ }
+ ],
+ "title": "BarPtr"
+ },
+ "pathComponents": [
+ "BarPtr"
+ ],
+ "type": "c:*$@S at Bar"
}
]
}
More information about the cfe-commits
mailing list