Author: StoeckOverflow
Date: 2026-08-13T11:52:13Z
New Revision: e67c6a8316dffc0aab581f773f189bfd6273f0ef

URL: 
https://github.com/llvm/llvm-project/commit/e67c6a8316dffc0aab581f773f189bfd6273f0ef
DIFF: 
https://github.com/llvm/llvm-project/commit/e67c6a8316dffc0aab581f773f189bfd6273f0ef.diff

LOG: [APINotes] Strip selector volatile and nested nullability from parameter 
selectors (#215266)

Address @Xazax-hun's comments about volatile and nullability stripping
from
https://github.com/llvm/llvm-project/pull/213043#pullrequestreview-4830763715.

This strips top-level `volatile` like top-level `const` when building
`Where.Parameters` selector spellings, and recursively strips
nullability through pointer-like layers such as `int * _Nullable *
_Nullable`.

This is a prequel PR to
https://github.com/llvm/llvm-project/pull/213043.

Reviewers: @Xazax-hun @j-hui @egorzhdan

Added: 
    

Modified: 
    clang/include/clang/AST/TypeBase.h
    clang/lib/AST/Type.cpp
    clang/lib/Sema/SemaAPINotes.cpp
    clang/test/APINotes/Inputs/Headers/WhereParametersSema.apinotes
    clang/test/APINotes/Inputs/Headers/WhereParametersSema.h
    clang/test/APINotes/where-parameters-sema.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/TypeBase.h 
b/clang/include/clang/AST/TypeBase.h
index a344402e90c17..eb05a068934ea 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -1635,6 +1635,9 @@ class QualType {
   /// Strip Objective-C "__kindof" types from the given type.
   QualType stripObjCKindOfType(const ASTContext &ctx) const;
 
+  /// Strip nullability attributes from the given type.
+  QualType stripNullability(const ASTContext &ctx) const;
+
   /// Remove all qualifiers including _Atomic.
   ///
   /// Like getUnqualifiedType(), the type may still be qualified if it is a

diff  --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index cc5b7d944129b..5069b587c1f8b 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -1639,6 +1639,24 @@ struct SubstObjCTypeArgsVisitor
   }
 };
 
