[clang] [APINotes] Match function-like Where.Parameters in Sema (PR #205307)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 8 09:55:13 PDT 2026
https://github.com/StoeckOverflow updated https://github.com/llvm/llvm-project/pull/205307
>From ad76085780d755900971db13c1e468be68663153 Mon Sep 17 00:00:00 2001
From: stoeckoverflow <dominic-st at gmx.de>
Date: Fri, 19 Jun 2026 11:17:22 +0200
Subject: [PATCH 1/5] [APINotes] Apply Where.Parameters selectors in Sema
---
clang/lib/Sema/SemaAPINotes.cpp | 45 +++++++
.../Headers/WhereParametersSema.apinotes | 126 ++++++++++++++++++
.../Inputs/Headers/WhereParametersSema.h | 51 +++++++
.../APINotes/Inputs/Headers/module.modulemap | 5 +
clang/test/APINotes/where-parameters-sema.cpp | 110 +++++++++++++++
5 files changed, 337 insertions(+)
create mode 100644 clang/test/APINotes/Inputs/Headers/WhereParametersSema.apinotes
create mode 100644 clang/test/APINotes/Inputs/Headers/WhereParametersSema.h
create mode 100644 clang/test/APINotes/where-parameters-sema.cpp
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index 67c08d239e758..269b96a57fa4b 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -993,6 +993,29 @@ UnwindTagContext(TagDecl *DC, api_notes::APINotesManager &APINotes) {
return std::nullopt;
}
+static std::optional<SmallVector<std::string, 4>>
+getAPINotesParameterSelector(const Sema &S, const FunctionDecl *FD) {
+ const auto *FPT = FD->getType()->getAs<FunctionProtoType>();
+ if (!FPT)
+ return std::nullopt;
+
+ SmallVector<std::string, 4> Parameters;
+ Parameters.reserve(FPT->getNumParams());
+ for (QualType ParamType : FPT->param_types())
+ Parameters.push_back(ParamType.getUnqualifiedType().getAsString(
+ S.Context.getPrintingPolicy()));
+ return Parameters;
+}
+
+static SmallVector<StringRef, 4>
+getAPINotesParameterSelectorRefs(ArrayRef<std::string> Strings) {
+ SmallVector<StringRef, 4> Refs;
+ Refs.reserve(Strings.size());
+ for (const std::string &String : Strings)
+ Refs.push_back(String);
+ return Refs;
+}
+
/// Process API notes that are associated with this declaration, mapping them
/// to attributes as appropriate.
void Sema::ProcessAPINotes(Decl *D) {
@@ -1024,10 +1047,21 @@ void Sema::ProcessAPINotes(Decl *D) {
// Global functions.
if (auto FD = dyn_cast<FunctionDecl>(D)) {
if (FD->getDeclName().isIdentifier()) {
+ std::optional<SmallVector<std::string, 4>> ParameterStrings =
+ getAPINotesParameterSelector(*this, FD);
+ SmallVector<StringRef, 4> Parameters;
+ if (ParameterStrings)
+ Parameters = getAPINotesParameterSelectorRefs(*ParameterStrings);
for (auto Reader : Readers) {
auto Info =
Reader->lookupGlobalFunction(FD->getName(), APINotesContext);
ProcessVersionedAPINotes(*this, FD, Info);
+
+ if (ParameterStrings) {
+ Info = Reader->lookupGlobalFunction(FD->getName(), Parameters,
+ APINotesContext);
+ ProcessVersionedAPINotes(*this, FD, Info);
+ }
}
}
@@ -1211,6 +1245,11 @@ void Sema::ProcessAPINotes(Decl *D) {
if (!isa<CXXConstructorDecl>(CXXMethod) &&
!isa<CXXDestructorDecl>(CXXMethod) &&
!isa<CXXConversionDecl>(CXXMethod)) {
+ std::optional<SmallVector<std::string, 4>> ParameterStrings =
+ getAPINotesParameterSelector(*this, CXXMethod);
+ SmallVector<StringRef, 4> Parameters;
+ if (ParameterStrings)
+ Parameters = getAPINotesParameterSelectorRefs(*ParameterStrings);
for (auto Reader : Readers) {
if (auto Context = UnwindTagContext(TagContext, APINotes)) {
std::string MethodName;
@@ -1223,6 +1262,12 @@ void Sema::ProcessAPINotes(Decl *D) {
auto Info = Reader->lookupCXXMethod(Context->id, MethodName);
ProcessVersionedAPINotes(*this, CXXMethod, Info);
+
+ if (ParameterStrings) {
+ Info =
+ Reader->lookupCXXMethod(Context->id, MethodName, Parameters);
+ ProcessVersionedAPINotes(*this, CXXMethod, Info);
+ }
}
}
}
diff --git a/clang/test/APINotes/Inputs/Headers/WhereParametersSema.apinotes b/clang/test/APINotes/Inputs/Headers/WhereParametersSema.apinotes
new file mode 100644
index 0000000000000..2a9f9c921347b
--- /dev/null
+++ b/clang/test/APINotes/Inputs/Headers/WhereParametersSema.apinotes
@@ -0,0 +1,126 @@
+---
+Name: WhereParametersSema
+Functions:
+- Name: makeWidget
+ Where:
+ Parameters:
+ - int
+ SwiftName: makeIntWidget(_:)
+- Name: makeWidget
+ Where:
+ Parameters:
+ - double
+ SwiftName: makeDoubleWidget(_:)
+- Name: makeWidget
+ Where:
+ Parameters: []
+ SwiftName: makeCurrentWidget()
+- Name: broadGlobal
+ SwiftPrivate: true
+- Name: coexistGlobal
+ SwiftPrivate: true
+- Name: coexistGlobal
+ Where:
+ Parameters:
+ - int
+ SwiftName: coexistGlobalInt(_:)
+- Name: mismatchGlobal
+ Where:
+ Parameters:
+ - int
+ SwiftName: shouldNotApplyGlobal(_:)
+- Name: aliasGlobal
+ Where:
+ Parameters:
+ - int
+ SwiftName: shouldNotApplyAliasGlobal(_:)
+- Name: rawIntGlobal
+ Where:
+ Parameters:
+ - int
+ SwiftName: rawIntGlobal(_:)
+- Name: constValueGlobal
+ Where:
+ Parameters:
+ - int
+ SwiftName: constValueGlobal(_:)
+Namespaces:
+- Name: SelectorNamespace
+ Functions:
+ - Name: makeNamespaced
+ Where:
+ Parameters:
+ - int
+ SwiftName: makeNamespacedInt(_:)
+ - Name: makeNamespaced
+ Where:
+ Parameters:
+ - double
+ SwiftName: makeNamespacedDouble(_:)
+Tags:
+- Name: SelectorWidget
+ Methods:
+ - Name: setValue
+ Where:
+ Parameters:
+ - int
+ SwiftName: setIntValue(_:)
+ - Name: setValue
+ Where:
+ Parameters:
+ - double
+ SwiftName: setDoubleValue(_:)
+ - Name: setValue
+ Where:
+ Parameters: []
+ SwiftName: currentValue()
+ - Name: broad
+ SwiftPrivate: true
+ - Name: coexist
+ SwiftPrivate: true
+ - Name: coexist
+ Where:
+ Parameters:
+ - int
+ SwiftName: coexistInt(_:)
+ - Name: defaults
+ Where:
+ Parameters:
+ - int
+ - double
+ SwiftName: defaultsWithTwoParameters(_:_:)
+ - Name: configure
+ Where:
+ Parameters:
+ - int
+ SwiftName: configureInt(_:)
+ - Name: mismatch
+ Where:
+ Parameters:
+ - int
+ SwiftName: shouldNotApplyMethod(_:)
+ - Name: alias
+ Where:
+ Parameters:
+ - int
+ SwiftName: shouldNotApplyAliasMethod(_:)
+ - Name: rawInt
+ Where:
+ Parameters:
+ - int
+ SwiftName: rawInt(_:)
+ - Name: constValue
+ Where:
+ Parameters:
+ - int
+ SwiftName: constValue(_:)
+ - Name: operator+
+ Where:
+ Parameters:
+ - int
+ SwiftName: plusInt(_:)
+ - Name: operator+
+ Where:
+ Parameters:
+ - double
+ SwiftName: plusDouble(_:)
diff --git a/clang/test/APINotes/Inputs/Headers/WhereParametersSema.h b/clang/test/APINotes/Inputs/Headers/WhereParametersSema.h
new file mode 100644
index 0000000000000..1cd10676e5533
--- /dev/null
+++ b/clang/test/APINotes/Inputs/Headers/WhereParametersSema.h
@@ -0,0 +1,51 @@
+#ifndef WHERE_PARAMETERS_SEMA_H
+#define WHERE_PARAMETERS_SEMA_H
+
+using AliasInt = int;
+
+void makeWidget(int);
+void makeWidget(double);
+void makeWidget();
+
+void broadGlobal(int);
+void broadGlobal(double);
+
+void coexistGlobal(int);
+void coexistGlobal(double);
+
+void mismatchGlobal(float);
+void aliasGlobal(AliasInt);
+void rawIntGlobal(int);
+void constValueGlobal(const int);
+
+namespace SelectorNamespace {
+void makeNamespaced(int);
+void makeNamespaced(double);
+}
+
+struct SelectorWidget {
+ void setValue(int);
+ void setValue(double);
+ void setValue();
+
+ void broad(int);
+ void broad(double);
+
+ void coexist(int);
+ void coexist(double);
+
+ void defaults(int, double = 0);
+ void defaults(int);
+
+ static void configure(int);
+
+ void mismatch(float);
+ void alias(AliasInt);
+ void rawInt(int);
+ void constValue(const int);
+
+ SelectorWidget operator+(int);
+ SelectorWidget operator+(double);
+};
+
+#endif // WHERE_PARAMETERS_SEMA_H
diff --git a/clang/test/APINotes/Inputs/Headers/module.modulemap b/clang/test/APINotes/Inputs/Headers/module.modulemap
index 7bcf33644a14f..592d482ea7a57 100644
--- a/clang/test/APINotes/Inputs/Headers/module.modulemap
+++ b/clang/test/APINotes/Inputs/Headers/module.modulemap
@@ -70,3 +70,8 @@ module UnsafeBufferUsage {
header "UnsafeBufferUsage.h"
export *
}
+
+module WhereParametersSema {
+ header "WhereParametersSema.h"
+ export *
+}
diff --git a/clang/test/APINotes/where-parameters-sema.cpp b/clang/test/APINotes/where-parameters-sema.cpp
new file mode 100644
index 0000000000000..7d1dcf7b61abb
--- /dev/null
+++ b/clang/test/APINotes/where-parameters-sema.cpp
@@ -0,0 +1,110 @@
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/WhereParametersSema -fdisable-module-hash -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers %s -x c++
+// 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 makeWidget -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-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 broadGlobal -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-BROAD %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 coexistGlobal -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-COEXIST %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 mismatchGlobal -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-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 aliasGlobal -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-ALIAS %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 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
+// 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::coexist -x c++ | FileCheck --check-prefix=CHECK-METHOD-COEXIST %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::defaults -x c++ | FileCheck --check-prefix=CHECK-METHOD-DEFAULTS %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::configure -x c++ | FileCheck --check-prefix=CHECK-METHOD-STATIC %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::mismatch -x c++ | FileCheck --check-prefix=CHECK-METHOD-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 SelectorWidget::alias -x c++ | FileCheck --check-prefix=CHECK-METHOD-ALIAS %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::rawInt -x c++ | FileCheck --check-prefix=CHECK-METHOD-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 SelectorWidget::constValue -x c++ | FileCheck --check-prefix=CHECK-METHOD-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 SelectorWidget::operator+ -x c++ | FileCheck --check-prefix=CHECK-METHOD-OPERATOR %s
+
+#include "WhereParametersSema.h"
+
+// CHECK-GLOBAL-OVERLOADS: FunctionDecl {{.+}} makeWidget 'void (int)'
+// CHECK-GLOBAL-OVERLOADS-NEXT: ParmVarDecl {{.+}} 'int'
+// CHECK-GLOBAL-OVERLOADS-NEXT: SwiftNameAttr {{.+}} "makeIntWidget(_:)"
+// CHECK-GLOBAL-OVERLOADS: FunctionDecl {{.+}} makeWidget 'void (double)'
+// CHECK-GLOBAL-OVERLOADS-NEXT: ParmVarDecl {{.+}} 'double'
+// CHECK-GLOBAL-OVERLOADS-NEXT: SwiftNameAttr {{.+}} "makeDoubleWidget(_:)"
+// CHECK-GLOBAL-OVERLOADS: FunctionDecl {{.+}} makeWidget 'void ()'
+// CHECK-GLOBAL-OVERLOADS-NEXT: SwiftNameAttr {{.+}} "makeCurrentWidget()"
+
+// CHECK-GLOBAL-BROAD: FunctionDecl {{.+}} broadGlobal 'void (int)'
+// CHECK-GLOBAL-BROAD: SwiftPrivateAttr
+// CHECK-GLOBAL-BROAD: FunctionDecl {{.+}} broadGlobal 'void (double)'
+// CHECK-GLOBAL-BROAD: SwiftPrivateAttr
+
+// CHECK-GLOBAL-COEXIST: FunctionDecl {{.+}} coexistGlobal 'void (int)'
+// CHECK-GLOBAL-COEXIST: SwiftPrivateAttr
+// CHECK-GLOBAL-COEXIST: SwiftNameAttr {{.+}} "coexistGlobalInt(_:)"
+// CHECK-GLOBAL-COEXIST: FunctionDecl {{.+}} coexistGlobal 'void (double)'
+// CHECK-GLOBAL-COEXIST: SwiftPrivateAttr
+// CHECK-GLOBAL-COEXIST-NOT: SwiftNameAttr
+
+// CHECK-GLOBAL-MISMATCH: FunctionDecl {{.+}} mismatchGlobal 'void (float)'
+// CHECK-GLOBAL-MISMATCH-NOT: SwiftNameAttr
+
+// CHECK-GLOBAL-ALIAS: FunctionDecl {{.+}} aliasGlobal 'void (AliasInt)'
+// CHECK-GLOBAL-ALIAS-NOT: SwiftNameAttr
+
+// CHECK-GLOBAL-RAW-INT: FunctionDecl {{.+}} rawIntGlobal 'void (int)'
+// CHECK-GLOBAL-RAW-INT: SwiftNameAttr {{.+}} "rawIntGlobal(_:)"
+
+// CHECK-GLOBAL-CONST: FunctionDecl {{.+}} constValueGlobal 'void (const int)'
+// CHECK-GLOBAL-CONST: SwiftNameAttr {{.+}} "constValueGlobal(_:)"
+
+// CHECK-GLOBAL-NAMESPACE: FunctionDecl {{.+}} makeNamespaced 'void (int)'
+// CHECK-GLOBAL-NAMESPACE-NEXT: ParmVarDecl {{.+}} 'int'
+// CHECK-GLOBAL-NAMESPACE-NEXT: SwiftNameAttr {{.+}} "makeNamespacedInt(_:)"
+// CHECK-GLOBAL-NAMESPACE: FunctionDecl {{.+}} makeNamespaced 'void (double)'
+// CHECK-GLOBAL-NAMESPACE-NEXT: ParmVarDecl {{.+}} 'double'
+// CHECK-GLOBAL-NAMESPACE-NEXT: SwiftNameAttr {{.+}} "makeNamespacedDouble(_:)"
+
+// CHECK-METHOD-OVERLOADS: CXXMethodDecl {{.+}} setValue 'void (int)'
+// CHECK-METHOD-OVERLOADS-NEXT: ParmVarDecl {{.+}} 'int'
+// CHECK-METHOD-OVERLOADS-NEXT: SwiftNameAttr {{.+}} "setIntValue(_:)"
+// CHECK-METHOD-OVERLOADS: CXXMethodDecl {{.+}} setValue 'void (double)'
+// CHECK-METHOD-OVERLOADS-NEXT: ParmVarDecl {{.+}} 'double'
+// CHECK-METHOD-OVERLOADS-NEXT: SwiftNameAttr {{.+}} "setDoubleValue(_:)"
+// CHECK-METHOD-OVERLOADS: CXXMethodDecl {{.+}} setValue 'void ()'
+// CHECK-METHOD-OVERLOADS-NEXT: SwiftNameAttr {{.+}} "currentValue()"
+
+// CHECK-METHOD-BROAD: CXXMethodDecl {{.+}} broad 'void (int)'
+// CHECK-METHOD-BROAD: SwiftPrivateAttr
+// CHECK-METHOD-BROAD: CXXMethodDecl {{.+}} broad 'void (double)'
+// CHECK-METHOD-BROAD: SwiftPrivateAttr
+
+// CHECK-METHOD-COEXIST: CXXMethodDecl {{.+}} coexist 'void (int)'
+// CHECK-METHOD-COEXIST: SwiftPrivateAttr
+// CHECK-METHOD-COEXIST: SwiftNameAttr {{.+}} "coexistInt(_:)"
+// CHECK-METHOD-COEXIST: CXXMethodDecl {{.+}} coexist 'void (double)'
+// CHECK-METHOD-COEXIST: SwiftPrivateAttr
+// CHECK-METHOD-COEXIST-NOT: SwiftNameAttr
+
+// CHECK-METHOD-DEFAULTS: CXXMethodDecl {{.+}} defaults 'void (int, double)'
+// CHECK-METHOD-DEFAULTS: SwiftNameAttr {{.+}} "defaultsWithTwoParameters(_:_:)"
+// CHECK-METHOD-DEFAULTS: CXXMethodDecl {{.+}} defaults 'void (int)'
+// CHECK-METHOD-DEFAULTS-NOT: SwiftNameAttr
+
+// CHECK-METHOD-STATIC: CXXMethodDecl {{.+}} configure 'void (int)' static
+// CHECK-METHOD-STATIC: SwiftNameAttr {{.+}} "configureInt(_:)"
+
+// CHECK-METHOD-MISMATCH: CXXMethodDecl {{.+}} mismatch 'void (float)'
+// CHECK-METHOD-MISMATCH-NOT: SwiftNameAttr
+
+// CHECK-METHOD-ALIAS: CXXMethodDecl {{.+}} alias 'void (AliasInt)'
+// CHECK-METHOD-ALIAS-NOT: SwiftNameAttr
+
+// CHECK-METHOD-RAW-INT: CXXMethodDecl {{.+}} rawInt 'void (int)'
+// CHECK-METHOD-RAW-INT: SwiftNameAttr {{.+}} "rawInt(_:)"
+
+// CHECK-METHOD-CONST: CXXMethodDecl {{.+}} constValue 'void (const int)'
+// CHECK-METHOD-CONST: SwiftNameAttr {{.+}} "constValue(_:)"
+
+// CHECK-METHOD-OPERATOR: CXXMethodDecl {{.+}} operator+ 'SelectorWidget (int)'
+// CHECK-METHOD-OPERATOR-NEXT: ParmVarDecl {{.+}} 'int'
+// CHECK-METHOD-OPERATOR-NEXT: SwiftNameAttr {{.+}} "plusInt(_:)"
+// CHECK-METHOD-OPERATOR: CXXMethodDecl {{.+}} operator+ 'SelectorWidget (double)'
+// CHECK-METHOD-OPERATOR-NEXT: ParmVarDecl {{.+}} 'double'
+// CHECK-METHOD-OPERATOR-NEXT: SwiftNameAttr {{.+}} "plusDouble(_:)"
>From f704aa74f2751e803d59aa7223ed5c2ce4cbb686 Mon Sep 17 00:00:00 2001
From: stoeckoverflow <dominic-st at gmx.de>
Date: Thu, 2 Jul 2026 11:31:45 +0200
Subject: [PATCH 2/5] [APINotes] Add permissive alias and nullability matching
for Where.Parameters
---
clang/lib/Sema/SemaAPINotes.cpp | 114 +++++++++++++-----
.../Headers/WhereParametersSema.apinotes | 34 +++++-
.../Inputs/Headers/WhereParametersSema.h | 4 +
clang/test/APINotes/where-parameters-sema.cpp | 22 +++-
4 files changed, 142 insertions(+), 32 deletions(-)
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index 269b96a57fa4b..cae73fe3f4e3b 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -993,18 +993,56 @@ UnwindTagContext(TagDecl *DC, api_notes::APINotesManager &APINotes) {
return std::nullopt;
}
-static std::optional<SmallVector<std::string, 4>>
-getAPINotesParameterSelector(const Sema &S, const FunctionDecl *FD) {
+static void stripAPINotesParameterNullability(QualType &ParamType) {
+ while (true) {
+ if (!AttributedType::stripOuterNullability(ParamType))
+ return;
+ }
+}
+
+// Print the APINotes selector spelling for one parameter. The source-spelled
+// selector is tried first. The desugared spelling is only a permissive
+// fallback.
+static std::string getAPINotesParameterSelectorSpelling(
+ QualType ParamType, const ASTContext &Context, const PrintingPolicy &Policy,
+ bool Desugar) {
+ ParamType.removeLocalConst();
+ stripAPINotesParameterNullability(ParamType);
+
+ if (Desugar) {
+ ParamType = ParamType.getDesugaredType(Context);
+ ParamType.removeLocalConst();
+ stripAPINotesParameterNullability(ParamType);
+ }
+
+ return ParamType.getAsString(Policy);
+}
+
+static std::optional<SmallVector<SmallVector<std::string, 4>, 2>>
+getAPINotesParameterSelectorCandidates(const Sema &S, const FunctionDecl *FD) {
const auto *FPT = FD->getType()->getAs<FunctionProtoType>();
if (!FPT)
return std::nullopt;
- SmallVector<std::string, 4> Parameters;
- Parameters.reserve(FPT->getNumParams());
- for (QualType ParamType : FPT->param_types())
- Parameters.push_back(ParamType.getUnqualifiedType().getAsString(
- S.Context.getPrintingPolicy()));
- return Parameters;
+ SmallVector<std::string, 4> SourceParameters;
+ SmallVector<std::string, 4> DesugaredParameters;
+ SourceParameters.reserve(FPT->getNumParams());
+ DesugaredParameters.reserve(FPT->getNumParams());
+
+ const PrintingPolicy &Policy = S.Context.getPrintingPolicy();
+ for (QualType ParamType : FPT->param_types()) {
+ SourceParameters.push_back(getAPINotesParameterSelectorSpelling(
+ ParamType, S.Context, Policy, /*Desugar=*/false));
+ DesugaredParameters.push_back(getAPINotesParameterSelectorSpelling(
+ ParamType, S.Context, Policy, /*Desugar=*/true));
+ }
+
+ SmallVector<SmallVector<std::string, 4>, 2> Candidates;
+ Candidates.push_back(std::move(SourceParameters));
+ if (Candidates.front() != DesugaredParameters)
+ Candidates.push_back(std::move(DesugaredParameters));
+
+ return Candidates;
}
static SmallVector<StringRef, 4>
@@ -1016,6 +1054,26 @@ getAPINotesParameterSelectorRefs(ArrayRef<std::string> Strings) {
return Refs;
}
+// Apply the first exact selector entry found. This preserves source-spelling
+// precedence over the desugared fallback and avoids applying multiple exact
+// entries for the same declaration.
+template <typename SpecificDecl, typename LookupExactFn>
+static void processExactAPINotes(
+ Sema &S, SpecificDecl *D,
+ ArrayRef<SmallVector<std::string, 4>> ParameterSelectorCandidates,
+ LookupExactFn LookupExact) {
+ for (ArrayRef<std::string> ParameterStrings : ParameterSelectorCandidates) {
+ SmallVector<StringRef, 4> Parameters =
+ getAPINotesParameterSelectorRefs(ParameterStrings);
+ auto Info = LookupExact(Parameters);
+ if (Info.size() == 0)
+ continue;
+
+ ProcessVersionedAPINotes(S, D, Info);
+ return;
+ }
+}
+
/// Process API notes that are associated with this declaration, mapping them
/// to attributes as appropriate.
void Sema::ProcessAPINotes(Decl *D) {
@@ -1047,21 +1105,21 @@ void Sema::ProcessAPINotes(Decl *D) {
// Global functions.
if (auto FD = dyn_cast<FunctionDecl>(D)) {
if (FD->getDeclName().isIdentifier()) {
- std::optional<SmallVector<std::string, 4>> ParameterStrings =
- getAPINotesParameterSelector(*this, FD);
- SmallVector<StringRef, 4> Parameters;
- if (ParameterStrings)
- Parameters = getAPINotesParameterSelectorRefs(*ParameterStrings);
+ std::optional<SmallVector<SmallVector<std::string, 4>, 2>>
+ ParameterSelectorCandidates =
+ getAPINotesParameterSelectorCandidates(*this, FD);
for (auto Reader : Readers) {
auto Info =
Reader->lookupGlobalFunction(FD->getName(), APINotesContext);
ProcessVersionedAPINotes(*this, FD, Info);
- if (ParameterStrings) {
- Info = Reader->lookupGlobalFunction(FD->getName(), Parameters,
- APINotesContext);
- ProcessVersionedAPINotes(*this, FD, Info);
- }
+ if (ParameterSelectorCandidates)
+ processExactAPINotes(*this, FD, *ParameterSelectorCandidates,
+ [&](ArrayRef<StringRef> Parameters) {
+ return Reader->lookupGlobalFunction(
+ FD->getName(), Parameters,
+ APINotesContext);
+ });
}
}
@@ -1245,11 +1303,9 @@ void Sema::ProcessAPINotes(Decl *D) {
if (!isa<CXXConstructorDecl>(CXXMethod) &&
!isa<CXXDestructorDecl>(CXXMethod) &&
!isa<CXXConversionDecl>(CXXMethod)) {
- std::optional<SmallVector<std::string, 4>> ParameterStrings =
- getAPINotesParameterSelector(*this, CXXMethod);
- SmallVector<StringRef, 4> Parameters;
- if (ParameterStrings)
- Parameters = getAPINotesParameterSelectorRefs(*ParameterStrings);
+ std::optional<SmallVector<SmallVector<std::string, 4>, 2>>
+ ParameterSelectorCandidates =
+ getAPINotesParameterSelectorCandidates(*this, CXXMethod);
for (auto Reader : Readers) {
if (auto Context = UnwindTagContext(TagContext, APINotes)) {
std::string MethodName;
@@ -1263,11 +1319,13 @@ void Sema::ProcessAPINotes(Decl *D) {
auto Info = Reader->lookupCXXMethod(Context->id, MethodName);
ProcessVersionedAPINotes(*this, CXXMethod, Info);
- if (ParameterStrings) {
- Info =
- Reader->lookupCXXMethod(Context->id, MethodName, Parameters);
- ProcessVersionedAPINotes(*this, CXXMethod, Info);
- }
+ if (ParameterSelectorCandidates)
+ processExactAPINotes(*this, CXXMethod,
+ *ParameterSelectorCandidates,
+ [&](ArrayRef<StringRef> Parameters) {
+ return Reader->lookupCXXMethod(
+ Context->id, MethodName, Parameters);
+ });
}
}
}
diff --git a/clang/test/APINotes/Inputs/Headers/WhereParametersSema.apinotes b/clang/test/APINotes/Inputs/Headers/WhereParametersSema.apinotes
index 2a9f9c921347b..2f3b31148661f 100644
--- a/clang/test/APINotes/Inputs/Headers/WhereParametersSema.apinotes
+++ b/clang/test/APINotes/Inputs/Headers/WhereParametersSema.apinotes
@@ -33,7 +33,22 @@ Functions:
Where:
Parameters:
- int
- SwiftName: shouldNotApplyAliasGlobal(_:)
+ SwiftName: aliasGlobal(_:)
+- Name: aliasPrecedenceGlobal
+ Where:
+ Parameters:
+ - int
+ SwiftName: fallbackAliasPrecedenceGlobal(_:)
+- Name: aliasPrecedenceGlobal
+ Where:
+ Parameters:
+ - AliasInt
+ SwiftName: aliasPrecedenceGlobal(_:)
+- Name: nullableGlobal
+ Where:
+ Parameters:
+ - 'char *'
+ SwiftName: nullableGlobal(_:)
- Name: rawIntGlobal
Where:
Parameters:
@@ -103,7 +118,22 @@ Tags:
Where:
Parameters:
- int
- SwiftName: shouldNotApplyAliasMethod(_:)
+ SwiftName: alias(_:)
+ - Name: aliasPrecedence
+ Where:
+ Parameters:
+ - int
+ SwiftName: fallbackAliasPrecedence(_:)
+ - Name: aliasPrecedence
+ Where:
+ Parameters:
+ - AliasInt
+ SwiftName: aliasPrecedence(_:)
+ - Name: nullable
+ Where:
+ Parameters:
+ - 'char *'
+ SwiftName: nullable(_:)
- Name: rawInt
Where:
Parameters:
diff --git a/clang/test/APINotes/Inputs/Headers/WhereParametersSema.h b/clang/test/APINotes/Inputs/Headers/WhereParametersSema.h
index 1cd10676e5533..85990e4ad7434 100644
--- a/clang/test/APINotes/Inputs/Headers/WhereParametersSema.h
+++ b/clang/test/APINotes/Inputs/Headers/WhereParametersSema.h
@@ -15,6 +15,8 @@ void coexistGlobal(double);
void mismatchGlobal(float);
void aliasGlobal(AliasInt);
+void aliasPrecedenceGlobal(AliasInt);
+void nullableGlobal(char * _Nonnull);
void rawIntGlobal(int);
void constValueGlobal(const int);
@@ -41,6 +43,8 @@ struct SelectorWidget {
void mismatch(float);
void alias(AliasInt);
+ void aliasPrecedence(AliasInt);
+ void nullable(char * _Nonnull);
void rawInt(int);
void constValue(const int);
diff --git a/clang/test/APINotes/where-parameters-sema.cpp b/clang/test/APINotes/where-parameters-sema.cpp
index 7d1dcf7b61abb..6e19719593197 100644
--- a/clang/test/APINotes/where-parameters-sema.cpp
+++ b/clang/test/APINotes/where-parameters-sema.cpp
@@ -5,6 +5,8 @@
// 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 coexistGlobal -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-COEXIST %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 mismatchGlobal -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-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 aliasGlobal -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-ALIAS %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 aliasPrecedenceGlobal -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-ALIAS-PRECEDENCE %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 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 SelectorNamespace::makeNamespaced -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-NAMESPACE %s
@@ -15,6 +17,8 @@
// 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::configure -x c++ | FileCheck --check-prefix=CHECK-METHOD-STATIC %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::mismatch -x c++ | FileCheck --check-prefix=CHECK-METHOD-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 SelectorWidget::alias -x c++ | FileCheck --check-prefix=CHECK-METHOD-ALIAS %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::aliasPrecedence -x c++ | FileCheck --check-prefix=CHECK-METHOD-ALIAS-PRECEDENCE %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::nullable -x c++ | FileCheck --check-prefix=CHECK-METHOD-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 SelectorWidget::rawInt -x c++ | FileCheck --check-prefix=CHECK-METHOD-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 SelectorWidget::constValue -x c++ | FileCheck --check-prefix=CHECK-METHOD-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 SelectorWidget::operator+ -x c++ | FileCheck --check-prefix=CHECK-METHOD-OPERATOR %s
@@ -46,7 +50,14 @@
// CHECK-GLOBAL-MISMATCH-NOT: SwiftNameAttr
// CHECK-GLOBAL-ALIAS: FunctionDecl {{.+}} aliasGlobal 'void (AliasInt)'
-// CHECK-GLOBAL-ALIAS-NOT: SwiftNameAttr
+// CHECK-GLOBAL-ALIAS: SwiftNameAttr {{.+}} "aliasGlobal(_:)"
+
+// CHECK-GLOBAL-ALIAS-PRECEDENCE: FunctionDecl {{.+}} aliasPrecedenceGlobal 'void (AliasInt)'
+// CHECK-GLOBAL-ALIAS-PRECEDENCE-NOT: fallbackAliasPrecedenceGlobal
+// CHECK-GLOBAL-ALIAS-PRECEDENCE: SwiftNameAttr {{.+}} "aliasPrecedenceGlobal(_:)"
+
+// CHECK-GLOBAL-NULLABILITY: FunctionDecl {{.+}} nullableGlobal 'void (char * _Nonnull)'
+// CHECK-GLOBAL-NULLABILITY: SwiftNameAttr {{.+}} "nullableGlobal(_:)"
// CHECK-GLOBAL-RAW-INT: FunctionDecl {{.+}} rawIntGlobal 'void (int)'
// CHECK-GLOBAL-RAW-INT: SwiftNameAttr {{.+}} "rawIntGlobal(_:)"
@@ -94,7 +105,14 @@
// CHECK-METHOD-MISMATCH-NOT: SwiftNameAttr
// CHECK-METHOD-ALIAS: CXXMethodDecl {{.+}} alias 'void (AliasInt)'
-// CHECK-METHOD-ALIAS-NOT: SwiftNameAttr
+// CHECK-METHOD-ALIAS: SwiftNameAttr {{.+}} "alias(_:)"
+
+// CHECK-METHOD-ALIAS-PRECEDENCE: CXXMethodDecl {{.+}} aliasPrecedence 'void (AliasInt)'
+// CHECK-METHOD-ALIAS-PRECEDENCE-NOT: fallbackAliasPrecedence
+// CHECK-METHOD-ALIAS-PRECEDENCE: SwiftNameAttr {{.+}} "aliasPrecedence(_:)"
+
+// CHECK-METHOD-NULLABILITY: CXXMethodDecl {{.+}} nullable 'void (char * _Nonnull)'
+// CHECK-METHOD-NULLABILITY: SwiftNameAttr {{.+}} "nullable(_:)"
// CHECK-METHOD-RAW-INT: CXXMethodDecl {{.+}} rawInt 'void (int)'
// CHECK-METHOD-RAW-INT: SwiftNameAttr {{.+}} "rawInt(_:)"
>From 06e6217d3f09728c67e7e6ec00ccd9e84abc3b95 Mon Sep 17 00:00:00 2001
From: StoeckOverflow <95052643+StoeckOverflow at users.noreply.github.com>
Date: Fri, 3 Jul 2026 08:48:03 +0200
Subject: [PATCH 3/5] Update clang/lib/Sema/SemaAPINotes.cpp
Co-authored-by: John Hui <updog at j-hui.com>
---
clang/lib/Sema/SemaAPINotes.cpp | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index cae73fe3f4e3b..448c6b410fbfc 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -1105,9 +1105,8 @@ void Sema::ProcessAPINotes(Decl *D) {
// Global functions.
if (auto FD = dyn_cast<FunctionDecl>(D)) {
if (FD->getDeclName().isIdentifier()) {
- std::optional<SmallVector<SmallVector<std::string, 4>, 2>>
- ParameterSelectorCandidates =
- getAPINotesParameterSelectorCandidates(*this, FD);
+ auto ParameterSelectorCandidates =
+ getAPINotesParameterSelectorCandidates(*this, FD);
for (auto Reader : Readers) {
auto Info =
Reader->lookupGlobalFunction(FD->getName(), APINotesContext);
>From 75d4bc723bbd9ae515c49c9c9b5f5f001bd255db Mon Sep 17 00:00:00 2001
From: stoeckoverflow <dominic-st at gmx.de>
Date: Fri, 3 Jul 2026 15:48:42 +0200
Subject: [PATCH 4/5] [APINotes] Refine Where.Parameters selector matching
---
clang/lib/Sema/SemaAPINotes.cpp | 121 +++++++++++-------
.../Headers/WhereParametersSema.apinotes | 10 ++
.../Inputs/Headers/WhereParametersSema.h | 4 +
clang/test/APINotes/where-parameters-sema.cpp | 8 ++
4 files changed, 98 insertions(+), 45 deletions(-)
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index 448c6b410fbfc..a2176a3b8b976 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -1000,6 +1000,40 @@ static void stripAPINotesParameterNullability(QualType &ParamType) {
}
}
+struct APINotesParameterSelector {
+ SmallVector<std::string, 4> Parameters;
+
+ SmallVector<StringRef, 4> getParameterRefs() const {
+ SmallVector<StringRef, 4> Refs;
+ Refs.reserve(Parameters.size());
+ for (const std::string &Parameter : Parameters)
+ Refs.push_back(Parameter);
+ return Refs;
+ }
+
+ bool operator==(const APINotesParameterSelector &Other) const {
+ return Parameters == Other.Parameters;
+ }
+};
+
+struct APINotesParameterSelectorCandidates {
+ APINotesParameterSelector Source;
+ std::optional<APINotesParameterSelector> Desugared;
+};
+
+static PrintingPolicy
+getAPINotesParameterSelectorPrintingPolicy(const ASTContext &Context) {
+ PrintingPolicy Policy(Context.getLangOpts());
+ Policy.PrintAsCanonical = false;
+ Policy.FullyQualifiedName = false;
+ Policy.SuppressScope = false;
+ Policy.UsePreferredNames = false;
+ Policy.MSVCFormatting = false;
+ Policy.SplitTemplateClosers = false;
+ Policy.IncludeNewlines = false;
+ return Policy;
+}
+
// Print the APINotes selector spelling for one parameter. The source-spelled
// selector is tried first. The desugared spelling is only a permissive
// fallback.
@@ -1018,60 +1052,58 @@ static std::string getAPINotesParameterSelectorSpelling(
return ParamType.getAsString(Policy);
}
-static std::optional<SmallVector<SmallVector<std::string, 4>, 2>>
+static std::optional<APINotesParameterSelectorCandidates>
getAPINotesParameterSelectorCandidates(const Sema &S, const FunctionDecl *FD) {
const auto *FPT = FD->getType()->getAs<FunctionProtoType>();
if (!FPT)
return std::nullopt;
- SmallVector<std::string, 4> SourceParameters;
- SmallVector<std::string, 4> DesugaredParameters;
- SourceParameters.reserve(FPT->getNumParams());
- DesugaredParameters.reserve(FPT->getNumParams());
+ APINotesParameterSelectorCandidates Candidates;
+ APINotesParameterSelector Desugared;
+ Candidates.Source.Parameters.reserve(FPT->getNumParams());
+ Desugared.Parameters.reserve(FPT->getNumParams());
- const PrintingPolicy &Policy = S.Context.getPrintingPolicy();
+ const PrintingPolicy Policy =
+ getAPINotesParameterSelectorPrintingPolicy(S.Context);
for (QualType ParamType : FPT->param_types()) {
- SourceParameters.push_back(getAPINotesParameterSelectorSpelling(
- ParamType, S.Context, Policy, /*Desugar=*/false));
- DesugaredParameters.push_back(getAPINotesParameterSelectorSpelling(
+ Candidates.Source.Parameters.push_back(
+ getAPINotesParameterSelectorSpelling(ParamType, S.Context, Policy,
+ /*Desugar=*/false));
+ Desugared.Parameters.push_back(getAPINotesParameterSelectorSpelling(
ParamType, S.Context, Policy, /*Desugar=*/true));
}
- SmallVector<SmallVector<std::string, 4>, 2> Candidates;
- Candidates.push_back(std::move(SourceParameters));
- if (Candidates.front() != DesugaredParameters)
- Candidates.push_back(std::move(DesugaredParameters));
+ if (!(Candidates.Source == Desugared))
+ Candidates.Desugared = std::move(Desugared);
return Candidates;
}
-static SmallVector<StringRef, 4>
-getAPINotesParameterSelectorRefs(ArrayRef<std::string> Strings) {
- SmallVector<StringRef, 4> Refs;
- Refs.reserve(Strings.size());
- for (const std::string &String : Strings)
- Refs.push_back(String);
- return Refs;
-}
-
// Apply the first exact selector entry found. This preserves source-spelling
// precedence over the desugared fallback and avoids applying multiple exact
// entries for the same declaration.
-template <typename SpecificDecl, typename LookupExactFn>
+template <typename SpecificInfo, typename SpecificDecl>
static void processExactAPINotes(
Sema &S, SpecificDecl *D,
- ArrayRef<SmallVector<std::string, 4>> ParameterSelectorCandidates,
- LookupExactFn LookupExact) {
- for (ArrayRef<std::string> ParameterStrings : ParameterSelectorCandidates) {
- SmallVector<StringRef, 4> Parameters =
- getAPINotesParameterSelectorRefs(ParameterStrings);
+ const APINotesParameterSelectorCandidates &ParameterSelectorCandidates,
+ llvm::function_ref<api_notes::APINotesReader::VersionedInfo<SpecificInfo>(
+ ArrayRef<StringRef>)>
+ LookupExact) {
+ auto ProcessSelector = [&](const APINotesParameterSelector &Selector) {
+ SmallVector<StringRef, 4> Parameters = Selector.getParameterRefs();
auto Info = LookupExact(Parameters);
if (Info.size() == 0)
- continue;
+ return false;
ProcessVersionedAPINotes(S, D, Info);
+ return true;
+ };
+
+ if (ProcessSelector(ParameterSelectorCandidates.Source))
return;
- }
+
+ if (ParameterSelectorCandidates.Desugared)
+ ProcessSelector(*ParameterSelectorCandidates.Desugared);
}
/// Process API notes that are associated with this declaration, mapping them
@@ -1113,12 +1145,12 @@ void Sema::ProcessAPINotes(Decl *D) {
ProcessVersionedAPINotes(*this, FD, Info);
if (ParameterSelectorCandidates)
- processExactAPINotes(*this, FD, *ParameterSelectorCandidates,
- [&](ArrayRef<StringRef> Parameters) {
- return Reader->lookupGlobalFunction(
- FD->getName(), Parameters,
- APINotesContext);
- });
+ processExactAPINotes<api_notes::GlobalFunctionInfo>(
+ *this, FD, *ParameterSelectorCandidates,
+ [&](ArrayRef<StringRef> Parameters) {
+ return Reader->lookupGlobalFunction(FD->getName(), Parameters,
+ APINotesContext);
+ });
}
}
@@ -1302,9 +1334,8 @@ void Sema::ProcessAPINotes(Decl *D) {
if (!isa<CXXConstructorDecl>(CXXMethod) &&
!isa<CXXDestructorDecl>(CXXMethod) &&
!isa<CXXConversionDecl>(CXXMethod)) {
- std::optional<SmallVector<SmallVector<std::string, 4>, 2>>
- ParameterSelectorCandidates =
- getAPINotesParameterSelectorCandidates(*this, CXXMethod);
+ auto ParameterSelectorCandidates =
+ getAPINotesParameterSelectorCandidates(*this, CXXMethod);
for (auto Reader : Readers) {
if (auto Context = UnwindTagContext(TagContext, APINotes)) {
std::string MethodName;
@@ -1319,12 +1350,12 @@ void Sema::ProcessAPINotes(Decl *D) {
ProcessVersionedAPINotes(*this, CXXMethod, Info);
if (ParameterSelectorCandidates)
- processExactAPINotes(*this, CXXMethod,
- *ParameterSelectorCandidates,
- [&](ArrayRef<StringRef> Parameters) {
- return Reader->lookupCXXMethod(
- Context->id, MethodName, Parameters);
- });
+ processExactAPINotes<api_notes::CXXMethodInfo>(
+ *this, CXXMethod, *ParameterSelectorCandidates,
+ [&](ArrayRef<StringRef> Parameters) {
+ return Reader->lookupCXXMethod(Context->id, MethodName,
+ Parameters);
+ });
}
}
}
diff --git a/clang/test/APINotes/Inputs/Headers/WhereParametersSema.apinotes b/clang/test/APINotes/Inputs/Headers/WhereParametersSema.apinotes
index 2f3b31148661f..7ffee9223f8c3 100644
--- a/clang/test/APINotes/Inputs/Headers/WhereParametersSema.apinotes
+++ b/clang/test/APINotes/Inputs/Headers/WhereParametersSema.apinotes
@@ -44,6 +44,11 @@ Functions:
Parameters:
- AliasInt
SwiftName: aliasPrecedenceGlobal(_:)
+- Name: multiAliasGlobal
+ Where:
+ Parameters:
+ - int
+ SwiftName: multiAliasGlobal(_:)
- Name: nullableGlobal
Where:
Parameters:
@@ -129,6 +134,11 @@ Tags:
Parameters:
- AliasInt
SwiftName: aliasPrecedence(_:)
+ - Name: multiAlias
+ Where:
+ Parameters:
+ - int
+ SwiftName: multiAlias(_:)
- Name: nullable
Where:
Parameters:
diff --git a/clang/test/APINotes/Inputs/Headers/WhereParametersSema.h b/clang/test/APINotes/Inputs/Headers/WhereParametersSema.h
index 85990e4ad7434..8226fa287b115 100644
--- a/clang/test/APINotes/Inputs/Headers/WhereParametersSema.h
+++ b/clang/test/APINotes/Inputs/Headers/WhereParametersSema.h
@@ -2,6 +2,8 @@
#define WHERE_PARAMETERS_SEMA_H
using AliasInt = int;
+using AliasAliasInt = AliasInt;
+using DeepAliasInt = AliasAliasInt;
void makeWidget(int);
void makeWidget(double);
@@ -16,6 +18,7 @@ void coexistGlobal(double);
void mismatchGlobal(float);
void aliasGlobal(AliasInt);
void aliasPrecedenceGlobal(AliasInt);
+void multiAliasGlobal(DeepAliasInt);
void nullableGlobal(char * _Nonnull);
void rawIntGlobal(int);
void constValueGlobal(const int);
@@ -44,6 +47,7 @@ struct SelectorWidget {
void mismatch(float);
void alias(AliasInt);
void aliasPrecedence(AliasInt);
+ void multiAlias(DeepAliasInt);
void nullable(char * _Nonnull);
void rawInt(int);
void constValue(const int);
diff --git a/clang/test/APINotes/where-parameters-sema.cpp b/clang/test/APINotes/where-parameters-sema.cpp
index 6e19719593197..fbb7cb45b9441 100644
--- a/clang/test/APINotes/where-parameters-sema.cpp
+++ b/clang/test/APINotes/where-parameters-sema.cpp
@@ -6,6 +6,7 @@
// 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 mismatchGlobal -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-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 aliasGlobal -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-ALIAS %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 aliasPrecedenceGlobal -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-ALIAS-PRECEDENCE %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 multiAliasGlobal -x c++ | FileCheck --check-prefix=CHECK-GLOBAL-MULTI-ALIAS %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 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
@@ -18,6 +19,7 @@
// 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::mismatch -x c++ | FileCheck --check-prefix=CHECK-METHOD-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 SelectorWidget::alias -x c++ | FileCheck --check-prefix=CHECK-METHOD-ALIAS %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::aliasPrecedence -x c++ | FileCheck --check-prefix=CHECK-METHOD-ALIAS-PRECEDENCE %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::multiAlias -x c++ | FileCheck --check-prefix=CHECK-METHOD-MULTI-ALIAS %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::nullable -x c++ | FileCheck --check-prefix=CHECK-METHOD-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 SelectorWidget::rawInt -x c++ | FileCheck --check-prefix=CHECK-METHOD-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 SelectorWidget::constValue -x c++ | FileCheck --check-prefix=CHECK-METHOD-CONST %s
@@ -56,6 +58,9 @@
// CHECK-GLOBAL-ALIAS-PRECEDENCE-NOT: fallbackAliasPrecedenceGlobal
// CHECK-GLOBAL-ALIAS-PRECEDENCE: SwiftNameAttr {{.+}} "aliasPrecedenceGlobal(_:)"
+// CHECK-GLOBAL-MULTI-ALIAS: FunctionDecl {{.+}} multiAliasGlobal 'void (DeepAliasInt)'
+// CHECK-GLOBAL-MULTI-ALIAS: SwiftNameAttr {{.+}} "multiAliasGlobal(_:)"
+
// CHECK-GLOBAL-NULLABILITY: FunctionDecl {{.+}} nullableGlobal 'void (char * _Nonnull)'
// CHECK-GLOBAL-NULLABILITY: SwiftNameAttr {{.+}} "nullableGlobal(_:)"
@@ -111,6 +116,9 @@
// CHECK-METHOD-ALIAS-PRECEDENCE-NOT: fallbackAliasPrecedence
// CHECK-METHOD-ALIAS-PRECEDENCE: SwiftNameAttr {{.+}} "aliasPrecedence(_:)"
+// CHECK-METHOD-MULTI-ALIAS: CXXMethodDecl {{.+}} multiAlias 'void (DeepAliasInt)'
+// CHECK-METHOD-MULTI-ALIAS: SwiftNameAttr {{.+}} "multiAlias(_:)"
+
// CHECK-METHOD-NULLABILITY: CXXMethodDecl {{.+}} nullable 'void (char * _Nonnull)'
// CHECK-METHOD-NULLABILITY: SwiftNameAttr {{.+}} "nullable(_:)"
>From 778b61cf434fbeb310b4107a8d283c4a984d491c Mon Sep 17 00:00:00 2001
From: stoeckoverflow <dominic-st at gmx.de>
Date: Wed, 8 Jul 2026 18:54:53 +0200
Subject: [PATCH 5/5] [APINotes] Clean up Where.Parameters Sema matching
---
clang/include/clang/APINotes/APINotesReader.h | 11 ++++---
clang/lib/APINotes/APINotesFormat.h | 9 +++---
clang/lib/APINotes/APINotesReader.cpp | 22 ++++++++-----
clang/lib/Sema/SemaAPINotes.cpp | 32 +++++++------------
4 files changed, 38 insertions(+), 36 deletions(-)
diff --git a/clang/include/clang/APINotes/APINotesReader.h b/clang/include/clang/APINotes/APINotesReader.h
index 8e748b5803189..761745e20b61a 100644
--- a/clang/include/clang/APINotes/APINotesReader.h
+++ b/clang/include/clang/APINotes/APINotesReader.h
@@ -22,6 +22,7 @@
#include "llvm/Support/VersionTuple.h"
#include <memory>
#include <optional>
+#include <string>
namespace clang {
namespace api_notes {
@@ -166,7 +167,7 @@ class APINotesReader {
/// key, and a non-empty list uses an exact ordered parameter key.
VersionedInfo<CXXMethodInfo>
lookupCXXMethod(ContextID CtxID, llvm::StringRef Name,
- llvm::ArrayRef<llvm::StringRef> Parameters);
+ llvm::ArrayRef<std::string> Parameters);
/// Look for information regarding the given global variable.
///
@@ -191,7 +192,7 @@ class APINotesReader {
/// key, and a non-empty list uses an exact ordered parameter key.
VersionedInfo<GlobalFunctionInfo>
lookupGlobalFunction(llvm::StringRef Name,
- llvm::ArrayRef<llvm::StringRef> Parameters,
+ llvm::ArrayRef<std::string> Parameters,
std::optional<Context> Ctx = std::nullopt);
/// Look for information regarding the given enumerator.
@@ -242,15 +243,17 @@ class APINotesReader {
private:
VersionedInfo<CXXMethodInfo> lookupCXXMethodImpl(ContextID CtxID,
llvm::StringRef Name);
+ template <typename ParameterT>
VersionedInfo<CXXMethodInfo>
lookupCXXMethodImpl(ContextID CtxID, llvm::StringRef Name,
- llvm::ArrayRef<llvm::StringRef> Parameters);
+ llvm::ArrayRef<ParameterT> Parameters);
VersionedInfo<GlobalFunctionInfo>
lookupGlobalFunctionImpl(llvm::StringRef Name, std::optional<Context> Ctx);
+ template <typename ParameterT>
VersionedInfo<GlobalFunctionInfo>
lookupGlobalFunctionImpl(llvm::StringRef Name,
- llvm::ArrayRef<llvm::StringRef> Parameters,
+ llvm::ArrayRef<ParameterT> Parameters,
std::optional<Context> Ctx);
};
diff --git a/clang/lib/APINotes/APINotesFormat.h b/clang/lib/APINotes/APINotesFormat.h
index df67da0845baf..f34ca2e2e363f 100644
--- a/clang/lib/APINotes/APINotesFormat.h
+++ b/clang/lib/APINotes/APINotesFormat.h
@@ -417,10 +417,10 @@ getFunctionKeyImpl(uint32_t ParentContextID, llvm::StringRef Name,
return FunctionTableKey(ParentContextID, *NameID);
}
-template <typename GetIdentifierFn>
+template <typename ParameterT, typename GetIdentifierFn>
std::optional<FunctionTableKey>
getFunctionKeyImpl(uint32_t ParentContextID, llvm::StringRef Name,
- llvm::ArrayRef<llvm::StringRef> Parameters,
+ llvm::ArrayRef<ParameterT> Parameters,
GetIdentifierFn GetIdentifier) {
std::optional<IdentifierID> NameID = GetIdentifier(Name);
if (!NameID)
@@ -428,8 +428,9 @@ getFunctionKeyImpl(uint32_t ParentContextID, llvm::StringRef Name,
llvm::SmallVector<IdentifierID, 2> ParameterTypeIDs;
ParameterTypeIDs.reserve(Parameters.size());
- for (llvm::StringRef Parameter : Parameters) {
- std::optional<IdentifierID> ParameterID = GetIdentifier(Parameter);
+ for (const ParameterT &Parameter : Parameters) {
+ std::optional<IdentifierID> ParameterID =
+ GetIdentifier(llvm::StringRef(Parameter));
if (!ParameterID)
return std::nullopt;
ParameterTypeIDs.push_back(*ParameterID);
diff --git a/clang/lib/APINotes/APINotesReader.cpp b/clang/lib/APINotes/APINotesReader.cpp
index 9305a5f10b4e8..c51ced8f27448 100644
--- a/clang/lib/APINotes/APINotesReader.cpp
+++ b/clang/lib/APINotes/APINotesReader.cpp
@@ -857,14 +857,16 @@ class APINotesReader::Implementation {
llvm::SmallVectorImpl<uint64_t> &Scratch);
std::optional<FunctionTableKey> getFunctionKey(uint32_t ParentContextID,
llvm::StringRef Name);
+ template <typename ParameterT>
std::optional<FunctionTableKey>
getFunctionKey(uint32_t ParentContextID, llvm::StringRef Name,
- llvm::ArrayRef<llvm::StringRef> Parameters);
+ llvm::ArrayRef<ParameterT> Parameters);
std::optional<FunctionTableKey>
getFunctionKey(std::optional<Context> ParentContext, llvm::StringRef Name);
+ template <typename ParameterT>
std::optional<FunctionTableKey>
getFunctionKey(std::optional<Context> ParentContext, llvm::StringRef Name,
- llvm::ArrayRef<llvm::StringRef> Parameters);
+ llvm::ArrayRef<ParameterT> Parameters);
llvm::Error readGlobalFunctionBlock(llvm::BitstreamCursor &Cursor,
llvm::SmallVectorImpl<uint64_t> &Scratch);
@@ -899,9 +901,10 @@ APINotesReader::Implementation::getFunctionKey(uint32_t ParentContextID,
});
}
+template <typename ParameterT>
std::optional<FunctionTableKey> APINotesReader::Implementation::getFunctionKey(
uint32_t ParentContextID, llvm::StringRef Name,
- llvm::ArrayRef<llvm::StringRef> Parameters) {
+ llvm::ArrayRef<ParameterT> Parameters) {
return getFunctionKeyImpl(
ParentContextID, Name, Parameters,
[this](llvm::StringRef S) { return getIdentifier(S); });
@@ -914,9 +917,10 @@ std::optional<FunctionTableKey> APINotesReader::Implementation::getFunctionKey(
return getFunctionKey(ParentContextID, Name);
}
+template <typename ParameterT>
std::optional<FunctionTableKey> APINotesReader::Implementation::getFunctionKey(
std::optional<Context> ParentContext, llvm::StringRef Name,
- llvm::ArrayRef<llvm::StringRef> Parameters) {
+ llvm::ArrayRef<ParameterT> Parameters) {
uint32_t ParentContextID =
ParentContext ? ParentContext->id.Value : static_cast<uint32_t>(-1);
return getFunctionKey(ParentContextID, Name, Parameters);
@@ -2342,7 +2346,7 @@ auto APINotesReader::lookupCXXMethod(ContextID CtxID, llvm::StringRef Name)
}
auto APINotesReader::lookupCXXMethod(ContextID CtxID, llvm::StringRef Name,
- llvm::ArrayRef<llvm::StringRef> Parameters)
+ llvm::ArrayRef<std::string> Parameters)
-> VersionedInfo<CXXMethodInfo> {
return lookupCXXMethodImpl(CtxID, Name, Parameters);
}
@@ -2364,9 +2368,10 @@ auto APINotesReader::lookupCXXMethodImpl(ContextID CtxID, llvm::StringRef Name)
return {Implementation->SwiftVersion, *Known};
}
+template <typename ParameterT>
auto APINotesReader::lookupCXXMethodImpl(
ContextID CtxID, llvm::StringRef Name,
- llvm::ArrayRef<llvm::StringRef> Parameters)
+ llvm::ArrayRef<ParameterT> Parameters)
-> VersionedInfo<CXXMethodInfo> {
if (!Implementation->CXXMethodTable)
return std::nullopt;
@@ -2409,7 +2414,7 @@ auto APINotesReader::lookupGlobalFunction(llvm::StringRef Name,
}
auto APINotesReader::lookupGlobalFunction(
- llvm::StringRef Name, llvm::ArrayRef<llvm::StringRef> Parameters,
+ llvm::StringRef Name, llvm::ArrayRef<std::string> Parameters,
std::optional<Context> Ctx) -> VersionedInfo<GlobalFunctionInfo> {
return lookupGlobalFunctionImpl(Name, Parameters, Ctx);
}
@@ -2432,8 +2437,9 @@ auto APINotesReader::lookupGlobalFunctionImpl(llvm::StringRef Name,
return {Implementation->SwiftVersion, *Known};
}
+template <typename ParameterT>
auto APINotesReader::lookupGlobalFunctionImpl(
- llvm::StringRef Name, llvm::ArrayRef<llvm::StringRef> Parameters,
+ llvm::StringRef Name, llvm::ArrayRef<ParameterT> Parameters,
std::optional<Context> Ctx) -> VersionedInfo<GlobalFunctionInfo> {
if (!Implementation->GlobalFunctionTable)
return std::nullopt;
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index a2176a3b8b976..1ab1eac4a5434 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -1003,17 +1003,13 @@ static void stripAPINotesParameterNullability(QualType &ParamType) {
struct APINotesParameterSelector {
SmallVector<std::string, 4> Parameters;
- SmallVector<StringRef, 4> getParameterRefs() const {
- SmallVector<StringRef, 4> Refs;
- Refs.reserve(Parameters.size());
- for (const std::string &Parameter : Parameters)
- Refs.push_back(Parameter);
- return Refs;
- }
-
bool operator==(const APINotesParameterSelector &Other) const {
return Parameters == Other.Parameters;
}
+
+ bool operator!=(const APINotesParameterSelector &Other) const {
+ return !(*this == Other);
+ }
};
struct APINotesParameterSelectorCandidates {
@@ -1040,15 +1036,12 @@ getAPINotesParameterSelectorPrintingPolicy(const ASTContext &Context) {
static std::string getAPINotesParameterSelectorSpelling(
QualType ParamType, const ASTContext &Context, const PrintingPolicy &Policy,
bool Desugar) {
+ if (Desugar)
+ ParamType = ParamType.getDesugaredType(Context);
+
ParamType.removeLocalConst();
stripAPINotesParameterNullability(ParamType);
- if (Desugar) {
- ParamType = ParamType.getDesugaredType(Context);
- ParamType.removeLocalConst();
- stripAPINotesParameterNullability(ParamType);
- }
-
return ParamType.getAsString(Policy);
}
@@ -1073,7 +1066,7 @@ getAPINotesParameterSelectorCandidates(const Sema &S, const FunctionDecl *FD) {
ParamType, S.Context, Policy, /*Desugar=*/true));
}
- if (!(Candidates.Source == Desugared))
+ if (Candidates.Source != Desugared)
Candidates.Desugared = std::move(Desugared);
return Candidates;
@@ -1087,11 +1080,10 @@ static void processExactAPINotes(
Sema &S, SpecificDecl *D,
const APINotesParameterSelectorCandidates &ParameterSelectorCandidates,
llvm::function_ref<api_notes::APINotesReader::VersionedInfo<SpecificInfo>(
- ArrayRef<StringRef>)>
+ ArrayRef<std::string>)>
LookupExact) {
auto ProcessSelector = [&](const APINotesParameterSelector &Selector) {
- SmallVector<StringRef, 4> Parameters = Selector.getParameterRefs();
- auto Info = LookupExact(Parameters);
+ auto Info = LookupExact(Selector.Parameters);
if (Info.size() == 0)
return false;
@@ -1147,7 +1139,7 @@ void Sema::ProcessAPINotes(Decl *D) {
if (ParameterSelectorCandidates)
processExactAPINotes<api_notes::GlobalFunctionInfo>(
*this, FD, *ParameterSelectorCandidates,
- [&](ArrayRef<StringRef> Parameters) {
+ [&](ArrayRef<std::string> Parameters) {
return Reader->lookupGlobalFunction(FD->getName(), Parameters,
APINotesContext);
});
@@ -1352,7 +1344,7 @@ void Sema::ProcessAPINotes(Decl *D) {
if (ParameterSelectorCandidates)
processExactAPINotes<api_notes::CXXMethodInfo>(
*this, CXXMethod, *ParameterSelectorCandidates,
- [&](ArrayRef<StringRef> Parameters) {
+ [&](ArrayRef<std::string> Parameters) {
return Reader->lookupCXXMethod(Context->id, MethodName,
Parameters);
});
More information about the cfe-commits
mailing list