https://github.com/StoeckOverflow updated https://github.com/llvm/llvm-project/pull/205307
>From ad76085780d755900971db13c1e468be68663153 Mon Sep 17 00:00:00 2001 From: stoeckoverflow <[email protected]> Date: Fri, 19 Jun 2026 11:17:22 +0200 Subject: [PATCH] [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(_:)" _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
