https://github.com/achaljhawar updated https://github.com/llvm/llvm-project/pull/205719
>From e2c41b02955dbc34871ae34f71a72e8f2a6e282b Mon Sep 17 00:00:00 2001 From: achaljhawar <[email protected]> Date: Thu, 25 Jun 2026 12:44:18 +1000 Subject: [PATCH] [clang][Tooling] Recognize standard user-defined literal operators --- .../Inclusions/Stdlib/StandardLibrary.cpp | 10 ++++- .../Inclusions/Stdlib/StdSpecialSymbolMap.inc | 14 ++++++ .../unittests/Tooling/StandardLibraryTest.cpp | 44 +++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp index 807a8d8a34ad7..e4de3b3850507 100644 --- a/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp +++ b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp @@ -298,6 +298,7 @@ std::optional<Symbol> Recognizer::operator()(const Decl *D) { if (!Symbols) return std::nullopt; + std::string NameStorage; llvm::StringRef Name = [&]() -> llvm::StringRef { for (const auto *SymDC : llvm::reverse(IntermediateDecl)) { DeclarationName N = cast<NamedDecl>(SymDC)->getDeclName(); @@ -306,9 +307,16 @@ std::optional<Symbol> Recognizer::operator()(const Decl *D) { if (!N.isEmpty()) return ""; // e.g. operator<: give up } - if (const auto *ND = llvm::dyn_cast<NamedDecl>(D)) + if (const auto *ND = llvm::dyn_cast<NamedDecl>(D)) { if (const auto *II = ND->getIdentifier()) return II->getName(); + DeclarationName DN = ND->getDeclName(); + if (DN.getNameKind() == DeclarationName::CXXLiteralOperatorName) { + NameStorage = + "operator\"\"" + DN.getCXXLiteralIdentifier()->getName().str(); + return NameStorage; + } + } return ""; }(); if (Name.empty()) diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc index c5b022e87ec33..d84f230232d8a 100644 --- a/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc +++ b/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc @@ -851,3 +851,17 @@ SYMBOL(UINT64_C, None, <cstdint>) SYMBOL(UINT64_C, None, <stdint.h>) SYMBOL(UINTMAX_C, None, <cstdint>) SYMBOL(UINTMAX_C, None, <stdint.h>) + +SYMBOL(operator""h, std::, <chrono>) +SYMBOL(operator""min, std::, <chrono>) +SYMBOL(operator""s, std::, <chrono>) +SYMBOL(operator""s, std::, <string>) +SYMBOL(operator""ms, std::, <chrono>) +SYMBOL(operator""us, std::, <chrono>) +SYMBOL(operator""ns, std::, <chrono>) +SYMBOL(operator""d, std::, <chrono>) +SYMBOL(operator""y, std::, <chrono>) +SYMBOL(operator""sv, std::, <string_view>) +SYMBOL(operator""i, std::, <complex>) +SYMBOL(operator""if, std::, <complex>) +SYMBOL(operator""il, std::, <complex>) diff --git a/clang/unittests/Tooling/StandardLibraryTest.cpp b/clang/unittests/Tooling/StandardLibraryTest.cpp index e4c109f3d580d..78fb7d10fe24e 100644 --- a/clang/unittests/Tooling/StandardLibraryTest.cpp +++ b/clang/unittests/Tooling/StandardLibraryTest.cpp @@ -10,6 +10,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclarationName.h" +#include "clang/AST/ExprCXX.h" #include "clang/Testing/TestAST.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" @@ -174,6 +175,49 @@ TEST(StdlibTest, Recognizer) { EXPECT_EQ(Recognizer(Sec), std::nullopt); } +TEST(StdlibTest, LiteralOperatorMappings) { + auto Chrono = stdlib::Header::named("<chrono>"); + auto Str = stdlib::Header::named("<string>"); + ASSERT_TRUE(Chrono); + ASSERT_TRUE(Str); + + auto Ms = stdlib::Symbol::named("std::", "operator\"\"ms"); + ASSERT_TRUE(Ms); + EXPECT_EQ(Ms->qualifiedName(), "std::operator\"\"ms"); + EXPECT_EQ(Ms->header(), *Chrono); + + auto S = stdlib::Symbol::named("std::", "operator\"\"s"); + ASSERT_TRUE(S); + EXPECT_THAT(S->headers(), ElementsAre(*Chrono, *Str)); + + EXPECT_EQ(stdlib::Symbol::named("std::", "operator\"\"sv")->header(), + stdlib::Header::named("<string_view>")); +} + +TEST(StdlibTest, RecognizerLiteralOperator) { + TestAST AST(R"cpp( + namespace std { + inline namespace literals { + inline namespace chrono_literals { + struct dur {}; + dur operator"" ms(unsigned long long); + } // chrono_literals + } // literals + } // std + + using namespace std::chrono_literals; + auto x = 5ms; + )cpp"); + + const VarDecl &X = cast<VarDecl>(lookup(AST, "x")); + const auto *UDL = cast<UserDefinedLiteral>(X.getInit()->IgnoreImplicit()); + const FunctionDecl *Op = UDL->getDirectCallee(); + ASSERT_TRUE(Op); + + stdlib::Recognizer Recognizer; + EXPECT_EQ(Recognizer(Op), stdlib::Symbol::named("std::", "operator\"\"ms")); +} + TEST(StdlibTest, RecognizerForC99) { TestInputs Input("typedef char uint8_t;"); Input.Language = TestLanguage::Lang_C99; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