+struct StripNullabilityTypeVisitor
+    : public SimpleTransformVisitor<StripNullabilityTypeVisitor> {
+  using BaseType = SimpleTransformVisitor<StripNullabilityTypeVisitor>;
+
+  explicit StripNullabilityTypeVisitor(ASTContext &ctx) : BaseType(ctx) {}
+
+  QualType VisitAttributedType(const AttributedType *attrType) {
+    QualType type(attrType, 0);
+    if (AttributedType::stripOuterNullability(type)) {
+      while (AttributedType::stripOuterNullability(type)) {
+      }
+      return BaseType::recurse(type);
+    }
+
+    return BaseType::VisitAttributedType(attrType);
+  }
+};
+
 struct StripObjCKindOfTypeVisitor
     : public SimpleTransformVisitor<StripObjCKindOfTypeVisitor> {
   using BaseType = SimpleTransformVisitor<StripObjCKindOfTypeVisitor>;
@@ -1716,6 +1734,14 @@ QualType QualType::stripObjCKindOfType(const ASTContext 
&constCtx) const {
   return visitor.recurse(*this);
 }
 
+QualType QualType::stripNullability(const ASTContext &constCtx) const {
+  // FIXME: SimpleTransformVisitor currently takes a non-const ASTContext
+  // because some rebuild paths use non-const ASTContext factory APIs.
+  auto &ctx = const_cast<ASTContext &>(constCtx);
+  StripNullabilityTypeVisitor visitor(ctx);
+  return visitor.recurse(*this);
+}
+
 QualType QualType::getAtomicUnqualifiedType() const {
   QualType T = *this;
   if (const auto AT = T.getTypePtr()->getAs<AtomicType>())

diff  --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index 2499104d697a8..78153d9ddf39d 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -1001,13 +1001,6 @@ UnwindTagContext(TagDecl *DC, api_notes::APINotesManager 
&APINotes) {
   return std::nullopt;
 }
 
-static void stripAPINotesParameterNullability(QualType &ParamType) {
-  while (true) {
-    if (!AttributedType::stripOuterNullability(ParamType))
-      return;
-  }
-}
-
 namespace clang {
 struct APINotesParameterSelector {
   SmallVector<std::string, 4> Parameters;
@@ -1050,7 +1043,8 @@ static std::string getAPINotesParameterSelectorSpelling(
     ParamType = ParamType.getDesugaredType(Context);
 
   ParamType.removeLocalConst();
-  stripAPINotesParameterNullability(ParamType);
+  ParamType.removeLocalVolatile();
+  ParamType = ParamType.stripNullability(Context);
 
   return ParamType.getAsString(Policy);
 }

diff  --git a/clang/test/APINotes/Inputs/Headers/WhereParametersSema.apinotes 
b/clang/test/APINotes/Inputs/Headers/WhereParametersSema.apinotes
index 7ffee9223f8c3..9287318253295 100644
--- a/clang/test/APINotes/Inputs/Headers/WhereParametersSema.apinotes
+++ b/clang/test/APINotes/Inputs/Headers/WhereParametersSema.apinotes
@@ -64,6 +64,46 @@ Functions:
     Parameters:
     - int
   SwiftName: constValueGlobal(_:)
+- Name: volatileValueGlobal
+  Where:
+    Parameters:
+    - int
+  SwiftName: volatileValueGlobal(_:)
+- Name: pointerVolatileGlobal
+  Where:
+    Parameters:
+    - 'int *'
+  SwiftName: pointerVolatileGlobal(_:)
+- Name: pointeeVolatileMismatchGlobal
+  Where:
+    Parameters:
+    - 'int *'
+  SwiftName: shouldNotApplyPointeeVolatile(_:)
+- Name: nestedNullableGlobal
+  Where:
+    Parameters:
+    - 'int **'
+  SwiftName: nestedNullableGlobal(_:)
+- Name: nullableArrayGlobal
+  Where:
+    Parameters:
+    - 'int **'
+  SwiftName: nullableArrayGlobal(_:)
+- Name: nullableFunctionPointerItselfGlobal
+  Where:
+    Parameters:
+    - 'void (*)(int *)'
+  SwiftName: nullableFunctionPointerItselfGlobal(_:)
+- Name: nullableFunctionPointerGlobal
+  Where:
+    Parameters:
+    - 'void (*)(int *)'
+  SwiftName: nullableFunctionPointerGlobal(_:)
+- Name: nullableNonnullFunctionPointerGlobal
+  Where:
+    Parameters:
+    - 'void (*)(int *, int *)'
+  SwiftName: nullableNonnullFunctionPointerGlobal(_:)
 Namespaces:
 - Name: SelectorNamespace
   Functions:

diff  --git a/clang/test/APINotes/Inputs/Headers/WhereParametersSema.h 
b/clang/test/APINotes/Inputs/Headers/WhereParametersSema.h
index 8226fa287b115..a302c5ddb18e3 100644
--- a/clang/test/APINotes/Inputs/Headers/WhereParametersSema.h
+++ b/clang/test/APINotes/Inputs/Headers/WhereParametersSema.h
@@ -22,6 +22,15 @@ void multiAliasGlobal(DeepAliasInt);
 void nullableGlobal(char * _Nonnull);
 void rawIntGlobal(int);
 void constValueGlobal(const int);
+void volatileValueGlobal(volatile int);
+void pointerVolatileGlobal(int *volatile);
+void pointeeVolatileMismatchGlobal(volatile int *);
+void nestedNullableGlobal(int * _Nullable * _Nullable);
+void nullableArrayGlobal(int * _Nullable values[4]);
+void nullableFunctionPointerItselfGlobal(void (* _Nullable callback)(int *));
+void nullableFunctionPointerGlobal(void (*callback)(int * _Nullable));
+void nullableNonnullFunctionPointerGlobal(void (*callback)(int * _Nullable,
+                                                          int * _Nonnull));
 
 namespace SelectorNamespace {
 void makeNamespaced(int);

diff  --git a/clang/test/APINotes/where-parameters-sema.cpp 
b/clang/test/APINotes/where-parameters-sema.cpp
index fbb7cb45b9441..089778efc3b7e 100644
--- a/clang/test/APINotes/where-parameters-sema.cpp
+++ b/clang/test/APINotes/where-parameters-sema.cpp
@@ -10,6 +10,14 @@
 // RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
nullableGlobal -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-NULLABILITY %s
 // RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
rawIntGlobal -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-RAW-INT %s
 // RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
constValueGlobal -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-CONST %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
volatileValueGlobal -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-VOLATILE %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
pointerVolatileGlobal -x c++ | FileCheck 
--check-prefix=CHECK-GLOBAL-POINTER-VOLATILE %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
pointeeVolatileMismatchGlobal -x c++ | FileCheck 
--check-prefix=CHECK-GLOBAL-POINTEE-VOLATILE-MISMATCH %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
nestedNullableGlobal -x c++ | FileCheck 
--check-prefix=CHECK-GLOBAL-NESTED-NULLABILITY %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
nullableArrayGlobal -x c++ | FileCheck 
--check-prefix=CHECK-GLOBAL-NULLABLE-ARRAY %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
nullableFunctionPointerItselfGlobal -x c++ | FileCheck 
--check-prefix=CHECK-GLOBAL-NULLABLE-FUNCTION-POINTER-ITSELF %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
nullableFunctionPointerGlobal -x c++ | FileCheck 
--check-prefix=CHECK-GLOBAL-NULLABLE-FUNCTION-POINTER %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
nullableNonnullFunctionPointerGlobal -x c++ | FileCheck 
--check-prefix=CHECK-GLOBAL-NULLABLE-NONNULL-FUNCTION-POINTER %s
 // RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
SelectorNamespace::makeNamespaced -x c++ | FileCheck 
--check-prefix=CHECK-GLOBAL-NAMESPACE %s
 // RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
SelectorWidget::setValue -x c++ | FileCheck 
--check-prefix=CHECK-METHOD-OVERLOADS %s
 // RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash 
-fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter 
SelectorWidget::broad -x c++ | FileCheck --check-prefix=CHECK-METHOD-BROAD %s
@@ -27,6 +35,30 @@
 
 #include "WhereParametersSema.h"
 
+// CHECK-GLOBAL-VOLATILE: FunctionDecl {{.+}} volatileValueGlobal 'void 
(volatile int)'
+// CHECK-GLOBAL-VOLATILE: SwiftNameAttr {{.+}} "volatileValueGlobal(_:)"
+
+// CHECK-GLOBAL-POINTER-VOLATILE: FunctionDecl {{.+}} pointerVolatileGlobal 
'void (int *volatile)'
+// CHECK-GLOBAL-POINTER-VOLATILE: SwiftNameAttr {{.+}} 
"pointerVolatileGlobal(_:)"
+
+// CHECK-GLOBAL-POINTEE-VOLATILE-MISMATCH: FunctionDecl {{.+}} 
pointeeVolatileMismatchGlobal 'void (volatile int *)'
+// CHECK-GLOBAL-POINTEE-VOLATILE-MISMATCH-NOT: SwiftNameAttr
+
+// CHECK-GLOBAL-NESTED-NULLABILITY: FunctionDecl {{.+}} nestedNullableGlobal 
'void (int * _Nullable * _Nullable)'
+// CHECK-GLOBAL-NESTED-NULLABILITY: SwiftNameAttr {{.+}} 
"nestedNullableGlobal(_:)"
+
+// CHECK-GLOBAL-NULLABLE-ARRAY: FunctionDecl {{.+}} nullableArrayGlobal 'void 
(int * _Nullable *)'
+// CHECK-GLOBAL-NULLABLE-ARRAY: SwiftNameAttr {{.+}} "nullableArrayGlobal(_:)"
+
+// CHECK-GLOBAL-NULLABLE-FUNCTION-POINTER-ITSELF: FunctionDecl {{.+}} 
nullableFunctionPointerItselfGlobal 'void (void (* _Nullable)(int *))'
+// CHECK-GLOBAL-NULLABLE-FUNCTION-POINTER-ITSELF: SwiftNameAttr {{.+}} 
"nullableFunctionPointerItselfGlobal(_:)"
+
+// CHECK-GLOBAL-NULLABLE-FUNCTION-POINTER: FunctionDecl {{.+}} 
nullableFunctionPointerGlobal 'void (void (*)(int * _Nullable))'
+// CHECK-GLOBAL-NULLABLE-FUNCTION-POINTER: SwiftNameAttr {{.+}} 
"nullableFunctionPointerGlobal(_:)"
+
+// CHECK-GLOBAL-NULLABLE-NONNULL-FUNCTION-POINTER: FunctionDecl {{.+}} 
nullableNonnullFunctionPointerGlobal 'void (void (*)(int * _Nullable, int * 
_Nonnull))'
+// CHECK-GLOBAL-NULLABLE-NONNULL-FUNCTION-POINTER: SwiftNameAttr {{.+}} 
"nullableNonnullFunctionPointerGlobal(_:)"
+
 // CHECK-GLOBAL-OVERLOADS: FunctionDecl {{.+}} makeWidget 'void (int)'
 // CHECK-GLOBAL-OVERLOADS-NEXT: ParmVarDecl {{.+}} 'int'
 // CHECK-GLOBAL-OVERLOADS-NEXT: SwiftNameAttr {{.+}} "makeIntWidget(_:)"


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to